From 7f4b588cdfe16df614fc1ce5f6b723589965809e Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Fri, 16 Oct 2020 15:25:05 -0800 Subject: [PATCH 001/101] server inventory. WORK IN PROGRESS wip commit of implementing server authoritative inventories. there is a lot of experimental and debug code. this is NOT ready for testing or review. --- .../org/geysermc/connector/entity/Entity.java | 8 +- .../connector/inventory/Container.java | 69 +++ .../inventory/EnchantmentInventory.java | 40 ++ .../connector/inventory/FurnaceInventory.java | 41 ++ .../connector/inventory/GeyserItemStack.java | 123 +++++ .../connector/inventory/Inventory.java | 30 +- .../inventory/MerchantContainer.java | 44 ++ .../connector/inventory/PlayerInventory.java | 22 +- .../network/session/GeyserSession.java | 81 ++- .../network/session/cache/InventoryCache.java | 61 --- .../BedrockContainerCloseTranslator.java | 32 +- ...BedrockInventoryTransactionTranslator.java | 45 +- .../BedrockItemStackRequestTranslator.java | 49 ++ .../BedrockMobEquipmentTranslator.java | 4 +- .../entity/BedrockEntityEventTranslator.java | 32 +- .../player/BedrockInteractTranslator.java | 7 +- .../inventory/AnvilInventoryTranslator.java | 167 ------- .../inventory/BaseInventoryTranslator.java | 50 +- .../inventory/BedrockContainerSlot.java | 36 ++ .../inventory/BlockInventoryTranslator.java | 72 --- .../inventory/BrewingInventoryTranslator.java | 99 ---- .../inventory/ChestInventoryTranslator.java | 20 +- .../CraftingInventoryTranslator.java | 89 ---- .../EnchantmentInventoryTranslator.java | 267 ---------- .../inventory/FurnaceInventoryTranslator.java | 70 --- .../GrindstoneInventoryTranslator.java | 69 --- .../inventory/InventoryTranslator.java | 460 +++++++++++++++++- .../MerchantInventoryTranslator.java | 92 ++-- .../inventory/PlayerInventoryTranslator.java | 115 ++--- .../SmithingInventoryTranslator.java | 69 --- .../inventory/action/ClickPlan.java | 125 ----- .../action/InventoryActionDataTranslator.java | 338 ------------- .../inventory/{action => click}/Click.java | 17 +- .../inventory/click/ClickPlan.java | 211 ++++++++ .../updater/ChestInventoryUpdater.java | 4 +- .../updater/ContainerInventoryUpdater.java | 4 +- .../inventory/updater/InventoryUpdater.java | 4 +- ...ryUpdater.java => UIInventoryUpdater.java} | 7 +- .../java/JavaDeclareRecipesTranslator.java | 11 +- .../java/JavaRespawnTranslator.java | 2 +- .../player/JavaPlayerActionAckTranslator.java | 13 +- .../JavaPlayerChangeHeldItemTranslator.java | 14 +- .../window/JavaCloseWindowTranslator.java | 6 +- .../JavaConfirmTransactionTranslator.java | 11 +- .../java/window/JavaOpenWindowTranslator.java | 77 +-- .../java/window/JavaSetSlotTranslator.java | 54 +- .../window/JavaWindowItemsTranslator.java | 36 +- .../window/JavaWindowPropertyTranslator.java | 17 +- .../world/JavaNotifyClientTranslator.java | 2 +- .../java/world/JavaTradeListTranslator.java | 35 +- .../sound/BlockSoundInteractionHandler.java | 9 +- .../sound/EntitySoundInteractionHandler.java | 9 +- .../block/BucketSoundInteractionHandler.java | 2 +- .../MilkCowSoundInteractionHandler.java | 2 +- .../geysermc/connector/utils/BlockUtils.java | 2 +- .../connector/utils/InventoryUtils.java | 91 ++-- connector/src/main/resources/languages | 2 +- connector/src/main/resources/mappings | 2 +- 58 files changed, 1611 insertions(+), 1859 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/inventory/Container.java create mode 100644 connector/src/main/java/org/geysermc/connector/inventory/EnchantmentInventory.java create mode 100644 connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java create mode 100644 connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java create mode 100644 connector/src/main/java/org/geysermc/connector/inventory/MerchantContainer.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/BedrockContainerSlot.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/GrindstoneInventoryTranslator.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/SmithingInventoryTranslator.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/{action => click}/Click.java (66%) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/{CursorInventoryUpdater.java => UIInventoryUpdater.java} (89%) diff --git a/connector/src/main/java/org/geysermc/connector/entity/Entity.java b/connector/src/main/java/org/geysermc/connector/entity/Entity.java index 5e825e892..57c827a9f 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -50,6 +50,7 @@ import org.geysermc.connector.entity.attribute.Attribute; import org.geysermc.connector.entity.attribute.AttributeType; import org.geysermc.connector.entity.living.ArmorStandEntity; import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.utils.AttributeUtils; @@ -288,11 +289,12 @@ public class Entity { // Shield code if (session.getPlayerEntity().getEntityId() == entityId && metadata.getFlags().getFlag(EntityFlag.SNEAKING)) { - if ((session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) || - (session.getInventoryCache().getPlayerInventory().getItem(45) != null && session.getInventoryCache().getPlayerInventory().getItem(45).getId() == ItemRegistry.SHIELD.getJavaId())) { + PlayerInventory playerInv = session.getPlayerInventory(); + if ((playerInv.getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) || + (playerInv.getOffhand().getId() == ItemRegistry.SHIELD.getJavaId())) { ClientPlayerUseItemPacket useItemPacket; metadata.getFlags().setFlag(EntityFlag.BLOCKING, true); - if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) { + if (playerInv.getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) { useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); } // Else we just assume it's the offhand, to simplify logic and to assure the packet gets sent diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Container.java b/connector/src/main/java/org/geysermc/connector/inventory/Container.java new file mode 100644 index 000000000..acf450e14 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/inventory/Container.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019-2020 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.inventory; + +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import lombok.Getter; +import lombok.NonNull; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; + +/** + * Combination of {@link Inventory} and {@link PlayerInventory} + */ +@Getter +public class Container extends Inventory { + private final PlayerInventory playerInventory; + private final int containerSize; + + public Container(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) { + super(title, id, windowType, size); + this.playerInventory = playerInventory; + this.containerSize = this.size + InventoryTranslator.PLAYER_INVENTORY_SIZE; + } + + @Override + public GeyserItemStack getItem(int slot) { + if (slot < this.size) { + return super.getItem(slot); + } else { + return playerInventory.getItem(slot - this.size + InventoryTranslator.PLAYER_INVENTORY_OFFSET); + } + } + + @Override + public void setItem(int slot, @NonNull GeyserItemStack item) { + if (slot < this.size) { + super.setItem(slot, item); + } else { + playerInventory.setItem(slot - this.size + InventoryTranslator.PLAYER_INVENTORY_OFFSET, item); + } + } + + @Override + public int getSize() { + return this.containerSize; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/inventory/EnchantmentInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/EnchantmentInventory.java new file mode 100644 index 000000000..65debc486 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/inventory/EnchantmentInventory.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019-2020 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.inventory; + +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.nukkitx.protocol.bedrock.data.inventory.EnchantOptionData; +import lombok.Getter; + +@Getter +public class EnchantmentInventory extends Inventory { + private EnchantOptionData[] enchantOptions; + + public EnchantmentInventory(String title, int id, WindowType windowType, int size) { + super(title, id, windowType, size); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java new file mode 100644 index 000000000..4dc098d89 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019-2020 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.inventory; + +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import lombok.Getter; +import lombok.Setter; + +@Getter +public class FurnaceInventory extends Inventory { + @Setter + private int test; + + public FurnaceInventory(String title, int id, WindowType windowType, int size) { + super(title, id, windowType, size); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java new file mode 100644 index 000000000..c935fcdb4 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2019-2020 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.inventory; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import lombok.Data; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.network.translators.item.ItemTranslator; + +@Data +public class GeyserItemStack { + public static final GeyserItemStack EMPTY = new GeyserItemStack(0, 0, null); + + private final int id; + private int amount; + private CompoundTag nbt; + private int netId; + + public GeyserItemStack(int id) { + this(id, 1); + } + + public GeyserItemStack(int id, int amount) { + this(id, amount, null); + } + + public GeyserItemStack(int id, int amount, CompoundTag nbt) { + this(id, amount, nbt, 1); + } + + public GeyserItemStack(int id, int amount, CompoundTag nbt, int netId) { + this.id = id; + this.amount = amount; + this.nbt = nbt; + this.netId = netId; + } + + public int getId() { + return isEmpty() ? 0 : id; + } + + public int getAmount() { + return isEmpty() ? 0 : amount; + } + + public CompoundTag getNbt() { + return isEmpty() ? null : nbt; + } + + public int getNetId() { + return isEmpty() ? 0 : netId; + } + + public void add(int add) { + amount += add; + } + + public void sub(int sub) { + amount -= sub; + } + + public static GeyserItemStack from(ItemStack itemStack) { + return from(itemStack, 1); + } + + public static GeyserItemStack from(ItemStack itemStack, int netId) { + return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getNbt(), netId); + } + + public ItemStack getItemStack() { + return isEmpty() ? null : new ItemStack(id, amount, nbt); + } + + public ItemData getItemData(GeyserSession session) { + ItemData itemData = ItemTranslator.translateToBedrock(session, getItemStack()); + itemData.setNetId(getNetId()); + return itemData; + } + + public ItemEntry getItemEntry() { + return ItemRegistry.ITEM_ENTRIES.get(getId()); + } + + public boolean isEmpty() { + return amount <= 0 || id == 0; + } + + public GeyserItemStack copy() { + return copy(amount); + } + + public GeyserItemStack copy(int newAmount) { + return isEmpty() ? EMPTY : new GeyserItemStack(id, newAmount, nbt == null ? null : nbt.clone(), netId); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java index 539fe1e26..f4aea4c90 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java @@ -25,23 +25,19 @@ package org.geysermc.connector.inventory; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.nukkitx.math.vector.Vector3i; import lombok.Getter; +import lombok.NonNull; import lombok.Setter; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.Arrays; public class Inventory { @Getter protected int id; - @Getter - @Setter - protected boolean open; - @Getter protected WindowType windowType; @@ -52,8 +48,7 @@ public class Inventory { @Setter protected String title; - @Setter - protected ItemStack[] items; + protected GeyserItemStack[] items; @Getter @Setter @@ -64,27 +59,30 @@ public class Inventory { protected long holderId = -1; @Getter - protected AtomicInteger transactionId = new AtomicInteger(1); + protected short transactionId = 0; - public Inventory(int id, WindowType windowType, int size) { + protected Inventory(int id, WindowType windowType, int size) { this("Inventory", id, windowType, size); } - public Inventory(String title, int id, WindowType windowType, int size) { + protected Inventory(String title, int id, WindowType windowType, int size) { this.title = title; this.id = id; this.windowType = windowType; this.size = size; - this.items = new ItemStack[size]; + this.items = new GeyserItemStack[size]; + Arrays.fill(items, GeyserItemStack.EMPTY); } - public ItemStack getItem(int slot) { + public GeyserItemStack getItem(int slot) { return items[slot]; } - public void setItem(int slot, ItemStack item) { - if (item != null && (item.getId() == 0 || item.getAmount() < 1)) - item = null; + public void setItem(int slot, @NonNull GeyserItemStack item) { items[slot] = item; } + + public short getNextTransactionId() { + return ++transactionId; + } } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/MerchantContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/MerchantContainer.java new file mode 100644 index 000000000..03ae8ac3a --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/inventory/MerchantContainer.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019-2020 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.inventory; + +import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import lombok.Getter; +import lombok.Setter; +import org.geysermc.connector.entity.Entity; + +@Getter +@Setter +public class MerchantContainer extends Container { + private Entity villager; + private VillagerTrade[] villagerTrades; + + public MerchantContainer(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) { + super(title, id, windowType, size, playerInventory); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java index 225335a97..e6aeb5cab 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java @@ -25,8 +25,8 @@ package org.geysermc.connector.inventory; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import lombok.Getter; +import lombok.NonNull; import lombok.Setter; public class PlayerInventory extends Inventory { @@ -40,20 +40,24 @@ public class PlayerInventory extends Inventory { private int heldItemSlot; @Getter - private ItemStack cursor; + @Setter + @NonNull + private GeyserItemStack cursor = GeyserItemStack.EMPTY; public PlayerInventory() { super(0, null, 46); heldItemSlot = 0; } - public void setCursor(ItemStack stack) { - if (stack != null && (stack.getId() == 0 || stack.getAmount() < 1)) - stack = null; - cursor = stack; - } - - public ItemStack getItemInHand() { + public GeyserItemStack getItemInHand() { return items[36 + heldItemSlot]; } + + public void setItemInHand(@NonNull GeyserItemStack item) { + items[36 + heldItemSlot] = item; + } + + public GeyserItemStack getOffhand() { + return items[45]; + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 1a0bbfb29..1d8120f37 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -32,6 +32,7 @@ import com.github.steveice10.mc.protocol.MinecraftConstants; import com.github.steveice10.mc.protocol.MinecraftProtocol; import com.github.steveice10.mc.protocol.data.SubProtocol; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; import com.github.steveice10.mc.protocol.data.message.MessageSerializer; import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket; @@ -49,11 +50,14 @@ import com.nukkitx.protocol.bedrock.BedrockServerSession; import com.nukkitx.protocol.bedrock.data.*; import com.nukkitx.protocol.bedrock.data.command.CommandPermission; import com.nukkitx.protocol.bedrock.packet.*; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMaps; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2LongMap; import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; +import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; import org.geysermc.common.window.CustomFormWindow; @@ -63,6 +67,7 @@ import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.common.AuthType; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.PlayerEntity; +import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.remote.RemoteServer; import org.geysermc.connector.network.session.auth.AuthData; @@ -71,7 +76,6 @@ import org.geysermc.connector.network.session.cache.*; import org.geysermc.connector.network.translators.BiomeTranslator; import org.geysermc.connector.network.translators.EntityIdentifierRegistry; import org.geysermc.connector.network.translators.PacketTranslatorRegistry; -import org.geysermc.connector.network.translators.inventory.EnchantmentInventoryTranslator; import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.utils.*; @@ -83,6 +87,12 @@ import java.net.InetSocketAddress; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; import java.util.*; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.atomic.AtomicInteger; @@ -100,11 +110,20 @@ public class GeyserSession implements CommandSender { private BedrockClientData clientData; private PlayerEntity playerEntity; - private PlayerInventory inventory; + + private final PlayerInventory playerInventory; + @Setter + private Inventory openInventory; + + private final AtomicInteger itemNetId = new AtomicInteger(1); + + @Getter(AccessLevel.NONE) + private final Object inventoryLock = new Object(); + @Getter(AccessLevel.NONE) + private CompletableFuture inventoryFuture; private ChunkCache chunkCache; private EntityCache entityCache; - private InventoryCache inventoryCache; private WorldCache worldCache; private WindowCache windowCache; @Setter @@ -170,9 +189,6 @@ public class GeyserSession implements CommandSender { @Setter private Entity ridingVehicleEntity; - @Setter - private int craftSlot = 0; - @Setter private long lastWindowCloseTime = 0; @@ -187,10 +203,8 @@ public class GeyserSession implements CommandSender { @Setter private long lastInteractedVillagerEid; - /** - * Stores the enchantment information the client has received if they are in an enchantment table GUI - */ - private final EnchantmentInventoryTranslator.EnchantmentSlotData[] enchantmentSlotData = new EnchantmentInventoryTranslator.EnchantmentSlotData[3]; + @Setter + private Int2ObjectMap craftingRecipes; /** * The current attack speed of the player. Used for sending proper cooldown timings. @@ -282,18 +296,19 @@ public class GeyserSession implements CommandSender { this.chunkCache = new ChunkCache(this); this.entityCache = new EntityCache(this); - this.inventoryCache = new InventoryCache(this); this.worldCache = new WorldCache(this); this.windowCache = new WindowCache(this); this.playerEntity = new PlayerEntity(new GameProfile(UUID.randomUUID(), "unknown"), 1, 1, Vector3f.ZERO, Vector3f.ZERO, Vector3f.ZERO); - this.inventory = new PlayerInventory(); + + this.playerInventory = new PlayerInventory(); + this.openInventory = null; + this.inventoryFuture = CompletableFuture.completedFuture(null); + this.craftingRecipes = new Int2ObjectOpenHashMap<>(); this.spawned = false; this.loggedIn = false; - this.inventoryCache.getInventories().put(0, inventory); - bedrockServerSession.addDisconnectHandler(disconnectReason -> { connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.disconnect", bedrockServerSession.getAddress().getAddress(), disconnectReason)); @@ -529,7 +544,6 @@ public class GeyserSession implements CommandSender { this.chunkCache = null; this.entityCache = null; this.worldCache = null; - this.inventoryCache = null; this.windowCache = null; closed = true; @@ -638,10 +652,47 @@ public class GeyserSession implements CommandSender { startGamePacket.setBlockPalette(BlockTranslator.BLOCKS); startGamePacket.setItemEntries(ItemRegistry.ITEMS); startGamePacket.setVanillaVersion("*"); + // startGamePacket.setMovementServerAuthoritative(true); + startGamePacket.setInventoriesServerAuthoritative(true); startGamePacket.setAuthoritativeMovementMode(AuthoritativeMovementMode.CLIENT); upstream.sendPacket(startGamePacket); } + /** + * Adds a new inventory task. + * Inventory tasks are executed one at a time, in order. + * + * @param task the task to run + */ + public void addInventoryTask(Runnable task) { + synchronized (inventoryLock) { + System.out.println("new task " + task.toString()); + inventoryFuture = inventoryFuture.thenRun(task).exceptionally(throwable -> { + GeyserConnector.getInstance().getLogger().error("Error processing inventory task", throwable.getCause()); + return null; + }); + } + } + + /** + * Adds a new inventory task with a delay. + * The delay is achieved by scheduling with the Geyser general thread pool. + * Inventory tasks are executed one at a time, in order. + * + * @param task the delayed task to run + * @param delayMillis delay in milliseconds + */ + public void addInventoryTask(Runnable task, long delayMillis) { + synchronized (inventoryLock) { + System.out.println("new delayed task " + task.toString()); + Executor delayedExecutor = command -> GeyserConnector.getInstance().getGeneralThreadPool().schedule(command, delayMillis, TimeUnit.MILLISECONDS); + inventoryFuture = inventoryFuture.thenRunAsync(task, delayedExecutor).exceptionally(throwable -> { + GeyserConnector.getInstance().getLogger().error("Error processing inventory task", throwable.getCause()); + return null; + }); + } + } + public boolean confirmTeleport(Vector3d position) { if (teleportCache != null) { if (!teleportCache.canConfirm(position)) { diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java deleted file mode 100644 index 032f64024..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2019-2020 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.cache; - -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import lombok.Getter; -import lombok.Setter; -import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.network.session.GeyserSession; - -public class InventoryCache { - - private GeyserSession session; - - @Getter - @Setter - private Inventory openInventory; - - @Getter - private Int2ObjectMap inventories = new Int2ObjectOpenHashMap<>(); - - public InventoryCache(GeyserSession session) { - this.session = session; - } - - public Inventory getPlayerInventory() { - return inventories.get(0); - } - - public void cacheInventory(Inventory inventory) { - inventories.put(inventory.getId(), inventory); - } - - public void uncacheInventory(int id) { - inventories.remove(id); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java index 00905f6d9..5571ff8b9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java @@ -38,24 +38,24 @@ public class BedrockContainerCloseTranslator extends PacketTranslator { + session.setLastWindowCloseTime(0); + byte windowId = packet.getId(); + + if (windowId == -1 && session.getOpenInventory() != null) { + windowId = (byte) session.getOpenInventory().getId(); } - } - if (windowId == 0 || (openInventory != null && openInventory.getId() == windowId)) { - ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(windowId); - session.getDownstream().getSession().send(closeWindowPacket); - InventoryUtils.closeInventory(session, windowId); - } + Inventory openInventory = session.getOpenInventory(); + if (openInventory != null && windowId == openInventory.getId()) { + System.out.println(packet); + ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(windowId); + session.getDownstream().getSession().send(closeWindowPacket); + InventoryUtils.closeInventory(session, windowId); + } - //Client wants close confirmation - session.sendUpstreamPacket(packet); + //Client wants close confirmation + session.sendUpstreamPacket(packet); + }); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index b81025beb..9dd0f1996 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.connector.network.translators.bedrock; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; @@ -43,23 +42,23 @@ import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; +import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; +import com.nukkitx.protocol.bedrock.data.inventory.InventorySource; import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket; import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; import org.geysermc.connector.entity.CommandBlockMinecartEntity; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.ItemFrameEntity; import org.geysermc.connector.entity.living.merchant.AbstractMerchantEntity; -import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.sound.EntitySoundInteractionHandler; import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.utils.BlockUtils; -import org.geysermc.connector.utils.InventoryUtils; import java.util.concurrent.TimeUnit; @@ -70,15 +69,36 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { + if (session.getPlayerInventory().getHeldItemSlot() != containerAction.getSlot()) + return; + if (session.getPlayerInventory().getItemInHand().isEmpty()) + return; + + boolean dropAll = worldAction.getToItem().getCount() > 1; + ClientPlayerActionPacket dropAllPacket = new ClientPlayerActionPacket( + dropAll ? PlayerAction.DROP_ITEM_STACK : PlayerAction.DROP_ITEM, + new Position(0, 0, 0), + BlockFace.DOWN + ); + session.sendDownstreamPacket(dropAllPacket); + + if (dropAll) { + session.getPlayerInventory().setItemInHand(GeyserItemStack.EMPTY); + } else { + session.getPlayerInventory().getItemInHand().sub(1); + } + }); + } + } break; case INVENTORY_MISMATCH: - Inventory inv = session.getInventoryCache().getOpenInventory(); - if (inv == null) inv = session.getInventory(); - InventoryTranslator.INVENTORY_TRANSLATORS.get(inv.getWindowType()).updateInventory(session, inv); - InventoryUtils.updateCursor(session); break; case ITEM_USE: switch (packet.getActionType()) { @@ -164,9 +184,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { + + @Override + public void translate(ItemStackRequestPacket packet, GeyserSession session) { + Inventory inventory = session.getOpenInventory(); + if (inventory == null) + return; + + InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()); + session.addInventoryTask(() -> translator.translateRequests(session, inventory, packet.getRequests())); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java index a220e389f..ade949199 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java @@ -40,12 +40,12 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator 8 || - packet.getContainerId() != ContainerId.INVENTORY || session.getInventory().getHeldItemSlot() == packet.getHotbarSlot()) { + packet.getContainerId() != ContainerId.INVENTORY || session.getPlayerInventory().getHeldItemSlot() == packet.getHotbarSlot()) { // For the last condition - Don't update the slot if the slot is the same - not Java Edition behavior and messes with plugins such as Grief Prevention return; } - session.getInventory().setHeldItemSlot(packet.getHotbarSlot()); + session.getPlayerInventory().setHeldItemSlot(packet.getHotbarSlot()); ClientPlayerChangeHeldItemPacket changeHeldItemPacket = new ClientPlayerChangeHeldItemPacket(packet.getHotbarSlot()); session.sendDownstreamPacket(changeHeldItemPacket); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/BedrockEntityEventTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/BedrockEntityEventTranslator.java index 18fd6614e..eaf352da9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/BedrockEntityEventTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/BedrockEntityEventTranslator.java @@ -26,12 +26,13 @@ package org.geysermc.connector.network.translators.bedrock.entity; import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; -import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientSelectTradePacket; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.MerchantContainer; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; @@ -47,20 +48,25 @@ public class BedrockEntityEventTranslator extends PacketTranslator { + ClientSelectTradePacket selectTradePacket = new ClientSelectTradePacket(packet.getData()); + session.getDownstream().getSession().send(selectTradePacket); + }); - Entity villager = session.getPlayerEntity(); - Inventory openInventory = session.getInventoryCache().getOpenInventory(); - if (openInventory != null && openInventory.getWindowType() == WindowType.MERCHANT) { - VillagerTrade[] trades = session.getVillagerTrades(); - if (trades != null && packet.getData() >= 0 && packet.getData() < trades.length) { - VillagerTrade trade = session.getVillagerTrades()[packet.getData()]; - openInventory.setItem(2, trade.getOutput()); - villager.getMetadata().put(EntityData.TRADE_XP, trade.getXp() + villager.getMetadata().getInt(EntityData.TRADE_XP)); - villager.updateBedrockMetadata(session); + session.addInventoryTask(() -> { + Entity villager = session.getPlayerEntity(); + Inventory openInventory = session.getOpenInventory(); + if (openInventory instanceof MerchantContainer) { + MerchantContainer merchantInventory = (MerchantContainer) openInventory; + VillagerTrade[] trades = merchantInventory.getVillagerTrades(); + if (trades != null && packet.getData() >= 0 && packet.getData() < trades.length) { + VillagerTrade trade = merchantInventory.getVillagerTrades()[packet.getData()]; + openInventory.setItem(2, GeyserItemStack.from(trade.getOutput())); + villager.getMetadata().put(EntityData.TRADE_XP, trade.getXp() + villager.getMetadata().getInt(EntityData.TRADE_XP)); + villager.updateBedrockMetadata(session); + } } - } + }, 100); return; } session.getConnector().getLogger().debug("Did not translate incoming EntityEventPacket: " + packet.toString()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java index c5d6f2dda..ff261aba7 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java @@ -60,7 +60,7 @@ public class BedrockInteractTranslator extends PacketTranslator switch (packet.getAction()) { case INTERACT: - if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemRegistry.SHIELD.getJavaId()) { + if (session.getPlayerInventory().getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) { break; } ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(), @@ -135,14 +135,15 @@ public class BedrockInteractTranslator extends PacketTranslator } break; case OPEN_INVENTORY: - if (!session.getInventory().isOpen()) { + if (session.getOpenInventory() == null) { + session.setOpenInventory(session.getPlayerInventory()); + ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); containerOpenPacket.setId((byte) 0); containerOpenPacket.setType(ContainerType.INVENTORY); containerOpenPacket.setUniqueEntityId(-1); containerOpenPacket.setBlockPosition(entity.getPosition().toInt()); session.sendUpstreamPacket(containerOpenPacket); - session.getInventory().setOpen(true); } break; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java deleted file mode 100644 index ab266faef..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2019-2020 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.translators.inventory; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientRenameItemPacket; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.google.gson.JsonSyntaxException; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.protocol.bedrock.data.inventory.*; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; - -import java.util.List; -import java.util.stream.Collectors; - -public class AnvilInventoryTranslator extends BlockInventoryTranslator { - public AnvilInventoryTranslator() { - super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL, new CursorInventoryUpdater()); - } - - @Override - public int bedrockSlotToJava(InventoryActionData action) { - if (action.getSource().getContainerId() == ContainerId.UI) { - switch (action.getSlot()) { - case 1: - return 0; - case 2: - return 1; - case 50: - return 2; - } - } - if (action.getSource().getContainerId() == ContainerId.ANVIL_RESULT) { - return 2; - } - return super.bedrockSlotToJava(action); - } - - @Override - public int javaSlotToBedrock(int slot) { - switch (slot) { - case 0: - return 1; - case 1: - return 2; - case 2: - return 50; - } - return super.javaSlotToBedrock(slot); - } - - @Override - public SlotType getSlotType(int javaSlot) { - if (javaSlot == 2) - return SlotType.OUTPUT; - return SlotType.NORMAL; - } - - @Override - public void translateActions(GeyserSession session, Inventory inventory, List actions) { - InventoryActionData anvilResult = null; - InventoryActionData anvilInput = null; - for (InventoryActionData action : actions) { - if (action.getSource().getContainerId() == ContainerId.ANVIL_MATERIAL) { - //useless packet - return; - } else if (action.getSource().getContainerId() == ContainerId.ANVIL_RESULT) { - anvilResult = action; - } else if (bedrockSlotToJava(action) == 0) { - anvilInput = action; - } - } - ItemData itemName = null; - if (anvilResult != null) { - itemName = anvilResult.getFromItem(); - } else if (anvilInput != null) { - itemName = anvilInput.getToItem(); - } - if (itemName != null) { - String rename; - NbtMap tag = itemName.getTag(); - if (tag != null && tag.containsKey("display")) { - String name = tag.getCompound("display").getString("Name"); - try { - Component component = GsonComponentSerializer.gson().deserialize(name); - rename = LegacyComponentSerializer.legacySection().serialize(component); - } catch (JsonSyntaxException e) { - rename = name; - } - } else { - rename = ""; - } - ClientRenameItemPacket renameItemPacket = new ClientRenameItemPacket(rename); - session.sendDownstreamPacket(renameItemPacket); - } - if (anvilResult != null) { - //Strip unnecessary actions - List strippedActions = actions.stream() - .filter(action -> action.getSource().getContainerId() == ContainerId.ANVIL_RESULT - || (action.getSource().getType() == InventorySource.Type.CONTAINER - && !(action.getSource().getContainerId() == ContainerId.UI && action.getSlot() != 0))) - .collect(Collectors.toList()); - super.translateActions(session, inventory, strippedActions); - return; - } - - super.translateActions(session, inventory, actions); - } - - @Override - public void updateSlot(GeyserSession session, Inventory inventory, int slot) { - if (slot == 0) { - ItemStack item = inventory.getItem(slot); - if (item != null) { - String rename; - CompoundTag tag = item.getNbt(); - if (tag != null) { - CompoundTag displayTag = tag.get("display"); - if (displayTag != null && displayTag.contains("Name")) { - String itemName = displayTag.get("Name").getValue().toString(); - try { - Component component = GsonComponentSerializer.gson().deserialize(itemName); - rename = LegacyComponentSerializer.legacySection().serialize(component); - } catch (JsonSyntaxException e) { - rename = itemName; - } - } else { - rename = ""; - } - } else { - rename = ""; - } - ClientRenameItemPacket renameItemPacket = new ClientRenameItemPacket(rename); - session.sendDownstreamPacket(renameItemPacket); - } - } - super.updateSlot(session, inventory, slot); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java index 6f00fc4d7..7d54667bd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java @@ -25,15 +25,15 @@ package org.geysermc.connector.network.translators.inventory; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +import org.geysermc.connector.inventory.Container; import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.action.InventoryActionDataTranslator; -import java.util.List; - -public abstract class BaseInventoryTranslator extends InventoryTranslator{ +public abstract class BaseInventoryTranslator extends InventoryTranslator { BaseInventoryTranslator(int size) { super(size); } @@ -44,15 +44,18 @@ public abstract class BaseInventoryTranslator extends InventoryTranslator{ } @Override - public int bedrockSlotToJava(InventoryActionData action) { - int slotnum = action.getSlot(); - if (action.getSource().getContainerId() == ContainerId.INVENTORY) { - //hotbar - if (slotnum >= 9) { - return slotnum + this.size - 9; - } else { - return slotnum + this.size + 27; - } + public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { + int slotnum = slotInfoData.getSlot(); + switch (slotInfoData.getContainer()) { + case HOTBAR_AND_INVENTORY: + case HOTBAR: + case INVENTORY: + //hotbar + if (slotnum >= 9) { + return slotnum + this.size - 9; + } else { + return slotnum + this.size + 27; + } } return slotnum; } @@ -70,13 +73,26 @@ public abstract class BaseInventoryTranslator extends InventoryTranslator{ return slot; } + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + if (slot >= this.size) { + final int tmp = slot - this.size; + if (tmp < 27) { + return new BedrockContainerSlot(ContainerSlotType.INVENTORY, tmp + 9); + } else { + return new BedrockContainerSlot(ContainerSlotType.HOTBAR, tmp - 27); + } + } + throw new IllegalArgumentException("Unknown bedrock slot"); + } + @Override public SlotType getSlotType(int javaSlot) { return SlotType.NORMAL; } @Override - public void translateActions(GeyserSession session, Inventory inventory, List actions) { - InventoryActionDataTranslator.translate(this, session, inventory, actions); + public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { + return new Container(name, windowId, windowType, this.size, playerInventory); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BedrockContainerSlot.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BedrockContainerSlot.java new file mode 100644 index 000000000..b3a09e167 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BedrockContainerSlot.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory; + +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import lombok.Value; + +@Value +public class BedrockContainerSlot { + ContainerSlotType container; + int slot; +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java deleted file mode 100644 index 4b8b57e8f..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2019-2020 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.translators.inventory; - -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; -import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder; -import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; - -public class BlockInventoryTranslator extends BaseInventoryTranslator { - private final InventoryHolder holder; - private final InventoryUpdater updater; - - public BlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater) { - super(size); - int javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); - int blockId = BlockTranslator.getBedrockBlockId(javaBlockState); - this.holder = new BlockInventoryHolder(blockId, containerType); - this.updater = updater; - } - - @Override - public void prepareInventory(GeyserSession session, Inventory inventory) { - holder.prepareInventory(this, session, inventory); - } - - @Override - public void openInventory(GeyserSession session, Inventory inventory) { - holder.openInventory(this, session, inventory); - } - - @Override - public void closeInventory(GeyserSession session, Inventory inventory) { - holder.closeInventory(this, session, inventory); - } - - @Override - public void updateInventory(GeyserSession session, Inventory inventory) { - updater.updateInventory(this, session, inventory); - } - - @Override - public void updateSlot(GeyserSession session, Inventory inventory, int slot) { - updater.updateSlot(this, session, inventory, slot); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java deleted file mode 100644 index 89cdbe8d7..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2019-2020 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.translators.inventory; - -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; -import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket; -import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; - -public class BrewingInventoryTranslator extends BlockInventoryTranslator { - public BrewingInventoryTranslator() { - super(5, "minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]", ContainerType.BREWING_STAND, new ContainerInventoryUpdater()); - } - - @Override - public void openInventory(GeyserSession session, Inventory inventory) { - super.openInventory(session, inventory); - ContainerSetDataPacket dataPacket = new ContainerSetDataPacket(); - dataPacket.setWindowId((byte) inventory.getId()); - dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_FUEL_TOTAL); - dataPacket.setValue(20); - session.sendUpstreamPacket(dataPacket); - } - - @Override - public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { - ContainerSetDataPacket dataPacket = new ContainerSetDataPacket(); - dataPacket.setWindowId((byte) inventory.getId()); - switch (key) { - case 0: - dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_BREW_TIME); - break; - case 1: - dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_FUEL_AMOUNT); - break; - default: - return; - } - dataPacket.setValue(value); - session.sendUpstreamPacket(dataPacket); - } - - @Override - public int bedrockSlotToJava(InventoryActionData action) { - final int slot = super.bedrockSlotToJava(action); - switch (slot) { - case 0: - return 3; - case 1: - return 0; - case 2: - return 1; - case 3: - return 2; - default: - return slot; - } - } - - @Override - public int javaSlotToBedrock(int slot) { - switch (slot) { - case 0: - return 1; - case 1: - return 2; - case 2: - return 3; - case 3: - return 0; - } - return super.javaSlotToBedrock(slot); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java index 152f4a852..df97563e5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java @@ -25,14 +25,11 @@ package org.geysermc.connector.network.translators.inventory; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater; import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; -import org.geysermc.connector.utils.InventoryUtils; - -import java.util.List; public abstract class ChestInventoryTranslator extends BaseInventoryTranslator { private final InventoryUpdater updater; @@ -53,17 +50,10 @@ public abstract class ChestInventoryTranslator extends BaseInventoryTranslator { } @Override - public void translateActions(GeyserSession session, Inventory inventory, List actions) { - for (InventoryActionData action : actions) { - if (action.getSource().getContainerId() == inventory.getId()) { - if (action.getSlot() >= size) { - updateInventory(session, inventory); - InventoryUtils.updateCursor(session); - return; - } - } + public BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot) { + if (javaSlot < this.size) { + return new BedrockContainerSlot(ContainerSlotType.CONTAINER, javaSlot); } - - super.translateActions(session, inventory, actions); + return super.javaSlotToBedrockContainer(javaSlot); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java deleted file mode 100644 index b260565b8..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2019-2020 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.translators.inventory; - -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; -import com.nukkitx.protocol.bedrock.data.inventory.InventorySource; -import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; -import org.geysermc.connector.utils.InventoryUtils; - -import java.util.List; - -public class CraftingInventoryTranslator extends BlockInventoryTranslator { - public CraftingInventoryTranslator() { - super(10, "minecraft:crafting_table", ContainerType.WORKBENCH, new CursorInventoryUpdater()); - } - - @Override - public int bedrockSlotToJava(InventoryActionData action) { - if (action.getSlot() == 50) { - // Slot 50 is used for crafting with a controller. - return 0; - } - - if (action.getSource().getContainerId() == ContainerId.UI) { - int slotnum = action.getSlot(); - if (slotnum >= 32 && 42 >= slotnum) { - return slotnum - 31; - } - } - return super.bedrockSlotToJava(action); - } - - @Override - public int javaSlotToBedrock(int slot) { - if (slot < size) { - return slot == 0 ? 50 : slot + 31; - } - return super.javaSlotToBedrock(slot); - } - - @Override - public SlotType getSlotType(int javaSlot) { - if (javaSlot == 0) - return SlotType.OUTPUT; - return SlotType.NORMAL; - } - - @Override - public void translateActions(GeyserSession session, Inventory inventory, List actions) { - if (session.getGameMode() == GameMode.CREATIVE) { - for (InventoryActionData action : actions) { - if (action.getSource().getType() == InventorySource.Type.CREATIVE) { - updateInventory(session, inventory); - InventoryUtils.updateCursor(session); - return; - } - } - } - super.translateActions(session, inventory, actions); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java deleted file mode 100644 index cbcdce10b..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 2019-2020 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.translators.inventory; - -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientClickWindowButtonPacket; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.nbt.NbtMapBuilder; -import com.nukkitx.nbt.NbtType; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; -import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; -import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; -import org.geysermc.connector.common.ChatColor; -import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; -import org.geysermc.connector.network.translators.item.ItemTranslator; -import org.geysermc.connector.utils.InventoryUtils; -import org.geysermc.connector.utils.LocaleUtils; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * A temporary reconstruction of the enchantment table UI until our inventory rewrite is complete. - * The enchantment table on Bedrock without server authoritative inventories doesn't tell us which button is pressed - * when selecting an enchantment. - */ -public class EnchantmentInventoryTranslator extends BlockInventoryTranslator { - - private static final int DYE_ID = 351; - private static final short LAPIS_DAMAGE = 4; - private static final int ENCHANTED_BOOK_ID = 403; - - public EnchantmentInventoryTranslator(InventoryUpdater updater) { - super(2, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, updater); - } - - @Override - public void translateActions(GeyserSession session, Inventory inventory, List actions) { - for (InventoryActionData action : actions) { - if (action.getSource().getContainerId() == inventory.getId()) { - // This is the hopper UI - switch (action.getSlot()) { - case 1: - // Don't allow the slot to be put through if the item isn't lapis - if ((action.getToItem().getId() != DYE_ID - && action.getToItem().getDamage() != LAPIS_DAMAGE) && action.getToItem() != ItemData.AIR) { - updateInventory(session, inventory); - InventoryUtils.updateCursor(session); - return; - } - break; - case 2: - case 3: - case 4: - // The books here act as buttons - ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), action.getSlot() - 2); - session.sendDownstreamPacket(packet); - updateInventory(session, inventory); - InventoryUtils.updateCursor(session); - return; - default: - break; - } - } - } - - super.translateActions(session, inventory, actions); - } - - @Override - public void updateInventory(GeyserSession session, Inventory inventory) { - super.updateInventory(session, inventory); - ItemData[] items = new ItemData[5]; - items[0] = ItemTranslator.translateToBedrock(session, inventory.getItem(0)); - items[1] = ItemTranslator.translateToBedrock(session, inventory.getItem(1)); - for (int i = 0; i < 3; i++) { - items[i + 2] = session.getEnchantmentSlotData()[i].getItem() != null ? session.getEnchantmentSlotData()[i].getItem() : createEnchantmentBook(); - } - - InventoryContentPacket contentPacket = new InventoryContentPacket(); - contentPacket.setContainerId(inventory.getId()); - contentPacket.setContents(items); - session.sendUpstreamPacket(contentPacket); - } - - @Override - public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { - int bookSlotToUpdate; - switch (key) { - case 0: - case 1: - case 2: - // Experience required - bookSlotToUpdate = key; - session.getEnchantmentSlotData()[bookSlotToUpdate].setExperienceRequired(value); - break; - case 4: - case 5: - case 6: - // Enchantment name - bookSlotToUpdate = key - 4; - if (value != -1) { - session.getEnchantmentSlotData()[bookSlotToUpdate].setEnchantmentType(EnchantmentTableEnchantments.values()[value - 1]); - } else { - // -1 means no enchantment specified - session.getEnchantmentSlotData()[bookSlotToUpdate].setEnchantmentType(null); - } - break; - case 7: - case 8: - case 9: - // Enchantment level - bookSlotToUpdate = key - 7; - session.getEnchantmentSlotData()[bookSlotToUpdate].setEnchantmentLevel(value); - break; - default: - return; - } - updateEnchantmentBook(session, inventory, bookSlotToUpdate); - } - - @Override - public void openInventory(GeyserSession session, Inventory inventory) { - super.openInventory(session, inventory); - for (int i = 0; i < session.getEnchantmentSlotData().length; i++) { - session.getEnchantmentSlotData()[i] = new EnchantmentSlotData(); - } - } - - @Override - public void closeInventory(GeyserSession session, Inventory inventory) { - super.closeInventory(session, inventory); - Arrays.fill(session.getEnchantmentSlotData(), null); - } - - private ItemData createEnchantmentBook() { - NbtMapBuilder root = NbtMap.builder(); - NbtMapBuilder display = NbtMap.builder(); - - display.putString("Name", ChatColor.RESET + "No Enchantment"); - - root.put("display", display.build()); - return ItemData.of(ENCHANTED_BOOK_ID, (short) 0, 1, root.build()); - } - - private void updateEnchantmentBook(GeyserSession session, Inventory inventory, int slot) { - NbtMapBuilder root = NbtMap.builder(); - NbtMapBuilder display = NbtMap.builder(); - EnchantmentSlotData data = session.getEnchantmentSlotData()[slot]; - if (data.getEnchantmentType() != null) { - display.putString("Name", ChatColor.ITALIC + data.getEnchantmentType().toString(session) + - (data.getEnchantmentLevel() != -1 ? " " + toRomanNumeral(session, data.getEnchantmentLevel()) : "") + "?"); - } else { - display.putString("Name", ChatColor.RESET + "No Enchantment"); - } - - display.putList("Lore", NbtType.STRING, Collections.singletonList(ChatColor.DARK_GRAY + data.getExperienceRequired() + "xp")); - root.put("display", display.build()); - ItemData book = ItemData.of(ENCHANTED_BOOK_ID, (short) 0, 1, root.build()); - - InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(inventory.getId()); - slotPacket.setSlot(slot + 2); - slotPacket.setItem(book); - session.sendUpstreamPacket(slotPacket); - data.setItem(book); - } - - private String toRomanNumeral(GeyserSession session, int level) { - return LocaleUtils.getLocaleString("enchantment.level." + level, - session.getClientData().getLanguageCode()); - } - - /** - * Stores the data of each slot in an enchantment table - */ - @NoArgsConstructor - @Getter - @Setter - @ToString - public static class EnchantmentSlotData { - private EnchantmentTableEnchantments enchantmentType = null; - private int enchantmentLevel = 0; - private int experienceRequired = 0; - private ItemData item; - } - - /** - * Classifies enchantments by Java order - */ - public enum EnchantmentTableEnchantments { - PROTECTION, - FIRE_PROTECTION, - FEATHER_FALLING, - BLAST_PROTECTION, - PROJECTILE_PROTECTION, - RESPIRATION, - AQUA_AFFINITY, - THORNS, - DEPTH_STRIDER, - FROST_WALKER, - BINDING_CURSE, - SHARPNESS, - SMITE, - BANE_OF_ARTHROPODS, - KNOCKBACK, - FIRE_ASPECT, - LOOTING, - SWEEPING, - EFFICIENCY, - SILK_TOUCH, - UNBREAKING, - FORTUNE, - POWER, - PUNCH, - FLAME, - INFINITY, - LUCK_OF_THE_SEA, - LURE, - LOYALTY, - IMPALING, - RIPTIDE, - CHANNELING, - MENDING, - VANISHING_CURSE, // After this is not documented - MULTISHOT, - PIERCING, - QUICK_CHARGE, - SOUL_SPEED; - - public String toString(GeyserSession session) { - return LocaleUtils.getLocaleString("enchantment.minecraft." + this.toString().toLowerCase(), - session.getClientData().getLanguageCode()); - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java deleted file mode 100644 index 1f148e024..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2019-2020 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.translators.inventory; - -import com.github.steveice10.mc.protocol.data.game.window.WindowType; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket; -import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; - -public class FurnaceInventoryTranslator extends BlockInventoryTranslator { - public FurnaceInventoryTranslator() { - super(3, "minecraft:furnace[facing=north,lit=false]", ContainerType.FURNACE, new ContainerInventoryUpdater()); - } - - @Override - public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { - ContainerSetDataPacket dataPacket = new ContainerSetDataPacket(); - dataPacket.setWindowId((byte) inventory.getId()); - switch (key) { - case 0: - dataPacket.setProperty(ContainerSetDataPacket.FURNACE_LIT_TIME); - break; - case 1: - dataPacket.setProperty(ContainerSetDataPacket.FURNACE_LIT_DURATION); - break; - case 2: - dataPacket.setProperty(ContainerSetDataPacket.FURNACE_TICK_COUNT); - if (inventory.getWindowType() == WindowType.BLAST_FURNACE || inventory.getWindowType() == WindowType.SMOKER) { - value *= 2; - } - break; - default: - return; - } - dataPacket.setValue(value); - session.sendUpstreamPacket(dataPacket); - } - - @Override - public SlotType getSlotType(int javaSlot) { - if (javaSlot == 2) - return SlotType.FURNACE_OUTPUT; - return SlotType.NORMAL; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GrindstoneInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GrindstoneInventoryTranslator.java deleted file mode 100644 index 4b4a12465..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GrindstoneInventoryTranslator.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2019-2020 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.translators.inventory; - -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; -import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; - -public class GrindstoneInventoryTranslator extends BlockInventoryTranslator { - - public GrindstoneInventoryTranslator() { - super(3, "minecraft:grindstone[face=floor,facing=north]", ContainerType.GRINDSTONE, new CursorInventoryUpdater()); - } - - @Override - public int bedrockSlotToJava(InventoryActionData action) { - final int slot = super.bedrockSlotToJava(action); - if (action.getSource().getContainerId() == ContainerId.UI) { - switch (slot) { - case 16: - return 0; - case 17: - return 1; - case 50: - return 2; - default: - return slot; - } - } return slot; - } - - @Override - public int javaSlotToBedrock(int slot) { - switch (slot) { - case 0: - return 16; - case 1: - return 17; - case 2: - return 50; - } - return super.javaSlotToBedrock(slot); - } - -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index e44e4bd0b..b4a12b00f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -25,18 +25,26 @@ package org.geysermc.connector.network.translators.inventory; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.window.WindowType; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.*; +import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; +import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import lombok.AllArgsConstructor; +import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; -import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; +import org.geysermc.connector.network.translators.inventory.click.Click; +import org.geysermc.connector.network.translators.inventory.click.ClickPlan; +import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.network.translators.item.ItemTranslator; +import org.geysermc.connector.utils.InventoryUtils; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; @AllArgsConstructor public abstract class InventoryTranslator { @@ -50,12 +58,13 @@ public abstract class InventoryTranslator { put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36)); put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45)); put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54)); - put(WindowType.BREWING_STAND, new BrewingInventoryTranslator()); + /*put(WindowType.BREWING_STAND, new BrewingInventoryTranslator()); put(WindowType.ANVIL, new AnvilInventoryTranslator()); put(WindowType.CRAFTING, new CraftingInventoryTranslator()); - put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator()); + put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());*/ put(WindowType.MERCHANT, new MerchantInventoryTranslator()); - put(WindowType.SMITHING, new SmithingInventoryTranslator()); + /*put(WindowType.SMITHING, new SmithingInventoryTranslator()); + //put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO InventoryTranslator furnace = new FurnaceInventoryTranslator(); put(WindowType.FURNACE, furnace); @@ -63,14 +72,15 @@ public abstract class InventoryTranslator { put(WindowType.SMOKER, furnace); InventoryUpdater containerUpdater = new ContainerInventoryUpdater(); - put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator(containerUpdater)); //TODO put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, containerUpdater)); put(WindowType.HOPPER, new BlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, containerUpdater)); put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER, containerUpdater)); - //put(WindowType.BEACON, new BlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO + //put(WindowType.BEACON, new BlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO*/ } }; + public static final int PLAYER_INVENTORY_SIZE = 36; + public static final int PLAYER_INVENTORY_OFFSET = 9; public final int size; public abstract void prepareInventory(GeyserSession session, Inventory inventory); @@ -79,8 +89,428 @@ public abstract class InventoryTranslator { public abstract void updateProperty(GeyserSession session, Inventory inventory, int key, int value); public abstract void updateInventory(GeyserSession session, Inventory inventory); public abstract void updateSlot(GeyserSession session, Inventory inventory, int slot); - public abstract int bedrockSlotToJava(InventoryActionData action); - public abstract int javaSlotToBedrock(int slot); + public abstract int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData); + public abstract int javaSlotToBedrock(int javaSlot); //TODO + public abstract BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot); //TODO public abstract SlotType getSlotType(int javaSlot); - public abstract void translateActions(GeyserSession session, Inventory inventory, List actions); + public abstract Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory); + + public void translateRequests(GeyserSession session, Inventory inventory, List requests) { + ItemStackResponsePacket responsePacket = new ItemStackResponsePacket(); + for (ItemStackRequestPacket.Request request : requests) { + if (request.getActions().length > 0) { + StackRequestActionData firstAction = request.getActions()[0]; + if (firstAction.getType() == StackRequestActionType.CRAFT_RECIPE || firstAction.getType() == StackRequestActionType.CRAFT_RECIPE_AUTO) { + responsePacket.getEntries().add(translateCraftingRequest(session, inventory, request)); + } else if (firstAction.getType() == StackRequestActionType.CRAFT_CREATIVE) { + responsePacket.getEntries().add(translateCreativeRequest(session, inventory, request)); + } else { + responsePacket.getEntries().add(translateRequest(session, inventory, request)); + } + } else { + responsePacket.getEntries().add(rejectRequest(request)); + } + } + session.sendUpstreamPacket(responsePacket); + System.out.println(responsePacket); + } + + public ItemStackResponsePacket.Response translateRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + System.out.println(request); + ClickPlan plan = new ClickPlan(session, this, inventory); + for (StackRequestActionData action : request.getActions()) { + GeyserItemStack cursor = session.getPlayerInventory().getCursor(); + switch (action.getType()) { + case TAKE: + case PLACE: { + TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action; + if (!(checkNetId(session, inventory, transferAction.getSource()) && checkNetId(session, inventory, transferAction.getDestination()))) + return rejectRequest(request); + + if (isCursor(transferAction.getSource()) && isCursor(transferAction.getDestination())) { //??? + return rejectRequest(request); + } else if (isCursor(transferAction.getSource())) { //releasing cursor + int sourceAmount = cursor.getAmount(); + int destSlot = bedrockSlotToJava(transferAction.getDestination()); + if (transferAction.getCount() == sourceAmount) { //release all + plan.add(Click.LEFT, destSlot); + } else { //release some + for (int i = 0; i < transferAction.getCount(); i++) { + plan.add(Click.RIGHT, destSlot); + } + } + } else if (isCursor(transferAction.getDestination())) { //picking up into cursor + int sourceSlot = bedrockSlotToJava(transferAction.getSource()); + GeyserItemStack sourceItem = plan.getItem(sourceSlot); + int sourceAmount = sourceItem.getAmount(); + if (cursor.isEmpty()) { //picking up into empty cursor + if (transferAction.getCount() == sourceAmount) { //pickup all + plan.add(Click.LEFT, sourceSlot); + } else if (transferAction.getCount() == sourceAmount - (sourceAmount / 2)) { //larger half; simple right click + plan.add(Click.RIGHT, sourceSlot); + } else { //pickup some; not a simple right click + plan.add(Click.LEFT, sourceSlot); //first pickup all + for (int i = 0; i < sourceAmount - transferAction.getCount(); i++) { + plan.add(Click.RIGHT, sourceSlot); //release extra items back into source slot + } + } + } else { //pickup into non-empty cursor + if (!InventoryUtils.canStack(cursor, plan.getItem(sourceSlot))) { //doesn't make sense, reject + return rejectRequest(request); + } + if (transferAction.getCount() != sourceAmount) { //TODO: handle partially picking up into non-empty cursor (temp slot) + return rejectRequest(request); + } + plan.add(Click.LEFT, sourceSlot); //release cursor onto source slot + plan.add(Click.LEFT, sourceSlot); //pickup combined cursor and source + } + } else { //transfer from one slot to another + if (!cursor.isEmpty()) { //TODO: handle slot transfer when cursor is already in use (temp slot) + return rejectRequest(request); + } + int sourceSlot = bedrockSlotToJava(transferAction.getSource()); + int sourceAmount = plan.getItem(sourceSlot).getAmount(); + int destSlot = bedrockSlotToJava(transferAction.getDestination()); + if (transferAction.getCount() == sourceAmount) { //transfer all + plan.add(Click.LEFT, sourceSlot); //pickup source + plan.add(Click.LEFT, destSlot); //let go of all items and done + } else { //transfer some + //try to transfer items with least clicks possible + int halfSource = sourceAmount / 2; //smaller half + int holding; + if (transferAction.getCount() <= halfSource) { //faster to take only half + plan.add(Click.RIGHT, sourceSlot); + holding = halfSource; + } else { //need all + plan.add(Click.LEFT, sourceSlot); + holding = sourceAmount; + } + if (transferAction.getCount() > holding / 2) { //faster to release extra items onto source or dest slot? + for (int i = 0; i < holding - transferAction.getCount(); i++) { + plan.add(Click.RIGHT, sourceSlot); //prepare cursor + } + plan.add(Click.LEFT, destSlot); //release cursor onto dest slot + } else { + for (int i = 0; i < transferAction.getCount(); i++) { + plan.add(Click.RIGHT, destSlot); //right click until transfer goal is met + } + plan.add(Click.LEFT, sourceSlot); //return extra items to source slot + } + } + } + break; + } + case SWAP: { //TODO + SwapStackRequestActionData swapAction = (SwapStackRequestActionData) action; + if (!(checkNetId(session, inventory, swapAction.getSource()) && checkNetId(session, inventory, swapAction.getDestination()))) + return rejectRequest(request); + + if (isCursor(swapAction.getSource()) && isCursor(swapAction.getDestination())) { //??? + return rejectRequest(request); + } else if (isCursor(swapAction.getSource())) { //swap cursor + int destSlot = bedrockSlotToJava(swapAction.getDestination()); + if (InventoryUtils.canStack(cursor, plan.getItem(destSlot))) { //TODO: cannot simply swap if cursor stacks with slot (temp slot) + return rejectRequest(request); + } + plan.add(Click.LEFT, destSlot); + } else if (isCursor(swapAction.getDestination())) { //swap cursor + int sourceSlot = bedrockSlotToJava(swapAction.getSource()); + if (InventoryUtils.canStack(cursor, plan.getItem(sourceSlot))) { //TODO + return rejectRequest(request); + } + plan.add(Click.LEFT, sourceSlot); + } else { + int sourceSlot = bedrockSlotToJava(swapAction.getSource()); + int destSlot = bedrockSlotToJava(swapAction.getDestination()); + if (!cursor.isEmpty()) { //TODO: (temp slot) + return rejectRequest(request); + } + if (sourceSlot == destSlot) { //doesn't make sense + return rejectRequest(request); + } + if (InventoryUtils.canStack(plan.getItem(sourceSlot), plan.getItem(destSlot))) { //TODO: (temp slot) + return rejectRequest(request); + } + plan.add(Click.LEFT, sourceSlot); //pickup source into cursor + plan.add(Click.LEFT, destSlot); //swap cursor with dest slot + plan.add(Click.LEFT, sourceSlot); //release cursor onto source + } + break; + } + case DROP: { + DropStackRequestActionData dropAction = (DropStackRequestActionData) action; + if (!checkNetId(session, inventory, dropAction.getSource())) + return rejectRequest(request); + + if (isCursor(dropAction.getSource())) { //clicking outside of window + int sourceAmount = plan.getCursor().getAmount(); + if (dropAction.getCount() == sourceAmount) { //drop all + plan.add(Click.LEFT_OUTSIDE, Click.OUTSIDE_SLOT); + } else { //drop some + for (int i = 0; i < dropAction.getCount(); i++) { + plan.add(Click.RIGHT_OUTSIDE, Click.OUTSIDE_SLOT); //drop one until goal is met + } + } + } else { //dropping from inventory + int sourceSlot = bedrockSlotToJava(dropAction.getSource()); + int sourceAmount = plan.getItem(sourceSlot).getAmount(); + if (dropAction.getCount() == sourceAmount && sourceAmount > 1) { //dropping all? (prefer DROP_ONE if only one) + plan.add(Click.DROP_ALL, sourceSlot); + } else { //drop some + for (int i = 0; i < dropAction.getCount(); i++) { + plan.add(Click.DROP_ONE, sourceSlot); //drop one until goal is met + } + } + } + break; + } + case CRAFT_CREATIVE: { + CraftCreativeStackRequestActionData creativeAction = (CraftCreativeStackRequestActionData) action; + System.out.println(creativeAction.getCreativeItemNetworkId()); + } + default: + return rejectRequest(request); + } + } + plan.execute(false); + return acceptRequest(request, makeContainerEntries(session, inventory, plan.getAffectedSlots())); + } + + public ItemStackResponsePacket.Response translateCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + System.out.println(request); + + int recipeId = 0; + int resultSize = 0; + boolean autoCraft; + CraftState craftState = CraftState.START; + + int leftover = 0; + ClickPlan plan = new ClickPlan(session, this, inventory); + for (StackRequestActionData action : request.getActions()) { + switch (action.getType()) { + case CRAFT_RECIPE: { + CraftRecipeStackRequestActionData craftAction = (CraftRecipeStackRequestActionData) action; + if (craftState != CraftState.START) { + return rejectRequest(request); + } + craftState = CraftState.RECIPE_ID; + recipeId = craftAction.getRecipeNetworkId(); + System.out.println(session.getCraftingRecipes().get(recipeId).toString()); + autoCraft = false; + break; + } + /*case CRAFT_RECIPE_AUTO: { + AutoCraftRecipeStackRequestActionData autoCraftAction = (AutoCraftRecipeStackRequestActionData) action; + if (craftState != CraftState.START) { + return rejectRequest(request); + } + craftState = CraftState.RECIPE_ID; + recipeId = autoCraftAction.getRecipeNetworkId(); + autoCraft = true; + //TODO: reject transaction if crafting grid is not clear + break; + }*/ + case CRAFT_RESULTS_DEPRECATED: { + CraftResultsDeprecatedStackRequestActionData deprecatedCraftAction = (CraftResultsDeprecatedStackRequestActionData) action; + if (craftState != CraftState.RECIPE_ID) { + return rejectRequest(request); + } + craftState = CraftState.DEPRECATED; + + if (deprecatedCraftAction.getResultItems().length != 1) { + return rejectRequest(request); + } + resultSize = deprecatedCraftAction.getResultItems()[0].getCount(); + if (resultSize <= 0) { + return rejectRequest(request); + } + break; + } + case CONSUME: { + ConsumeStackRequestActionData consumeAction = (ConsumeStackRequestActionData) action; + if (craftState != CraftState.DEPRECATED && craftState != CraftState.INGREDIENTS) { + return rejectRequest(request); + } + craftState = CraftState.INGREDIENTS; + break; + } + case TAKE: + case PLACE: { + TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action; + if (craftState != CraftState.INGREDIENTS && craftState != CraftState.TRANSFER) { + return rejectRequest(request); + } + craftState = CraftState.TRANSFER; + + if (transferAction.getSource().getContainer() != ContainerSlotType.CREATIVE_OUTPUT) { + return rejectRequest(request); + } + if (transferAction.getCount() <= 0) { + return rejectRequest(request); + } + + int sourceSlot = bedrockSlotToJava(transferAction.getSource()); + if (isCursor(transferAction.getDestination())) { + plan.add(Click.LEFT, sourceSlot); + craftState = CraftState.DONE; + } else { + int destSlot = bedrockSlotToJava(transferAction.getDestination()); + if (leftover != 0) { + if (transferAction.getCount() > leftover) { + return rejectRequest(request); + } + if (transferAction.getCount() == leftover) { + plan.add(Click.LEFT, destSlot); + } else { + for (int i = 0; i < transferAction.getCount(); i++) { + plan.add(Click.RIGHT, destSlot); + } + } + leftover -= transferAction.getCount(); + break; + } + + int remainder = transferAction.getCount() % resultSize; + int timesToCraft = transferAction.getCount() / resultSize; + for (int i = 0; i < timesToCraft; i++) { + plan.add(Click.LEFT, sourceSlot); + plan.add(Click.LEFT, destSlot); + } + if (remainder > 0) { + plan.add(Click.LEFT, 0); + for (int i = 0; i < remainder; i++) { + plan.add(Click.RIGHT, destSlot); + } + leftover = resultSize - remainder; + } + } + break; + } + default: + return rejectRequest(request); + } + } + plan.execute(false); + Set affectedSlots = plan.getAffectedSlots(); + affectedSlots.addAll(Arrays.asList(1, 2, 3, 4)); //TODO: crafting grid + return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); + } + + public ItemStackResponsePacket.Response translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + int creativeId = 0; + CraftState craftState = CraftState.START; + for (StackRequestActionData action : request.getActions()) { + switch (action.getType()) { + case CRAFT_CREATIVE: { + CraftCreativeStackRequestActionData creativeAction = (CraftCreativeStackRequestActionData) action; + if (craftState != CraftState.START) { + return rejectRequest(request); + } + craftState = CraftState.RECIPE_ID; + + creativeId = creativeAction.getCreativeItemNetworkId(); + break; + } + case CRAFT_RESULTS_DEPRECATED: { + CraftResultsDeprecatedStackRequestActionData deprecatedCraftAction = (CraftResultsDeprecatedStackRequestActionData) action; + if (craftState != CraftState.RECIPE_ID) { + return rejectRequest(request); + } + craftState = CraftState.DEPRECATED; + break; + } + case TAKE: + case PLACE: { + TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action; + if (craftState != CraftState.DEPRECATED) { + return rejectRequest(request); + } + craftState = CraftState.TRANSFER; + + if (transferAction.getSource().getContainer() != ContainerSlotType.CREATIVE_OUTPUT) { + return rejectRequest(request); + } + if (isCursor(transferAction.getDestination())) { + session.getPlayerInventory().setCursor(GeyserItemStack.from(ItemTranslator.translateToJava(ItemRegistry.CREATIVE_ITEMS[creativeId]), session.getItemNetId().getAndIncrement())); //TODO + return acceptRequest(request, makeContainerEntries(session, inventory, Collections.emptySet())); + } else { + int javaSlot = bedrockSlotToJava(transferAction.getDestination()); + ItemStack javaItem = ItemTranslator.translateToJava(ItemRegistry.CREATIVE_ITEMS[creativeId - 1]); //TODO + inventory.setItem(javaSlot, GeyserItemStack.from(javaItem, session.getItemNetId().getAndIncrement())); + ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( + javaSlot, + javaItem + ); + session.sendDownstreamPacket(creativeActionPacket); + Set affectedSlots = Collections.singleton(javaSlot); + return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); + } + } + default: + return rejectRequest(request); + } + } + return rejectRequest(request); + } + + public static ItemStackResponsePacket.Response acceptRequest(ItemStackRequestPacket.Request request, List containerEntries) { + return new ItemStackResponsePacket.Response(true, request.getRequestId(), containerEntries); + } + + public static ItemStackResponsePacket.Response rejectRequest(ItemStackRequestPacket.Request request) { + new Throwable("DEBUGGING: ItemStackRequest rejected").printStackTrace(); //TODO: temporary debugging + return new ItemStackResponsePacket.Response(false, request.getRequestId(), Collections.emptyList()); + } + + public boolean checkNetId(GeyserSession session, Inventory inventory, StackRequestSlotInfoData slotInfoData) { + if (slotInfoData.getStackNetworkId() < 0) + return true; + + GeyserItemStack currentItem = isCursor(slotInfoData) ? session.getPlayerInventory().getCursor() : inventory.getItem(bedrockSlotToJava(slotInfoData)); + return currentItem.getNetId() == slotInfoData.getStackNetworkId(); + } + + public List makeContainerEntries(GeyserSession session, Inventory inventory, Set affectedSlots) { + Map> containerMap = new HashMap<>(); + for (int slot : affectedSlots) { + BedrockContainerSlot bedrockSlot = javaSlotToBedrockContainer(slot); + List list = containerMap.computeIfAbsent(bedrockSlot.getContainer(), k -> new ArrayList<>()); + list.add(makeItemEntry(session, bedrockSlot.getSlot(), inventory.getItem(slot))); + } + + List containerEntries = new ArrayList<>(); + for (Map.Entry> entry : containerMap.entrySet()) { + containerEntries.add(new ItemStackResponsePacket.ContainerEntry(entry.getKey(), entry.getValue())); + } + + ItemStackResponsePacket.ItemEntry cursorEntry = makeItemEntry(session, 0, session.getPlayerInventory().getCursor()); + containerEntries.add(new ItemStackResponsePacket.ContainerEntry(ContainerSlotType.CURSOR, Collections.singletonList(cursorEntry))); + + return containerEntries; + } + + public static ItemStackResponsePacket.ItemEntry makeItemEntry(GeyserSession session, int bedrockSlot, GeyserItemStack itemStack) { + ItemStackResponsePacket.ItemEntry itemEntry; + if (!itemStack.isEmpty()) { + int newNetId = session.getItemNetId().getAndIncrement(); + itemStack.setNetId(newNetId); + itemEntry = new ItemStackResponsePacket.ItemEntry((byte) bedrockSlot, (byte) bedrockSlot, (byte) itemStack.getAmount(), newNetId); + } else { + itemEntry = new ItemStackResponsePacket.ItemEntry((byte) bedrockSlot, (byte) bedrockSlot, (byte) 0, 0); + } + return itemEntry; + } + + private static boolean isCursor(StackRequestSlotInfoData slotInfoData) { + return slotInfoData.getContainer() == ContainerSlotType.CURSOR; + } + + private enum CraftState { + START, + RECIPE_ID, + DEPRECATED, + INGREDIENTS, + TRANSFER, + DONE + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java index 25fdae688..c4b2fc9a1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java @@ -25,15 +25,21 @@ package org.geysermc.connector.network.translators.inventory; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; -import com.nukkitx.protocol.bedrock.data.inventory.InventorySource; +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.entity.EntityDataMap; +import com.nukkitx.protocol.bedrock.data.entity.EntityLinkData; +import com.nukkitx.protocol.bedrock.data.inventory.*; +import com.nukkitx.protocol.bedrock.packet.SetEntityLinkPacket; +import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.MerchantContainer; +import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; - -import java.util.List; +import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; public class MerchantInventoryTranslator extends BaseInventoryTranslator { @@ -41,7 +47,7 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator { public MerchantInventoryTranslator() { super(3); - this.updater = new CursorInventoryUpdater(); + this.updater = new UIInventoryUpdater(); } @Override @@ -58,26 +64,30 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator { } @Override - public int bedrockSlotToJava(InventoryActionData action) { - switch (action.getSource().getContainerId()) { - case ContainerId.UI: - switch (action.getSlot()) { - case 4: - return 0; - case 5: - return 1; - case 50: - return 2; - } - break; - case -28: // Trading 1? + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + switch (slot) { + case 0: + return new BedrockContainerSlot(ContainerSlotType.TRADE2_INGREDIENT1, 4); + case 1: + return new BedrockContainerSlot(ContainerSlotType.TRADE2_INGREDIENT2, 5); + case 2: + return new BedrockContainerSlot(ContainerSlotType.TRADE2_RESULT, 50); + } + return super.javaSlotToBedrockContainer(slot); + } + + @Override + public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { + switch (slotInfoData.getContainer()) { + case TRADE2_INGREDIENT1: return 0; - case -29: // Trading 2? + case TRADE2_INGREDIENT2: return 1; - case -30: // Trading Output? + case TRADE2_RESULT: + case CREATIVE_OUTPUT: return 2; } - return super.bedrockSlotToJava(action); + return super.bedrockSlotToJava(slotInfoData); } @Override @@ -90,18 +100,40 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator { @Override public void prepareInventory(GeyserSession session, Inventory inventory) { + MerchantContainer merchantInventory = (MerchantContainer) inventory; + if (merchantInventory.getVillager() == null) { + long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet(); + Vector3f pos = session.getPlayerEntity().getPosition().sub(0, 3, 0); + EntityDataMap metadata = new EntityDataMap(); + metadata.put(EntityData.SCALE, 0f); + metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0f); + metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0f); + + Entity villager = new Entity(0, geyserId, EntityType.VILLAGER, pos, Vector3f.ZERO, Vector3f.ZERO); + villager.setMetadata(metadata); + villager.spawnEntity(session); + + SetEntityLinkPacket linkPacket = new SetEntityLinkPacket(); + EntityLinkData.Type type = EntityLinkData.Type.PASSENGER; + linkPacket.setEntityLink(new EntityLinkData(session.getPlayerEntity().getGeyserId(), geyserId, type, true, false)); + session.sendUpstreamPacket(linkPacket); + + merchantInventory.setVillager(villager); + } } @Override public void openInventory(GeyserSession session, Inventory inventory) { - + //Handled in JavaTradeListTranslator } @Override public void closeInventory(GeyserSession session, Inventory inventory) { - session.setLastInteractedVillagerEid(-1); - session.setVillagerTrades(null); + MerchantContainer merchantInventory = (MerchantContainer) inventory; + if (merchantInventory.getVillager() != null) { + merchantInventory.getVillager().despawnEntity(session); + } } @Override @@ -115,11 +147,7 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator { } @Override - public void translateActions(GeyserSession session, Inventory inventory, List actions) { - if (actions.stream().anyMatch(a -> a.getSource().getContainerId() == -31)) { - return; - } - - super.translateActions(session, inventory, actions); + public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { + return new MerchantContainer(name, windowId, windowType, this.size, playerInventory); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java index 7d7673c4e..48315fc1c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java @@ -25,18 +25,15 @@ package org.geysermc.connector.network.translators.inventory; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; -import com.nukkitx.protocol.bedrock.data.inventory.InventorySource; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.nukkitx.protocol.bedrock.data.inventory.*; import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; +import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.action.InventoryActionDataTranslator; import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.utils.InventoryUtils; import org.geysermc.connector.utils.LanguageUtils; @@ -59,11 +56,11 @@ public class PlayerInventoryTranslator extends InventoryTranslator { ItemData[] contents = new ItemData[36]; // Inventory for (int i = 9; i < 36; i++) { - contents[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(i)); + contents[i] = inventory.getItem(i).getItemData(session); } // Hotbar for (int i = 36; i < 45; i++) { - contents[i - 36] = ItemTranslator.translateToBedrock(session, inventory.getItem(i)); + contents[i - 36] = inventory.getItem(i).getItemData(session); } inventoryContentPacket.setContents(contents); session.sendUpstreamPacket(inventoryContentPacket); @@ -73,7 +70,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { armorContentPacket.setContainerId(ContainerId.ARMOR); contents = new ItemData[4]; for (int i = 5; i < 9; i++) { - contents[i - 5] = ItemTranslator.translateToBedrock(session, inventory.getItem(i)); + contents[i - 5] = inventory.getItem(i).getItemData(session); } armorContentPacket.setContents(contents); session.sendUpstreamPacket(armorContentPacket); @@ -81,7 +78,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { // Offhand InventoryContentPacket offhandPacket = new InventoryContentPacket(); offhandPacket.setContainerId(ContainerId.OFFHAND); - offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(session, inventory.getItem(45))}); + offhandPacket.setContents(new ItemData[]{inventory.getItem(45).getItemData(session)}); session.sendUpstreamPacket(offhandPacket); } @@ -100,7 +97,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { if (session.getGameMode() == GameMode.CREATIVE) { slotPacket.setItem(UNUSUABLE_CRAFTING_SPACE_BLOCK); }else{ - slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i))); + slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i).getItemStack())); } session.sendUpstreamPacket(slotPacket); @@ -125,21 +122,23 @@ public class PlayerInventoryTranslator extends InventoryTranslator { slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(slot + 27); } - slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(slot))); + slotPacket.setItem(inventory.getItem(slot).getItemData(session)); session.sendUpstreamPacket(slotPacket); } else if (slot == 45) { InventoryContentPacket offhandPacket = new InventoryContentPacket(); offhandPacket.setContainerId(ContainerId.OFFHAND); - offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(session, inventory.getItem(slot))}); + offhandPacket.setContents(new ItemData[]{inventory.getItem(slot).getItemData(session)}); session.sendUpstreamPacket(offhandPacket); } } @Override - public int bedrockSlotToJava(InventoryActionData action) { - int slotnum = action.getSlot(); - switch (action.getSource().getContainerId()) { - case ContainerId.INVENTORY: + public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { + int slotnum = slotInfoData.getSlot(); + switch (slotInfoData.getContainer()) { + case HOTBAR_AND_INVENTORY: + case HOTBAR: + case INVENTORY: // Inventory if (slotnum >= 9 && slotnum <= 35) { return slotnum; @@ -149,19 +148,19 @@ public class PlayerInventoryTranslator extends InventoryTranslator { return slotnum + 36; } break; - case ContainerId.ARMOR: + case ARMOR: if (slotnum >= 0 && slotnum <= 3) { return slotnum + 5; } break; - case ContainerId.OFFHAND: + case OFFHAND: return 45; - case ContainerId.UI: + case CRAFTING_INPUT: if (slotnum >= 28 && 31 >= slotnum) { return slotnum - 27; } break; - case ContainerId.CRAFTING_RESULT: + case CREATIVE_OUTPUT: return 0; } return slotnum; @@ -169,7 +168,26 @@ public class PlayerInventoryTranslator extends InventoryTranslator { @Override public int javaSlotToBedrock(int slot) { - return slot; + return -1; + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + if (slot >= 36 && slot <= 44) { + return new BedrockContainerSlot(ContainerSlotType.HOTBAR, slot - 36); + } else if (slot >= 9 && slot <= 35) { + return new BedrockContainerSlot(ContainerSlotType.INVENTORY, slot); + } else if (slot >= 5 && slot <= 8) { + return new BedrockContainerSlot(ContainerSlotType.ARMOR, slot - 5); + } else if (slot == 45) { + return new BedrockContainerSlot(ContainerSlotType.OFFHAND, 1); + } else if (slot >= 1 && slot <= 4) { + return new BedrockContainerSlot(ContainerSlotType.CRAFTING_INPUT, slot + 27); + } else if (slot == 0) { + return new BedrockContainerSlot(ContainerSlotType.CRAFTING_OUTPUT, 0); + } else { + throw new IllegalArgumentException("Unknown bedrock slot"); + } } @Override @@ -180,52 +198,13 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } @Override - public void translateActions(GeyserSession session, Inventory inventory, List actions) { - if (session.getGameMode() == GameMode.CREATIVE) { - //crafting grid is not visible in creative mode in java edition - for (InventoryActionData action : actions) { - if (action.getSource().getContainerId() == ContainerId.UI && (action.getSlot() >= 28 && 31 >= action.getSlot())) { - updateInventory(session, inventory); - InventoryUtils.updateCursor(session); - return; - } - } + public void translateRequests(GeyserSession session, Inventory inventory, List requests) { + super.translateRequests(session, inventory, requests); + } - ItemStack javaItem; - for (InventoryActionData action : actions) { - switch (action.getSource().getContainerId()) { - case ContainerId.INVENTORY: - case ContainerId.ARMOR: - case ContainerId.OFFHAND: - int javaSlot = bedrockSlotToJava(action); - if (action.getToItem().getId() == 0) { - javaItem = new ItemStack(-1, 0, null); - } else { - javaItem = ItemTranslator.translateToJava(action.getToItem()); - } - ClientCreativeInventoryActionPacket creativePacket = new ClientCreativeInventoryActionPacket(javaSlot, javaItem); - session.sendDownstreamPacket(creativePacket); - inventory.setItem(javaSlot, javaItem); - break; - case ContainerId.UI: - if (action.getSlot() == 0) { - session.getInventory().setCursor(ItemTranslator.translateToJava(action.getToItem())); - } - break; - case ContainerId.NONE: - if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION - && action.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) { - javaItem = ItemTranslator.translateToJava(action.getToItem()); - ClientCreativeInventoryActionPacket creativeDropPacket = new ClientCreativeInventoryActionPacket(-1, javaItem); - session.sendDownstreamPacket(creativeDropPacket); - } - break; - } - } - return; - } - - InventoryActionDataTranslator.translate(this, session, inventory, actions); + @Override + public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { + throw new UnsupportedOperationException(); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SmithingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SmithingInventoryTranslator.java deleted file mode 100644 index f7f0acd8c..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SmithingInventoryTranslator.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2019-2020 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.translators.inventory; - -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; -import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; - -public class SmithingInventoryTranslator extends BlockInventoryTranslator { - - public SmithingInventoryTranslator() { - super(3, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, new CursorInventoryUpdater()); - } - - @Override - public int bedrockSlotToJava(InventoryActionData action) { - final int slot = super.bedrockSlotToJava(action); - if (action.getSource().getContainerId() == ContainerId.UI) { - switch (slot) { - case 51: - return 0; - case 52: - return 1; - case 50: - return 2; - default: - return slot; - } - } return slot; - } - - @Override - public int javaSlotToBedrock(int slot) { - switch (slot) { - case 0: - return 51; - case 1: - return 52; - case 2: - return 50; - } - return super.javaSlotToBedrock(slot); - } - -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java deleted file mode 100644 index a9c1eddca..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2019-2020 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.translators.inventory.action; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.github.steveice10.mc.protocol.data.game.window.WindowAction; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientConfirmTransactionPacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket; -import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.inventory.PlayerInventory; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.InventoryTranslator; -import org.geysermc.connector.network.translators.inventory.SlotType; -import org.geysermc.connector.utils.InventoryUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.ListIterator; - -class ClickPlan { - private final List plan = new ArrayList<>(); - - public void add(Click click, int slot) { - plan.add(new ClickAction(click, slot)); - } - - public void execute(GeyserSession session, InventoryTranslator translator, Inventory inventory, boolean refresh) { - PlayerInventory playerInventory = session.getInventory(); - ListIterator planIter = plan.listIterator(); - while (planIter.hasNext()) { - final ClickAction action = planIter.next(); - final ItemStack cursorItem = playerInventory.getCursor(); - final ItemStack clickedItem = inventory.getItem(action.slot); - final short actionId = (short) inventory.getTransactionId().getAndIncrement(); - - //TODO: stop relying on refreshing the inventory for crafting to work properly - if (translator.getSlotType(action.slot) != SlotType.NORMAL) - refresh = true; - - ClientWindowActionPacket clickPacket = new ClientWindowActionPacket(inventory.getId(), - actionId, action.slot, !planIter.hasNext() && refresh ? InventoryUtils.REFRESH_ITEM : clickedItem, - WindowAction.CLICK_ITEM, action.click.actionParam); - - if (translator.getSlotType(action.slot) == SlotType.OUTPUT) { - if (cursorItem == null && clickedItem != null) { - playerInventory.setCursor(clickedItem); - } else if (InventoryUtils.canStack(cursorItem, clickedItem)) { - playerInventory.setCursor(new ItemStack(cursorItem.getId(), - cursorItem.getAmount() + clickedItem.getAmount(), cursorItem.getNbt())); - } - } else { - switch (action.click) { - case LEFT: - if (!InventoryUtils.canStack(cursorItem, clickedItem)) { - playerInventory.setCursor(clickedItem); - inventory.setItem(action.slot, cursorItem); - } else { - playerInventory.setCursor(null); - inventory.setItem(action.slot, new ItemStack(clickedItem.getId(), - clickedItem.getAmount() + cursorItem.getAmount(), clickedItem.getNbt())); - } - break; - case RIGHT: - if (cursorItem == null && clickedItem != null) { - ItemStack halfItem = new ItemStack(clickedItem.getId(), - clickedItem.getAmount() / 2, clickedItem.getNbt()); - inventory.setItem(action.slot, halfItem); - playerInventory.setCursor(new ItemStack(clickedItem.getId(), - clickedItem.getAmount() - halfItem.getAmount(), clickedItem.getNbt())); - } else if (cursorItem != null && clickedItem == null) { - playerInventory.setCursor(new ItemStack(cursorItem.getId(), - cursorItem.getAmount() - 1, cursorItem.getNbt())); - inventory.setItem(action.slot, new ItemStack(cursorItem.getId(), - 1, cursorItem.getNbt())); - } else if (InventoryUtils.canStack(cursorItem, clickedItem)) { - playerInventory.setCursor(new ItemStack(cursorItem.getId(), - cursorItem.getAmount() - 1, cursorItem.getNbt())); - inventory.setItem(action.slot, new ItemStack(clickedItem.getId(), - clickedItem.getAmount() + 1, clickedItem.getNbt())); - } - break; - } - } - session.sendDownstreamPacket(clickPacket); - session.sendDownstreamPacket(new ClientConfirmTransactionPacket(inventory.getId(), actionId, true)); - } - - /*if (refresh) { - translator.updateInventory(session, inventory); - InventoryUtils.updateCursor(session); - }*/ - } - - private static class ClickAction { - final Click click; - final int slot; - ClickAction(Click click, int slot) { - this.click = click; - this.slot = slot; - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java deleted file mode 100644 index 96cbd61fb..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (c) 2019-2020 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.translators.inventory.action; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; -import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; -import com.github.steveice10.mc.protocol.data.game.window.*; -import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; -import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; -import com.nukkitx.protocol.bedrock.data.inventory.InventorySource; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; -import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.InventoryTranslator; -import org.geysermc.connector.network.translators.inventory.SlotType; -import org.geysermc.connector.network.translators.item.ItemTranslator; -import org.geysermc.connector.utils.InventoryUtils; - -import java.util.*; - -public class InventoryActionDataTranslator { - public static void translate(InventoryTranslator translator, GeyserSession session, Inventory inventory, List actions) { - if (actions.size() != 2) - return; - - InventoryActionData worldAction = null; - InventoryActionData cursorAction = null; - InventoryActionData containerAction = null; - boolean refresh = false; - for (InventoryActionData action : actions) { - if (action.getSource().getContainerId() == ContainerId.CRAFTING_USE_INGREDIENT) { - return; - } else if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION) { - worldAction = action; - } else if (action.getSource().getContainerId() == ContainerId.UI && action.getSlot() == 0) { - cursorAction = action; - ItemData translatedCursor = ItemTranslator.translateToBedrock(session, session.getInventory().getCursor()); - if (!translatedCursor.equals(action.getFromItem())) { - refresh = true; - } - } else { - containerAction = action; - ItemData translatedItem = ItemTranslator.translateToBedrock(session, inventory.getItem(translator.bedrockSlotToJava(action))); - if (!translatedItem.equals(action.getFromItem())) { - refresh = true; - } - } - } - - final int craftSlot = session.getCraftSlot(); - session.setCraftSlot(0); - - if (worldAction != null) { - InventoryActionData sourceAction; - if (cursorAction != null) { - sourceAction = cursorAction; - } else { - sourceAction = containerAction; - } - - if (sourceAction != null) { - if (worldAction.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) { - //quick dropping from hotbar? - if (session.getInventoryCache().getOpenInventory() == null && sourceAction.getSource().getContainerId() == ContainerId.INVENTORY) { - int heldSlot = session.getInventory().getHeldItemSlot(); - if (sourceAction.getSlot() == heldSlot) { - ClientPlayerActionPacket actionPacket = new ClientPlayerActionPacket( - sourceAction.getToItem().getCount() == 0 ? PlayerAction.DROP_ITEM_STACK : PlayerAction.DROP_ITEM, - new Position(0, 0, 0), BlockFace.DOWN); - session.sendDownstreamPacket(actionPacket); - ItemStack item = session.getInventory().getItem(heldSlot); - if (item != null) { - session.getInventory().setItem(heldSlot, new ItemStack(item.getId(), item.getAmount() - 1, item.getNbt())); - } - return; - } - } - int dropAmount = sourceAction.getFromItem().getCount() - sourceAction.getToItem().getCount(); - if (sourceAction != cursorAction) { //dropping directly from inventory - int javaSlot = translator.bedrockSlotToJava(sourceAction); - if (dropAmount == sourceAction.getFromItem().getCount()) { - ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(), - inventory.getTransactionId().getAndIncrement(), - javaSlot, null, WindowAction.DROP_ITEM, - DropItemParam.DROP_SELECTED_STACK); - session.sendDownstreamPacket(dropPacket); - } else { - for (int i = 0; i < dropAmount; i++) { - ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(), - inventory.getTransactionId().getAndIncrement(), - javaSlot, null, WindowAction.DROP_ITEM, - DropItemParam.DROP_FROM_SELECTED); - session.sendDownstreamPacket(dropPacket); - } - } - ItemStack item = inventory.getItem(javaSlot); - if (item != null) { - inventory.setItem(javaSlot, new ItemStack(item.getId(), item.getAmount() - dropAmount, item.getNbt())); - } - return; - } else { //clicking outside of inventory - ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getTransactionId().getAndIncrement(), - -999, null, WindowAction.CLICK_ITEM, - dropAmount > 1 ? ClickItemParam.LEFT_CLICK : ClickItemParam.RIGHT_CLICK); - session.sendDownstreamPacket(dropPacket); - ItemStack cursor = session.getInventory().getCursor(); - if (cursor != null) { - session.getInventory().setCursor(new ItemStack(cursor.getId(), dropAmount > 1 ? 0 : cursor.getAmount() - 1, cursor.getNbt())); - } - return; - } - } - } - } else if (cursorAction != null && containerAction != null) { - //left/right click - ClickPlan plan = new ClickPlan(); - int javaSlot = translator.bedrockSlotToJava(containerAction); - if (cursorAction.getFromItem().equals(containerAction.getToItem()) - && containerAction.getFromItem().equals(cursorAction.getToItem()) - && !InventoryUtils.canStack(cursorAction.getFromItem(), containerAction.getFromItem())) { //simple swap - plan.add(Click.LEFT, javaSlot); - } else if (cursorAction.getFromItem().getCount() > cursorAction.getToItem().getCount()) { //release - if (cursorAction.getToItem().getCount() == 0) { - plan.add(Click.LEFT, javaSlot); - } else { - int difference = cursorAction.getFromItem().getCount() - cursorAction.getToItem().getCount(); - for (int i = 0; i < difference; i++) { - plan.add(Click.RIGHT, javaSlot); - } - } - } else { //pickup - if (cursorAction.getFromItem().getCount() == 0) { - if (containerAction.getToItem().getCount() == 0) { //pickup all - plan.add(Click.LEFT, javaSlot); - } else { //pickup some - if (translator.getSlotType(javaSlot) == SlotType.FURNACE_OUTPUT - || containerAction.getToItem().getCount() == containerAction.getFromItem().getCount() / 2) { //right click - plan.add(Click.RIGHT, javaSlot); - } else { - plan.add(Click.LEFT, javaSlot); - int difference = containerAction.getFromItem().getCount() - cursorAction.getToItem().getCount(); - for (int i = 0; i < difference; i++) { - plan.add(Click.RIGHT, javaSlot); - } - } - } - } else { //pickup into non-empty cursor - if (translator.getSlotType(javaSlot) == SlotType.FURNACE_OUTPUT) { - if (containerAction.getToItem().getCount() == 0) { - plan.add(Click.LEFT, javaSlot); - } else { - ClientWindowActionPacket shiftClickPacket = new ClientWindowActionPacket(inventory.getId(), - inventory.getTransactionId().getAndIncrement(), - javaSlot, InventoryUtils.REFRESH_ITEM, WindowAction.SHIFT_CLICK_ITEM, - ShiftClickItemParam.LEFT_CLICK); - session.sendDownstreamPacket(shiftClickPacket); - translator.updateInventory(session, inventory); - return; - } - } else if (translator.getSlotType(javaSlot) == SlotType.OUTPUT) { - plan.add(Click.LEFT, javaSlot); - } else { - int cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Collections.singletonList(javaSlot), false); - if (cursorSlot != -1) { - plan.add(Click.LEFT, cursorSlot); - } else { - translator.updateInventory(session, inventory); - InventoryUtils.updateCursor(session); - return; - } - plan.add(Click.LEFT, javaSlot); - int difference = cursorAction.getToItem().getCount() - cursorAction.getFromItem().getCount(); - for (int i = 0; i < difference; i++) { - plan.add(Click.RIGHT, cursorSlot); - } - plan.add(Click.LEFT, javaSlot); - plan.add(Click.LEFT, cursorSlot); - } - } - } - plan.execute(session, translator, inventory, refresh); - return; - } else { - ClickPlan plan = new ClickPlan(); - InventoryActionData fromAction; - InventoryActionData toAction; - if (actions.get(0).getFromItem().getCount() >= actions.get(0).getToItem().getCount()) { - fromAction = actions.get(0); - toAction = actions.get(1); - } else { - fromAction = actions.get(1); - toAction = actions.get(0); - } - int fromSlot = translator.bedrockSlotToJava(fromAction); - int toSlot = translator.bedrockSlotToJava(toAction); - - if (translator.getSlotType(fromSlot) == SlotType.OUTPUT) { - if ((craftSlot != 0 && craftSlot != -2) && (inventory.getItem(toSlot) == null - || InventoryUtils.canStack(session.getInventory().getCursor(), inventory.getItem(toSlot)))) { - if (fromAction.getToItem().getCount() == 0) { - refresh = true; - plan.add(Click.LEFT, toSlot); - if (craftSlot != -1) { - plan.add(Click.LEFT, craftSlot); - } - } else { - int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount(); - for (int i = 0; i < difference; i++) { - plan.add(Click.RIGHT, toSlot); - } - session.setCraftSlot(craftSlot); - } - plan.execute(session, translator, inventory, refresh); - return; - } else { - session.setCraftSlot(-2); - } - } - - int cursorSlot = -1; - if (session.getInventory().getCursor() != null) { //move cursor contents to a temporary slot - cursorSlot = findTempSlot(inventory, - session.getInventory().getCursor(), - Arrays.asList(fromSlot, toSlot), - translator.getSlotType(fromSlot) == SlotType.OUTPUT); - if (cursorSlot != -1) { - plan.add(Click.LEFT, cursorSlot); - } else { - translator.updateInventory(session, inventory); - InventoryUtils.updateCursor(session); - return; - } - } - if ((fromAction.getFromItem().equals(toAction.getToItem()) && !InventoryUtils.canStack(fromAction.getFromItem(), toAction.getFromItem())) - || fromAction.getToItem().getId() == 0) { //slot swap - plan.add(Click.LEFT, fromSlot); - plan.add(Click.LEFT, toSlot); - if (fromAction.getToItem().getId() != 0) { - plan.add(Click.LEFT, fromSlot); - } - } else if (InventoryUtils.canStack(fromAction.getFromItem(), toAction.getToItem())) { //partial item move - if (translator.getSlotType(fromSlot) == SlotType.FURNACE_OUTPUT) { - ClientWindowActionPacket shiftClickPacket = new ClientWindowActionPacket(inventory.getId(), - inventory.getTransactionId().getAndIncrement(), - fromSlot, InventoryUtils.REFRESH_ITEM, WindowAction.SHIFT_CLICK_ITEM, - ShiftClickItemParam.LEFT_CLICK); - session.sendDownstreamPacket(shiftClickPacket); - translator.updateInventory(session, inventory); - return; - } else if (translator.getSlotType(fromSlot) == SlotType.OUTPUT) { - session.setCraftSlot(cursorSlot); - plan.add(Click.LEFT, fromSlot); - int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount(); - for (int i = 0; i < difference; i++) { - plan.add(Click.RIGHT, toSlot); - } - //client will send additional packets later to finish transferring crafting output - //translator will know how to handle this using the craftSlot variable - } else { - plan.add(Click.LEFT, fromSlot); - int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount(); - for (int i = 0; i < difference; i++) { - plan.add(Click.RIGHT, toSlot); - } - plan.add(Click.LEFT, fromSlot); - } - } - if (cursorSlot != -1) { - plan.add(Click.LEFT, cursorSlot); - } - plan.execute(session, translator, inventory, refresh); - return; - } - - translator.updateInventory(session, inventory); - InventoryUtils.updateCursor(session); - } - - private static int findTempSlot(Inventory inventory, ItemStack item, List slotBlacklist, boolean emptyOnly) { - /*try and find a slot that can temporarily store the given item - only look in the main inventory and hotbar - only slots that are empty or contain a different type of item are valid*/ - int offset = inventory.getId() == 0 ? 1 : 0; //offhand is not a viable slot (some servers disable it) - List itemBlacklist = new ArrayList<>(slotBlacklist.size() + 1); - itemBlacklist.add(item); - for (int slot : slotBlacklist) { - ItemStack blacklistItem = inventory.getItem(slot); - if (blacklistItem != null) - itemBlacklist.add(blacklistItem); - } - for (int i = inventory.getSize() - (36 + offset); i < inventory.getSize() - offset; i++) { - ItemStack testItem = inventory.getItem(i); - boolean acceptable = true; - if (testItem != null) { - if (emptyOnly) { - continue; - } - for (ItemStack blacklistItem : itemBlacklist) { - if (InventoryUtils.canStack(testItem, blacklistItem)) { - acceptable = false; - break; - } - } - } - if (acceptable && !slotBlacklist.contains(i)) - return i; - } - //could not find a viable temp slot - return -1; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/Click.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/Click.java similarity index 66% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/Click.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/Click.java index 1fdfa3640..d27290bff 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/Click.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/Click.java @@ -23,16 +23,25 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.inventory.action; +package org.geysermc.connector.network.translators.inventory.click; import com.github.steveice10.mc.protocol.data.game.window.ClickItemParam; +import com.github.steveice10.mc.protocol.data.game.window.DropItemParam; +import com.github.steveice10.mc.protocol.data.game.window.WindowAction; import com.github.steveice10.mc.protocol.data.game.window.WindowActionParam; import lombok.AllArgsConstructor; @AllArgsConstructor -enum Click { - LEFT(ClickItemParam.LEFT_CLICK), - RIGHT(ClickItemParam.RIGHT_CLICK); +public enum Click { + LEFT(WindowAction.CLICK_ITEM, ClickItemParam.LEFT_CLICK), + RIGHT(WindowAction.CLICK_ITEM, ClickItemParam.RIGHT_CLICK), + DROP_ONE(WindowAction.DROP_ITEM, DropItemParam.DROP_FROM_SELECTED), + DROP_ALL(WindowAction.DROP_ITEM, DropItemParam.DROP_SELECTED_STACK), + LEFT_OUTSIDE(WindowAction.CLICK_ITEM, ClickItemParam.LEFT_CLICK), + RIGHT_OUTSIDE(WindowAction.CLICK_ITEM, ClickItemParam.RIGHT_CLICK); + public static final int OUTSIDE_SLOT = -999; + + public final WindowAction windowAction; public final WindowActionParam actionParam; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java new file mode 100644 index 000000000..f4cf35617 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.click; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.window.WindowAction; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientConfirmTransactionPacket; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import lombok.Value; +import org.geysermc.connector.inventory.GeyserItemStack; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.network.translators.inventory.SlotType; +import org.geysermc.connector.utils.InventoryUtils; + +import java.util.*; + +public class ClickPlan { + private final List plan = new ArrayList<>(); + private final Int2ObjectMap simulatedItems; + private GeyserItemStack simulatedCursor; + private boolean simulating; + + private final GeyserSession session; + private final InventoryTranslator translator; + private final Inventory inventory; + + public ClickPlan(GeyserSession session, InventoryTranslator translator, Inventory inventory) { + this.session = session; + this.translator = translator; + this.inventory = inventory; + + this.simulatedItems = new Int2ObjectOpenHashMap<>(inventory.getSize()); + this.simulatedCursor = session.getPlayerInventory().getCursor().copy(); + this.simulating = true; + } + + public void add(Click click, int slot) { + if (!simulating) + throw new UnsupportedOperationException("ClickPlan already executed"); + + if (click == Click.LEFT_OUTSIDE || click == Click.RIGHT_OUTSIDE) { + slot = Click.OUTSIDE_SLOT; + } + + ClickAction action = new ClickAction(click, slot); + plan.add(action); + simulateAction(action); + } + + public void execute(boolean refresh) { + simulating = false; + ListIterator planIter = plan.listIterator(); + while (planIter.hasNext()) { + ClickAction action = planIter.next(); + + if (action.slot != Click.OUTSIDE_SLOT && translator.getSlotType(action.slot) != SlotType.NORMAL) { + refresh = true; + } + + ItemStack clickedItemStack; + if (!planIter.hasNext() && refresh) { + clickedItemStack = InventoryUtils.REFRESH_ITEM; + } else if (action.click.windowAction == WindowAction.DROP_ITEM || action.slot == Click.OUTSIDE_SLOT) { + clickedItemStack = null; + } else { + clickedItemStack = inventory.getItem(action.slot).getItemStack(); + } + + short actionId = inventory.getNextTransactionId(); + ClientWindowActionPacket clickPacket = new ClientWindowActionPacket( + inventory.getId(), + actionId, + action.slot, + clickedItemStack, + action.click.windowAction, + action.click.actionParam + ); + + simulateAction(action); + + session.sendDownstreamPacket(clickPacket); + if (clickedItemStack == InventoryUtils.REFRESH_ITEM) { + session.sendDownstreamPacket(new ClientConfirmTransactionPacket(inventory.getId(), actionId, true)); + } + System.out.println(clickPacket); + } + } + + public GeyserItemStack getItem(int slot) { + return simulatedItems.computeIfAbsent(slot, k -> inventory.getItem(slot).copy()); + } + + public GeyserItemStack getCursor() { + return simulatedCursor; + } + + private void setItem(int slot, GeyserItemStack item) { + if (simulating) { + simulatedItems.put(slot, item); + } else { + inventory.setItem(slot, item); + } + } + + private void setCursor(GeyserItemStack item) { + if (simulating) { + simulatedCursor = item; + } else { + session.getPlayerInventory().setCursor(item); + } + } + + private void simulateAction(ClickAction action) { + GeyserItemStack cursor = simulating ? getCursor() : session.getPlayerInventory().getCursor(); + switch (action.click) { + case LEFT_OUTSIDE: + setCursor(GeyserItemStack.EMPTY); + return; + case RIGHT_OUTSIDE: + if (!cursor.isEmpty()) { + cursor.sub(1); + } + return; + } + + GeyserItemStack clicked = simulating ? getItem(action.slot) : inventory.getItem(action.slot); + if (translator.getSlotType(action.slot) == SlotType.OUTPUT) { + if (cursor.isEmpty() && !clicked.isEmpty()) { + setCursor(clicked.copy()); + } else if (InventoryUtils.canStack(cursor, clicked)) { + cursor.add(clicked.getAmount()); + } + } else { + switch (action.click) { + case LEFT: + if (!InventoryUtils.canStack(cursor, clicked)) { + setCursor(clicked); + setItem(action.slot, cursor); + } else { + setCursor(GeyserItemStack.EMPTY); + clicked.add(cursor.getAmount()); + } + break; + case RIGHT: + if (cursor.isEmpty() && !clicked.isEmpty()) { + int half = clicked.getAmount() / 2; //smaller half + setCursor(clicked.copy(clicked.getAmount() - half)); //larger half + clicked.setAmount(half); + } else if (!cursor.isEmpty() && clicked.isEmpty()) { + cursor.sub(1); + setItem(action.slot, cursor.copy(1)); + } else if (InventoryUtils.canStack(cursor, clicked)) { + cursor.sub(1); + clicked.add(1); + } + break; + case DROP_ONE: + if (!clicked.isEmpty()) { + clicked.sub(1); + } + break; + case DROP_ALL: + setItem(action.slot, GeyserItemStack.EMPTY); + break; + } + } + } + + public Set getAffectedSlots() { + Set affectedSlots = new HashSet<>(); + for (ClickAction action : plan) { + if (translator.getSlotType(action.slot) == SlotType.NORMAL && action.slot != Click.OUTSIDE_SLOT) { + affectedSlots.add(action.slot); + } + } + return affectedSlots; + } + + @Value + private static class ClickAction { + Click click; + int slot; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java index e45945bc3..58e6178b4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java @@ -49,7 +49,7 @@ public class ChestInventoryUpdater extends InventoryUpdater { ItemData[] bedrockItems = new ItemData[paddedSize]; for (int i = 0; i < bedrockItems.length; i++) { if (i < translator.size) { - bedrockItems[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(i)); + bedrockItems[i] = inventory.getItem(i).getItemData(session); } else { bedrockItems[i] = UNUSUABLE_SPACE_BLOCK; } @@ -69,7 +69,7 @@ public class ChestInventoryUpdater extends InventoryUpdater { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(inventory.getId()); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); - slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot))); + slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java index 51f33ac43..1abc65b5b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java @@ -40,7 +40,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater { ItemData[] bedrockItems = new ItemData[translator.size]; for (int i = 0; i < bedrockItems.length; i++) { - bedrockItems[translator.javaSlotToBedrock(i)] = ItemTranslator.translateToBedrock(session, inventory.getItem(i)); + bedrockItems[translator.javaSlotToBedrock(i)] = inventory.getItem(i).getItemData(session); } InventoryContentPacket contentPacket = new InventoryContentPacket(); @@ -57,7 +57,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(inventory.getId()); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); - slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot))); + slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java index 57601a9e0..655868c9a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java @@ -39,7 +39,7 @@ public abstract class InventoryUpdater { ItemData[] bedrockItems = new ItemData[36]; for (int i = 0; i < 36; i++) { final int offset = i < 9 ? 27 : -9; - bedrockItems[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(translator.size + i + offset)); + bedrockItems[i] = inventory.getItem(translator.size + i + offset).getItemData(session); } InventoryContentPacket contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(ContainerId.INVENTORY); @@ -52,7 +52,7 @@ public abstract class InventoryUpdater { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(ContainerId.INVENTORY); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); - slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot))); + slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/UIInventoryUpdater.java similarity index 89% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/UIInventoryUpdater.java index 26d889900..5100ddc99 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/UIInventoryUpdater.java @@ -32,9 +32,8 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.item.ItemTranslator; -public class CursorInventoryUpdater extends InventoryUpdater { +public class UIInventoryUpdater extends InventoryUpdater { - //TODO: Consider renaming this? Since the Protocol enum updated @Override public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { super.updateInventory(translator, session, inventory); @@ -46,7 +45,7 @@ public class CursorInventoryUpdater extends InventoryUpdater { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(bedrockSlot); - slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i))); + slotPacket.setItem(inventory.getItem(i).getItemData(session)); session.sendUpstreamPacket(slotPacket); } } @@ -59,7 +58,7 @@ public class CursorInventoryUpdater extends InventoryUpdater { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); - slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot))); + slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java index 9ffb4f0d9..559da5d97 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -34,6 +34,8 @@ import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import lombok.AllArgsConstructor; @@ -51,8 +53,10 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator recipeMap = new Int2ObjectOpenHashMap<>(); CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); craftingDataPacket.setCleanRecipes(true); + int netId = 1; for (Recipe recipe : packet.getRecipes()) { switch (recipe.getType()) { case CRAFTING_SHAPELESS: { @@ -63,7 +67,8 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator // Max health must be divisible by two in bedrock entity.getAttributes().put(AttributeType.HEALTH, AttributeType.HEALTH.getAttribute(maxHealth, (maxHealth % 2 == 1 ? maxHealth + 1 : maxHealth))); - session.getInventoryCache().setOpenInventory(null); + session.setOpenInventory(null); SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket(); playerGameTypePacket.setGamemode(packet.getGamemode().ordinal()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java index 9ed11a23d..05cc1a418 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java @@ -32,6 +32,7 @@ import com.github.steveice10.opennbt.tag.builtin.*; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; +import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; @@ -71,15 +72,9 @@ public class JavaPlayerActionAckTranslator extends PacketTranslator { + PlayerHotbarPacket hotbarPacket = new PlayerHotbarPacket(); + hotbarPacket.setContainerId(0); + hotbarPacket.setSelectedHotbarSlot(packet.getSlot()); + hotbarPacket.setSelectHotbarSlot(true); + session.sendUpstreamPacket(hotbarPacket); - session.getInventory().setHeldItemSlot(packet.getSlot()); + session.getPlayerInventory().setHeldItemSlot(packet.getSlot()); + }); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java index 93cfa08e4..68f1dda91 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java @@ -26,6 +26,7 @@ package org.geysermc.connector.network.translators.java.window; import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerCloseWindowPacket; +import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; @@ -36,7 +37,8 @@ public class JavaCloseWindowTranslator extends PacketTranslator { + InventoryUtils.closeInventory(session, packet.getWindowId()); + }); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java index e67877536..6d6c1686c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java @@ -27,6 +27,7 @@ package org.geysermc.connector.network.translators.java.window; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientConfirmTransactionPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerConfirmTransactionPacket; +import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; @@ -36,9 +37,11 @@ public class JavaConfirmTransactionTranslator extends PacketTranslator { + if (!packet.isAccepted()) { + ClientConfirmTransactionPacket confirmPacket = new ClientConfirmTransactionPacket(packet.getWindowId(), packet.getActionId(), true); + session.sendDownstreamPacket(confirmPacket); + } + }); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java index 820639b3d..e5ef4ecf5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java @@ -43,46 +43,47 @@ public class JavaOpenWindowTranslator extends PacketTranslator { + if (packet.getWindowId() == 0) { + return; + } + + InventoryTranslator newTranslator = InventoryTranslator.INVENTORY_TRANSLATORS.get(packet.getType()); + Inventory openInventory = session.getOpenInventory(); + //No translator exists for this window type. Close all windows and return. + if (newTranslator == null) { + if (openInventory != null) { + InventoryUtils.closeInventory(session, openInventory.getId()); + } + ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(packet.getWindowId()); + session.sendDownstreamPacket(closeWindowPacket); + return; + } + + String name = packet.getName(); + try { + JsonParser parser = new JsonParser(); + JsonObject jsonObject = parser.parse(packet.getName()).getAsJsonObject(); + if (jsonObject.has("text")) { + name = jsonObject.get("text").getAsString(); + } else if (jsonObject.has("translate")) { + name = jsonObject.get("translate").getAsString(); + } + } catch (Exception e) { + GeyserConnector.getInstance().getLogger().debug("JavaOpenWindowTranslator: " + e.toString()); + } + + name = LocaleUtils.getLocaleString(name, session.getClientData().getLanguageCode()); + + Inventory newInventory = newTranslator.createInventory(name, packet.getWindowId(), packet.getType(), session.getPlayerInventory()); if (openInventory != null) { - InventoryUtils.closeWindow(session, openInventory.getId()); - InventoryUtils.closeInventory(session, openInventory.getId()); + InventoryTranslator openTranslator = InventoryTranslator.INVENTORY_TRANSLATORS.get(openInventory.getWindowType()); + if (!openTranslator.getClass().equals(newTranslator.getClass())) { + InventoryUtils.closeInventory(session, openInventory.getId()); + } } - ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(packet.getWindowId()); - session.sendDownstreamPacket(closeWindowPacket); - return; - } - String name = packet.getName(); - try { - JsonParser parser = new JsonParser(); - JsonObject jsonObject = parser.parse(packet.getName()).getAsJsonObject(); - if (jsonObject.has("text")) { - name = jsonObject.get("text").getAsString(); - } else if (jsonObject.has("translate")) { - name = jsonObject.get("translate").getAsString(); - } - } catch (Exception e) { - GeyserConnector.getInstance().getLogger().debug("JavaOpenWindowTranslator: " + e.toString()); - } - - name = LocaleUtils.getLocaleString(name, session.getClientData().getLanguageCode()); - - Inventory newInventory = new Inventory(name, packet.getWindowId(), packet.getType(), newTranslator.size + 36); - session.getInventoryCache().cacheInventory(newInventory); - if (openInventory != null) { - InventoryTranslator openTranslator = InventoryTranslator.INVENTORY_TRANSLATORS.get(openInventory.getWindowType()); - if (!openTranslator.getClass().equals(newTranslator.getClass())) { - InventoryUtils.closeWindow(session, openInventory.getId()); - InventoryUtils.closeInventory(session, openInventory.getId()); - } - } - - InventoryUtils.openInventory(session, newInventory); + InventoryUtils.openInventory(session, newInventory); + }); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java index 19d7db217..22a0edcac 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java @@ -26,37 +26,53 @@ package org.geysermc.connector.network.translators.java.window; import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerSetSlotPacket; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.Translator; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.utils.InventoryUtils; -import java.util.Objects; - @Translator(packet = ServerSetSlotPacket.class) public class JavaSetSlotTranslator extends PacketTranslator { @Override public void translate(ServerSetSlotPacket packet, GeyserSession session) { - if (packet.getWindowId() == 255 && packet.getSlot() == -1) { //cursor - if (session.getCraftSlot() != 0) + session.addInventoryTask(() -> { + if (packet.getWindowId() == 255) { //cursor + GeyserItemStack newItem = GeyserItemStack.from(packet.getItem()); + GeyserItemStack oldItem = session.getPlayerInventory().getCursor(); + if (newItem.getItemData(session).equals(oldItem.getItemData(session))) { + newItem.setNetId(oldItem.getNetId()); + } else { + newItem.setNetId(session.getItemNetId().getAndIncrement()); + } + session.getPlayerInventory().setCursor(newItem); + InventoryUtils.updateCursor(session); + return; + } + + //TODO: support window id -2, should update player inventory + Inventory inventory = InventoryUtils.getInventory(session, packet.getWindowId()); + if (inventory == null) return; - session.getInventory().setCursor(packet.getItem()); - InventoryUtils.updateCursor(session); - return; - } - - Inventory inventory = session.getInventoryCache().getInventories().get(packet.getWindowId()); - if (inventory == null || (packet.getWindowId() != 0 && inventory.getWindowType() == null)) - return; - - InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()); - if (translator != null) { - inventory.setItem(packet.getSlot(), packet.getItem()); - translator.updateSlot(session, inventory, packet.getSlot()); - } + InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()); + if (translator != null) { + GeyserItemStack newItem = GeyserItemStack.from(packet.getItem()); + GeyserItemStack oldItem = inventory.getItem(packet.getSlot()); + if (newItem.getItemData(session).equals(oldItem.getItemData(session), false, false, false)) { + newItem.setNetId(oldItem.getNetId()); + System.out.println("OLD: " + newItem.getNetId()); + } else { + newItem.setNetId(session.getItemNetId().getAndIncrement()); + System.out.println("NEW: " + newItem.getNetId()); + } + inventory.setItem(packet.getSlot(), newItem); + translator.updateSlot(session, inventory, packet.getSlot()); + } + }); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java index 2cc392f53..26aab47b3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java @@ -26,32 +26,40 @@ package org.geysermc.connector.network.translators.java.window; import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerWindowItemsPacket; +import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; - -import java.util.Arrays; +import org.geysermc.connector.utils.InventoryUtils; @Translator(packet = ServerWindowItemsPacket.class) public class JavaWindowItemsTranslator extends PacketTranslator { @Override public void translate(ServerWindowItemsPacket packet, GeyserSession session) { - Inventory inventory = session.getInventoryCache().getInventories().get(packet.getWindowId()); - if (inventory == null || (packet.getWindowId() != 0 && inventory.getWindowType() == null)) - return; + session.addInventoryTask(() -> { + Inventory inventory = InventoryUtils.getInventory(session, packet.getWindowId()); + if (inventory == null) + return; - if (packet.getItems().length < inventory.getSize()) { - inventory.setItems(Arrays.copyOf(packet.getItems(), inventory.getSize())); - } else { - inventory.setItems(packet.getItems()); - } + for (int i = 0; i < packet.getItems().length; i++) { + GeyserItemStack newItem = GeyserItemStack.from(packet.getItems()[i]); + GeyserItemStack oldItem = inventory.getItem(i); + if (newItem.getItemData(session).equals(oldItem.getItemData(session), false, false, false)) { + newItem.setNetId(oldItem.getNetId()); + } else { + newItem.setNetId(session.getItemNetId().getAndIncrement()); + } + inventory.setItem(i, newItem); + } - InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()); - if (translator != null) { - translator.updateInventory(session, inventory); - } + InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()); + if (translator != null) { + translator.updateInventory(session, inventory); + } + }); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java index daebed1b6..97c4708ff 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java @@ -31,19 +31,22 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.utils.InventoryUtils; @Translator(packet = ServerWindowPropertyPacket.class) public class JavaWindowPropertyTranslator extends PacketTranslator { @Override public void translate(ServerWindowPropertyPacket packet, GeyserSession session) { - Inventory inventory = session.getInventoryCache().getInventories().get(packet.getWindowId()); - if (inventory == null || (packet.getWindowId() != 0 && inventory.getWindowType() == null)) - return; + session.addInventoryTask(() -> { + Inventory inventory = InventoryUtils.getInventory(session, packet.getWindowId()); + if (inventory == null) + return; - InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()); - if (translator != null) { - translator.updateProperty(session, inventory, packet.getRawProperty(), packet.getValue()); - } + InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()); + if (translator != null) { + translator.updateProperty(session, inventory, packet.getRawProperty(), packet.getValue()); + } + }); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java index d7961dd98..cb1aeaa71 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java @@ -111,7 +111,7 @@ public class JavaNotifyClientTranslator extends PacketTranslator tags = new ArrayList<>(); - for (VillagerTrade trade : packet.getTrades()) { + for (int i = 0; i < packet.getTrades().length; i++) { + VillagerTrade trade = packet.getTrades()[i]; NbtMapBuilder recipe = NbtMap.builder(); - recipe.putInt("maxUses", trade.getMaxUses()); + recipe.putInt("netId", i + 1); + recipe.putInt("maxUses", trade.isTradeDisabled() ? 0 : trade.getMaxUses()); recipe.putInt("traderExp", trade.getXp()); recipe.putFloat("priceMultiplierA", trade.getPriceMultiplier()); recipe.put("sell", getItemTag(session, trade.getOutput(), 0)); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/BlockSoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/BlockSoundInteractionHandler.java index f3dff0cc2..ab73e6028 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/BlockSoundInteractionHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/BlockSoundInteractionHandler.java @@ -27,6 +27,7 @@ package org.geysermc.connector.network.translators.sound; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.nukkitx.math.vector.Vector3f; +import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.item.ItemRegistry; @@ -60,12 +61,12 @@ public interface BlockSoundInteractionHandler extends SoundInteractionHandler 500) { - ContainerClosePacket closePacket = new ContainerClosePacket(); - closePacket.setId((byte) windowId); - session.sendUpstreamPacket(closePacket); + Inventory inventory = getInventory(session, windowId); + if (inventory != null) { + InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()); + translator.closeInventory(session, inventory); session.setLastWindowCloseTime(System.currentTimeMillis()); } - */ + session.setOpenInventory(null); + } + + public static Inventory getInventory(GeyserSession session, int windowId) { + if (windowId == 0) { + return session.getPlayerInventory(); + } else { + Inventory openInventory = session.getOpenInventory(); + if (openInventory != null && windowId == openInventory.getId()) { + return openInventory; + } + return null; + } } public static void updateCursor(GeyserSession session) { InventorySlotPacket cursorPacket = new InventorySlotPacket(); cursorPacket.setContainerId(ContainerId.UI); cursorPacket.setSlot(0); - cursorPacket.setItem(ItemTranslator.translateToBedrock(session, session.getInventory().getCursor())); + cursorPacket.setItem(session.getPlayerInventory().getCursor().getItemData(session)); session.sendUpstreamPacket(cursorPacket); } + public static boolean canStack(GeyserItemStack item1, GeyserItemStack item2) { + if (item1.isEmpty() || item2.isEmpty()) + return false; + return item1.getId() == item2.getId() && Objects.equals(item1.getNbt(), item2.getNbt()); + } + public static boolean canStack(ItemStack item1, ItemStack item2) { if (item1 == null || item2 == null) return false; @@ -170,19 +162,16 @@ public class InventoryUtils { */ public static void findOrCreatePickedBlock(GeyserSession session, String itemName) { // Get the inventory to choose a slot to pick - Inventory inventory = session.getInventoryCache().getOpenInventory(); - if (inventory == null) { - inventory = session.getInventory(); - } + PlayerInventory inventory = session.getPlayerInventory(); // Check hotbar for item for (int i = 36; i < 45; i++) { - if (inventory.getItem(i) == null) { + GeyserItemStack geyserItem = inventory.getItem(i); + if (geyserItem.isEmpty()) { continue; } - ItemEntry item = ItemRegistry.getItem(inventory.getItem(i)); // If this isn't the item we're looking for - if (!item.getJavaIdentifier().equals(itemName)) { + if (!geyserItem.getItemEntry().getJavaIdentifier().equals(itemName)) { continue; } @@ -193,12 +182,12 @@ public class InventoryUtils { // Check inventory for item for (int i = 9; i < 36; i++) { - if (inventory.getItem(i) == null) { + GeyserItemStack geyserItem = inventory.getItem(i); + if (geyserItem.isEmpty()) { continue; } - ItemEntry item = ItemRegistry.getItem(inventory.getItem(i)); // If this isn't the item we're looking for - if (!item.getJavaIdentifier().equals(itemName)) { + if (!geyserItem.getItemEntry().getJavaIdentifier().equals(itemName)) { continue; } @@ -209,10 +198,10 @@ public class InventoryUtils { // If we still have not found the item, and we're in creative, ask for the item from the server. if (session.getGameMode() == GameMode.CREATIVE) { - int slot = session.getInventory().getHeldItemSlot() + 36; - if (session.getInventory().getItemInHand() != null) { // Otherwise we should just use the current slot + int slot = inventory.getHeldItemSlot() + 36; + if (!inventory.getItemInHand().isEmpty()) { // Otherwise we should just use the current slot for (int i = 36; i < 45; i++) { - if (inventory.getItem(i) == null) { + if (inventory.getItem(i).isEmpty()) { slot = i; break; } @@ -221,7 +210,7 @@ public class InventoryUtils { ClientCreativeInventoryActionPacket actionPacket = new ClientCreativeInventoryActionPacket(slot, new ItemStack(ItemRegistry.getItemEntry(itemName).getJavaId())); - if ((slot - 36) != session.getInventory().getHeldItemSlot()) { + if ((slot - 36) != inventory.getHeldItemSlot()) { setHotbarItem(session, slot); } session.sendDownstreamPacket(actionPacket); diff --git a/connector/src/main/resources/languages b/connector/src/main/resources/languages index 5f2179226..93b2caed3 160000 --- a/connector/src/main/resources/languages +++ b/connector/src/main/resources/languages @@ -1 +1 @@ -Subproject commit 5f21792264a364e32425014e0be79db93593da1e +Subproject commit 93b2caed3c4ecd94b3c77a87f1b2304a7bf4f062 diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index 0fae8d3f0..ec8b68297 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 0fae8d3f0de6210a10435a36128db14cb7650ae6 +Subproject commit ec8b68297c4d62a9e4d640a8c7e77977062628ee From 3b3e72d5c3e37e3c0747d63f67ddafef48936733 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 15 Dec 2020 23:01:27 -0500 Subject: [PATCH 002/101] Initial crafting table support --- .../BedrockItemStackRequestTranslator.java | 1 - .../CraftingInventoryTranslator.java | 114 ++++++++++++++++++ .../inventory/InventoryTranslator.java | 4 +- .../holder/BlockInventoryHolder.java | 3 + 4 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java index 00ca83c73..8190bb556 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java @@ -32,7 +32,6 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; -import org.geysermc.connector.utils.InventoryUtils; @Translator(packet = ItemStackRequestPacket.class) public class BedrockItemStackRequestTranslator extends PacketTranslator { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java new file mode 100644 index 000000000..61dd9b040 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory; + +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; +import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder; +import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; +import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; + +public class CraftingInventoryTranslator extends BaseInventoryTranslator { + private final InventoryHolder holder; + private final InventoryUpdater updater; + + CraftingInventoryTranslator() { + super(10); + int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:crafting_table"); + this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), ContainerType.WORKBENCH); + this.updater = new ContainerInventoryUpdater(); + } + + @Override + public void prepareInventory(GeyserSession session, Inventory inventory) { + holder.prepareInventory(this, session, inventory); + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + holder.openInventory(this, session, inventory); + } + + @Override + public void closeInventory(GeyserSession session, Inventory inventory) { + holder.closeInventory(this, session, inventory); + } + + @Override + public void updateInventory(GeyserSession session, Inventory inventory) { + updater.updateInventory(this, session, inventory); + } + + @Override + public void updateSlot(GeyserSession session, Inventory inventory, int slot) { + updater.updateSlot(this, session, inventory, slot); + } + + @Override + public SlotType getSlotType(int javaSlot) { + if (javaSlot == 0) + return SlotType.OUTPUT; + return SlotType.NORMAL; + } + + + @Override + public int javaSlotToBedrock(int slot) { + if (slot < size) { + return slot == 0 ? 50 : slot + 31; + } + return super.javaSlotToBedrock(slot); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + if (slot >= 1 && slot <= 9) { + return new BedrockContainerSlot(ContainerSlotType.CRAFTING_INPUT, slot + 31); + } + if (slot == 0) { + return new BedrockContainerSlot(ContainerSlotType.CRAFTING_OUTPUT, 0); + } + return super.javaSlotToBedrockContainer(slot); + } + + @Override + public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { + if (slotInfoData.getContainer() == ContainerSlotType.CRAFTING_INPUT) { + // Java goes from 1 - 9, left to right then up to down + // Bedrock is the same, but it starts from 32. + return slotInfoData.getSlot() - 31; + } + if (slotInfoData.getContainer() == ContainerSlotType.CRAFTING_OUTPUT || slotInfoData.getContainer() == ContainerSlotType.CREATIVE_OUTPUT) { + return 0; + } + return super.bedrockSlotToJava(slotInfoData); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index 69670a3de..4fa54b389 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -58,9 +58,9 @@ public abstract class InventoryTranslator { put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36)); put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45)); put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54)); + put(WindowType.CRAFTING, new CraftingInventoryTranslator()); /*put(WindowType.BREWING_STAND, new BrewingInventoryTranslator()); put(WindowType.ANVIL, new AnvilInventoryTranslator()); - put(WindowType.CRAFTING, new CraftingInventoryTranslator()); put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());*/ put(WindowType.MERCHANT, new MerchantInventoryTranslator()); /*put(WindowType.SMITHING, new SmithingInventoryTranslator()); @@ -295,7 +295,7 @@ public abstract class InventoryTranslator { } craftState = CraftState.RECIPE_ID; recipeId = craftAction.getRecipeNetworkId(); - System.out.println(session.getCraftingRecipes().get(recipeId).toString()); + System.out.println(session.getCraftingRecipes().get(recipeId)); autoCraft = false; break; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java index 6afdb25dd..339c8a545 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java @@ -38,6 +38,9 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.world.block.BlockTranslator; +/** + * Manages the fake block we implement for each inventory. + */ @AllArgsConstructor public class BlockInventoryHolder extends InventoryHolder { private final int blockId; From 988e697a706ba1cbc5617a60b17c209d93395959 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 15 Dec 2020 23:33:17 -0500 Subject: [PATCH 003/101] Crafting table works --- .../CraftingInventoryTranslator.java | 4 +- .../inventory/InventoryTranslator.java | 31 +++++---- .../updater/CursorInventoryUpdater.java | 64 +++++++++++++++++++ 3 files changed, 85 insertions(+), 14 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java index 61dd9b040..a266074da 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java @@ -32,7 +32,7 @@ import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder; -import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; +import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; import org.geysermc.connector.network.translators.world.block.BlockTranslator; @@ -44,7 +44,7 @@ public class CraftingInventoryTranslator extends BaseInventoryTranslator { super(10); int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:crafting_table"); this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), ContainerType.WORKBENCH); - this.updater = new ContainerInventoryUpdater(); + this.updater = new CursorInventoryUpdater(); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index 4fa54b389..a9ac58cb4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -295,21 +295,28 @@ public abstract class InventoryTranslator { } craftState = CraftState.RECIPE_ID; recipeId = craftAction.getRecipeNetworkId(); - System.out.println(session.getCraftingRecipes().get(recipeId)); + //System.out.println(session.getCraftingRecipes().get(recipeId)); autoCraft = false; break; } - /*case CRAFT_RECIPE_AUTO: { - AutoCraftRecipeStackRequestActionData autoCraftAction = (AutoCraftRecipeStackRequestActionData) action; - if (craftState != CraftState.START) { - return rejectRequest(request); - } - craftState = CraftState.RECIPE_ID; - recipeId = autoCraftAction.getRecipeNetworkId(); - autoCraft = true; - //TODO: reject transaction if crafting grid is not clear - break; - }*/ +// case CRAFT_RECIPE_AUTO: { +// AutoCraftRecipeStackRequestActionData autoCraftAction = (AutoCraftRecipeStackRequestActionData) action; +// if (craftState != CraftState.START) { +// return rejectRequest(request); +// } +// craftState = CraftState.RECIPE_ID; +// recipeId = autoCraftAction.getRecipeNetworkId(); +// Recipe recipe = session.getCraftingRecipes().get(recipeId); +// System.out.println(recipe); +// if (recipe == null) { +// return rejectRequest(request); +// } +//// ClientPrepareCraftingGridPacket packet = new ClientPrepareCraftingGridPacket(session.getOpenInventory().getId(), recipe.getIdentifier(), true); +//// session.sendDownstreamPacket(packet); +// autoCraft = true; +// //TODO: reject transaction if crafting grid is not clear +// break; +// } case CRAFT_RESULTS_DEPRECATED: { CraftResultsDeprecatedStackRequestActionData deprecatedCraftAction = (CraftResultsDeprecatedStackRequestActionData) action; if (craftState != CraftState.RECIPE_ID) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java new file mode 100644 index 000000000..43306ea15 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.updater; + +import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; +import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; + +public class CursorInventoryUpdater extends InventoryUpdater { + + @Override + public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { + super.updateInventory(translator, session, inventory); + + for (int i = 0; i < translator.size; i++) { + final int bedrockSlot = translator.javaSlotToBedrock(i); + if (bedrockSlot == 50) + continue; + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(ContainerId.UI); + slotPacket.setSlot(bedrockSlot); + slotPacket.setItem(inventory.getItem(i).getItemData(session)); + session.sendUpstreamPacket(slotPacket); + } + } + + @Override + public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) { + if (super.updateSlot(translator, session, inventory, javaSlot)) + return true; + + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(ContainerId.UI); + slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); + slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); + session.sendUpstreamPacket(slotPacket); + return true; + } +} From 929b0ba80cc9d128c51826f1f459232f4853af36 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Wed, 16 Dec 2020 23:52:45 -0500 Subject: [PATCH 004/101] Refactors, and add furnace --- .../inventory/InventoryTranslator.java | 27 ++++--- .../AbstractBlockInventoryTranslator.java | 80 ++++++++++++++++++ .../BaseInventoryTranslator.java | 7 +- .../CraftingInventoryTranslator.java | 56 ++----------- .../MerchantInventoryTranslator.java | 4 +- .../PlayerInventoryTranslator.java | 5 +- .../chest}/ChestInventoryTranslator.java | 4 +- .../DoubleChestInventoryTranslator.java | 2 +- .../SingleChestInventoryTranslator.java | 2 +- .../AbstractFurnaceInventoryTranslator.java | 81 +++++++++++++++++++ .../BlastFurnaceInventoryTranslator.java | 44 ++++++++++ .../furnace/FurnaceInventoryTranslator.java | 44 ++++++++++ .../furnace/SmokerInventoryTranslator.java | 44 ++++++++++ .../world/JavaNotifyClientTranslator.java | 2 +- .../connector/utils/InventoryUtils.java | 4 +- 15 files changed, 336 insertions(+), 70 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/{ => translators}/BaseInventoryTranslator.java (90%) rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/{ => translators}/CraftingInventoryTranslator.java (57%) rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/{ => translators}/MerchantInventoryTranslator.java (96%) rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/{ => translators}/PlayerInventoryTranslator.java (96%) rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/{ => translators/chest}/ChestInventoryTranslator.java (90%) rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/{ => translators/chest}/DoubleChestInventoryTranslator.java (98%) rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/{ => translators/chest}/SingleChestInventoryTranslator.java (96%) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/AbstractFurnaceInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/BlastFurnaceInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/FurnaceInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/SmokerInventoryTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index a9ac58cb4..a0c1a3fa3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -40,6 +40,16 @@ import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.click.Click; import org.geysermc.connector.network.translators.inventory.click.ClickPlan; +import org.geysermc.connector.network.translators.inventory.translators.CraftingInventoryTranslator; +import org.geysermc.connector.network.translators.inventory.translators.MerchantInventoryTranslator; +import org.geysermc.connector.network.translators.inventory.translators.PlayerInventoryTranslator; +import org.geysermc.connector.network.translators.inventory.translators.chest.DoubleChestInventoryTranslator; +import org.geysermc.connector.network.translators.inventory.translators.chest.SingleChestInventoryTranslator; +import org.geysermc.connector.network.translators.inventory.translators.furnace.BlastFurnaceInventoryTranslator; +import org.geysermc.connector.network.translators.inventory.translators.furnace.FurnaceInventoryTranslator; +import org.geysermc.connector.network.translators.inventory.translators.furnace.SmokerInventoryTranslator; +import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; +import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.utils.InventoryUtils; @@ -63,19 +73,18 @@ public abstract class InventoryTranslator { put(WindowType.ANVIL, new AnvilInventoryTranslator()); put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());*/ put(WindowType.MERCHANT, new MerchantInventoryTranslator()); - /*put(WindowType.SMITHING, new SmithingInventoryTranslator()); + //put(WindowType.SMITHING, new SmithingInventoryTranslator()); //put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO - InventoryTranslator furnace = new FurnaceInventoryTranslator(); - put(WindowType.FURNACE, furnace); - put(WindowType.BLAST_FURNACE, furnace); - put(WindowType.SMOKER, furnace); + put(WindowType.FURNACE, new FurnaceInventoryTranslator()); + put(WindowType.BLAST_FURNACE, new BlastFurnaceInventoryTranslator()); + put(WindowType.SMOKER, new SmokerInventoryTranslator()); InventoryUpdater containerUpdater = new ContainerInventoryUpdater(); - put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, containerUpdater)); - put(WindowType.HOPPER, new BlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, containerUpdater)); - put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER, containerUpdater)); - //put(WindowType.BEACON, new BlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO*/ + //put(WindowType.GENERIC_3X3, new AbstractBlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, containerUpdater)); + //put(WindowType.HOPPER, new AbstractBlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, containerUpdater)); + //put(WindowType.SHULKER_BOX, new AbstractBlockInventoryTranslator(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER, containerUpdater)); + //put(WindowType.BEACON, new AbstractBlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO*/ } }; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java new file mode 100644 index 000000000..bff90c520 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators; + +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; +import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder; +import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; + +/** + * Provided as a base for any inventory that requires a block for opening it + */ +public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTranslator { + private final InventoryHolder holder; + private final InventoryUpdater updater; + + /** + * @param size the amount of slots that the inventory adds alongside the base inventory slots + * @param javaBlockIdentifier a Java block identifier that is used as a temporary block + * @param containerType the container type of this inventory + * @param updater updater + */ + public AbstractBlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater) { + super(size); + int javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); + this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), containerType); + this.updater = updater; + } + + @Override + public void prepareInventory(GeyserSession session, Inventory inventory) { + holder.prepareInventory(this, session, inventory); + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + holder.openInventory(this, session, inventory); + } + + @Override + public void closeInventory(GeyserSession session, Inventory inventory) { + holder.closeInventory(this, session, inventory); + } + + @Override + public void updateInventory(GeyserSession session, Inventory inventory) { + updater.updateInventory(this, session, inventory); + } + + @Override + public void updateSlot(GeyserSession session, Inventory inventory, int slot) { + updater.updateSlot(this, session, inventory, slot); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BaseInventoryTranslator.java similarity index 90% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BaseInventoryTranslator.java index 7d54667bd..48d2ac109 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BaseInventoryTranslator.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.inventory; +package org.geysermc.connector.network.translators.inventory.translators; import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; @@ -32,9 +32,12 @@ import org.geysermc.connector.inventory.Container; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.network.translators.inventory.SlotType; public abstract class BaseInventoryTranslator extends InventoryTranslator { - BaseInventoryTranslator(int size) { + public BaseInventoryTranslator(int size) { super(size); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CraftingInventoryTranslator.java similarity index 57% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CraftingInventoryTranslator.java index a266074da..2c420ada4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CraftingInventoryTranslator.java @@ -23,53 +23,18 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.inventory; +package org.geysermc.connector.network.translators.inventory.translators; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; -import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; -import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.SlotType; import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; -import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; -public class CraftingInventoryTranslator extends BaseInventoryTranslator { - private final InventoryHolder holder; - private final InventoryUpdater updater; - - CraftingInventoryTranslator() { - super(10); - int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:crafting_table"); - this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), ContainerType.WORKBENCH); - this.updater = new CursorInventoryUpdater(); - } - - @Override - public void prepareInventory(GeyserSession session, Inventory inventory) { - holder.prepareInventory(this, session, inventory); - } - - @Override - public void openInventory(GeyserSession session, Inventory inventory) { - holder.openInventory(this, session, inventory); - } - - @Override - public void closeInventory(GeyserSession session, Inventory inventory) { - holder.closeInventory(this, session, inventory); - } - - @Override - public void updateInventory(GeyserSession session, Inventory inventory) { - updater.updateInventory(this, session, inventory); - } - - @Override - public void updateSlot(GeyserSession session, Inventory inventory, int slot) { - updater.updateSlot(this, session, inventory, slot); +public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslator { + public CraftingInventoryTranslator() { + super(10, "minecraft:crafting_table", ContainerType.WORKBENCH, new CursorInventoryUpdater()); } @Override @@ -79,15 +44,6 @@ public class CraftingInventoryTranslator extends BaseInventoryTranslator { return SlotType.NORMAL; } - - @Override - public int javaSlotToBedrock(int slot) { - if (slot < size) { - return slot == 0 ? 50 : slot + 31; - } - return super.javaSlotToBedrock(slot); - } - @Override public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { if (slot >= 1 && slot <= 9) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/MerchantInventoryTranslator.java similarity index 96% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/MerchantInventoryTranslator.java index c4b2fc9a1..e798157d6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/MerchantInventoryTranslator.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.inventory; +package org.geysermc.connector.network.translators.inventory.translators; import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.nukkitx.math.vector.Vector3f; @@ -38,6 +38,8 @@ import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.inventory.MerchantContainer; import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.SlotType; import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java similarity index 96% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java index 5ace8fde0..286c3f63b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.inventory; +package org.geysermc.connector.network.translators.inventory.translators; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.window.WindowType; @@ -34,6 +34,9 @@ import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.network.translators.inventory.SlotType; import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.utils.InventoryUtils; import org.geysermc.connector.utils.LanguageUtils; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/ChestInventoryTranslator.java similarity index 90% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/ChestInventoryTranslator.java index df97563e5..1e81bb67d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/ChestInventoryTranslator.java @@ -23,11 +23,13 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.inventory; +package org.geysermc.connector.network.translators.inventory.translators.chest; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.translators.BaseInventoryTranslator; import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater; import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java similarity index 98% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java index 1183b21da..f807cfe08 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.inventory; +package org.geysermc.connector.network.translators.inventory.translators.chest; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.nukkitx.math.vector.Vector3i; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java similarity index 96% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java index 45860dcd3..43e060064 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.inventory; +package org.geysermc.connector.network.translators.inventory.translators.chest; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import org.geysermc.connector.inventory.Inventory; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/AbstractFurnaceInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/AbstractFurnaceInventoryTranslator.java new file mode 100644 index 000000000..b5f5b97f1 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/AbstractFurnaceInventoryTranslator.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators.furnace; + +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.SlotType; +import org.geysermc.connector.network.translators.inventory.translators.AbstractBlockInventoryTranslator; +import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; + +public abstract class AbstractFurnaceInventoryTranslator extends AbstractBlockInventoryTranslator { + AbstractFurnaceInventoryTranslator(String javaBlockIdentifier, ContainerType containerType) { + super(3, javaBlockIdentifier, containerType, new ContainerInventoryUpdater()); + } + + @Override + public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { + ContainerSetDataPacket dataPacket = new ContainerSetDataPacket(); + dataPacket.setWindowId((byte) inventory.getId()); + switch (key) { + case 0: + dataPacket.setProperty(ContainerSetDataPacket.FURNACE_LIT_TIME); + break; + case 1: + dataPacket.setProperty(ContainerSetDataPacket.FURNACE_LIT_DURATION); + break; + case 2: + dataPacket.setProperty(ContainerSetDataPacket.FURNACE_TICK_COUNT); + break; + default: + return; + } + dataPacket.setValue(value); + session.sendUpstreamPacket(dataPacket); + } + + @Override + public SlotType getSlotType(int javaSlot) { + if (javaSlot == 2) + return SlotType.FURNACE_OUTPUT; + return SlotType.NORMAL; + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + if (slot == 1) { + return new BedrockContainerSlot(ContainerSlotType.FURNACE_FUEL, javaSlotToBedrock(slot)); + } + if (slot == 2) { + return new BedrockContainerSlot(ContainerSlotType.FURNACE_OUTPUT, javaSlotToBedrock(slot)); + } + return super.javaSlotToBedrockContainer(slot); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/BlastFurnaceInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/BlastFurnaceInventoryTranslator.java new file mode 100644 index 000000000..b7834dde9 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/BlastFurnaceInventoryTranslator.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators.furnace; + +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; + +public class BlastFurnaceInventoryTranslator extends AbstractFurnaceInventoryTranslator { + public BlastFurnaceInventoryTranslator() { + super("minecraft:blast_furnace[facing=north,lit=false]", ContainerType.BLAST_FURNACE); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + if (slot == 0) { + return new BedrockContainerSlot(ContainerSlotType.BLAST_FURNACE_INGREDIENT, javaSlotToBedrock(slot)); + } + return super.javaSlotToBedrockContainer(slot); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/FurnaceInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/FurnaceInventoryTranslator.java new file mode 100644 index 000000000..f3d759412 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/FurnaceInventoryTranslator.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators.furnace; + +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; + +public class FurnaceInventoryTranslator extends AbstractFurnaceInventoryTranslator { + public FurnaceInventoryTranslator() { + super("minecraft:furnace[facing=north,lit=false]", ContainerType.FURNACE); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + if (slot == 0) { + return new BedrockContainerSlot(ContainerSlotType.FURNACE_INGREDIENT, javaSlotToBedrock(slot)); + } + return super.javaSlotToBedrockContainer(slot); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/SmokerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/SmokerInventoryTranslator.java new file mode 100644 index 000000000..75eb33d97 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/SmokerInventoryTranslator.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators.furnace; + +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; + +public class SmokerInventoryTranslator extends AbstractFurnaceInventoryTranslator { + public SmokerInventoryTranslator() { + super("minecraft:smoker[facing=north,lit=false]", ContainerType.SMOKER); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + if (slot == 0) { + return new BedrockContainerSlot(ContainerSlotType.SMOKER_INGREDIENT, javaSlotToBedrock(slot)); + } + return super.javaSlotToBedrockContainer(slot); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java index 44c1ad9b5..11f20f975 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java @@ -42,7 +42,7 @@ import org.geysermc.connector.entity.player.PlayerEntity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.inventory.PlayerInventoryTranslator; +import org.geysermc.connector.network.translators.inventory.translators.PlayerInventoryTranslator; import org.geysermc.connector.utils.LocaleUtils; @Translator(packet = ServerNotifyClientPacket.class) diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java index 876717a83..cbdfa9c56 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -43,11 +43,9 @@ import org.geysermc.connector.common.ChatColor; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.DoubleChestInventoryTranslator; +import org.geysermc.connector.network.translators.inventory.translators.chest.DoubleChestInventoryTranslator; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; -import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.ItemRegistry; -import org.geysermc.connector.network.translators.item.ItemTranslator; import java.util.Collections; import java.util.Objects; From 33a86485dca06cff48e3e162c66927851e9db3ae Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Thu, 17 Dec 2020 11:46:11 -0500 Subject: [PATCH 005/101] Implement dropper/dispenser, hopper, shulker --- .../BedrockItemStackRequestTranslator.java | 1 + .../inventory/InventoryTranslator.java | 14 ++---- .../CraftingInventoryTranslator.java | 2 +- .../GenericBlockInventoryTranslator.java | 48 +++++++++++++++++++ .../ShulkerInventoryTranslator.java | 45 +++++++++++++++++ .../AbstractFurnaceInventoryTranslator.java | 2 +- .../updater/ContainerInventoryUpdater.java | 3 +- .../updater/CursorInventoryUpdater.java | 1 + 8 files changed, 104 insertions(+), 12 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/ShulkerInventoryTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java index 8190bb556..1ab68106e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java @@ -38,6 +38,7 @@ public class BedrockItemStackRequestTranslator extends PacketTranslator Date: Thu, 17 Dec 2020 21:47:18 -0500 Subject: [PATCH 006/101] Brewing stand support; other attempts --- .../inventory/InventoryTranslator.java | 42 ++++++- .../BrewingInventoryTranslator.java | 113 ++++++++++++++++++ 2 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BrewingInventoryTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index fe22d397c..35bbb2cdd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -26,6 +26,7 @@ package org.geysermc.connector.network.translators.inventory; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; @@ -67,9 +68,9 @@ public abstract class InventoryTranslator { put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54)); put(WindowType.CRAFTING, new CraftingInventoryTranslator()); put(WindowType.SHULKER_BOX, new ShulkerInventoryTranslator()); - /*put(WindowType.BREWING_STAND, new BrewingInventoryTranslator()); - put(WindowType.ANVIL, new AnvilInventoryTranslator()); - put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());*/ + put(WindowType.BREWING_STAND, new BrewingInventoryTranslator()); + //put(WindowType.ANVIL, new AnvilInventoryTranslator()); + //put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator()); put(WindowType.MERCHANT, new MerchantInventoryTranslator()); //put(WindowType.SMITHING, new SmithingInventoryTranslator()); //put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO @@ -81,6 +82,11 @@ public abstract class InventoryTranslator { put(WindowType.GENERIC_3X3, new GenericBlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER)); put(WindowType.HOPPER, new GenericBlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER)); //put(WindowType.BEACON, new AbstractBlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO*/ + + //put(WindowType.CARTOGRAPHY + //put(WindowType.STONECUTTER + //put(WindowType.LOOM + //put(WindowType. } }; @@ -129,8 +135,12 @@ public abstract class InventoryTranslator { case TAKE: case PLACE: { TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action; - if (!(checkNetId(session, inventory, transferAction.getSource()) && checkNetId(session, inventory, transferAction.getDestination()))) + if (!(checkNetId(session, inventory, transferAction.getSource()) && checkNetId(session, inventory, transferAction.getDestination()))) { + session.getConnector().getLogger().error("DEBUG: About to reject request."); + session.getConnector().getLogger().error("Source: " + transferAction.getSource().toString() + " Result: " + checkNetId(session, inventory, transferAction.getSource())); + session.getConnector().getLogger().error("Destination: " + transferAction.getDestination().toString() + " Result: " + checkNetId(session, inventory, transferAction.getDestination())); return rejectRequest(request); + } if (isCursor(transferAction.getSource()) && isCursor(transferAction.getDestination())) { //??? return rejectRequest(request); @@ -273,6 +283,30 @@ public abstract class InventoryTranslator { CraftCreativeStackRequestActionData creativeAction = (CraftCreativeStackRequestActionData) action; System.out.println(creativeAction.getCreativeItemNetworkId()); } + case DESTROY: { + //TODO: Yeah this doesn't work yet. + + // Only called when a creative client wants to destroy an item... I think - Camotoy + DestroyStackRequestActionData destroyAction = (DestroyStackRequestActionData) action; + if (session.getGameMode() == GameMode.CREATIVE) { + if (isCursor(destroyAction.getSource())) { + session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY); + return acceptRequest(request, makeContainerEntries(session, inventory, Collections.emptySet())); + } else { + int javaSlot = bedrockSlotToJava(destroyAction.getSource()); + inventory.setItem(javaSlot, GeyserItemStack.EMPTY); + ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( + javaSlot, + new ItemStack(0) + ); + session.sendDownstreamPacket(creativeActionPacket); + Set affectedSlots = Collections.singleton(javaSlot); + return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); + } + } else { + return rejectRequest(request); + } + } default: return rejectRequest(request); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BrewingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BrewingInventoryTranslator.java new file mode 100644 index 000000000..6bc30a90f --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BrewingInventoryTranslator.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators; + +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; + +public class BrewingInventoryTranslator extends AbstractBlockInventoryTranslator { + public BrewingInventoryTranslator() { + super(5, "minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]", ContainerType.BREWING_STAND, ContainerInventoryUpdater.INSTANCE); + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + super.openInventory(session, inventory); + ContainerSetDataPacket dataPacket = new ContainerSetDataPacket(); + dataPacket.setWindowId((byte) inventory.getId()); + dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_FUEL_TOTAL); + dataPacket.setValue(20); + session.sendUpstreamPacket(dataPacket); + } + + @Override + public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { + ContainerSetDataPacket dataPacket = new ContainerSetDataPacket(); + dataPacket.setWindowId((byte) inventory.getId()); + switch (key) { + case 0: + dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_BREW_TIME); + break; + case 1: + dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_FUEL_AMOUNT); + break; + default: + return; + } + dataPacket.setValue(value); + session.sendUpstreamPacket(dataPacket); + } + + @Override + public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { + System.out.println("Brewing stand: " + slotInfoData); + if (slotInfoData.getContainer() == ContainerSlotType.BREWING_INPUT) { + // Ingredient + // TODO: This hasn't worked and then suddenly, it did. + return 3; + } + if (slotInfoData.getContainer() == ContainerSlotType.BREWING_RESULT) { + // Potions + return slotInfoData.getSlot() - 1; + } + return super.bedrockSlotToJava(slotInfoData); + } + + @Override + public int javaSlotToBedrock(int slot) { + switch (slot) { + case 0: + return 1; + case 1: + return 2; + case 2: + return 3; + case 3: + return 0; + } + return super.javaSlotToBedrock(slot); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + if (slot == 0 || slot == 1 || slot == 2) { + return new BedrockContainerSlot(ContainerSlotType.BREWING_RESULT, javaSlotToBedrock(slot)); + } + if (slot == 3) { + return new BedrockContainerSlot(ContainerSlotType.BREWING_INPUT, 0); + } + if (slot == 4) { + return new BedrockContainerSlot(ContainerSlotType.BREWING_FUEL, 4); + } + return super.javaSlotToBedrockContainer(slot); + } +} From f47cf32d903c2822da814f17c33e0e6c5f2de851 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Sat, 19 Dec 2020 19:19:44 -0500 Subject: [PATCH 007/101] Make my life tolerable --- .../translators/inventory/InventoryTranslator.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index 35bbb2cdd..52fb6e96c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -136,6 +136,10 @@ public abstract class InventoryTranslator { case PLACE: { TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action; if (!(checkNetId(session, inventory, transferAction.getSource()) && checkNetId(session, inventory, transferAction.getDestination()))) { + if (session.getGameMode().equals(GameMode.CREATIVE) && transferAction.getSource().getContainer() == ContainerSlotType.CRAFTING_INPUT && + transferAction.getSource().getSlot() >= 28 && transferAction.getSource().getSlot() <= 31) { + return rejectRequest(request, false); + } session.getConnector().getLogger().error("DEBUG: About to reject request."); session.getConnector().getLogger().error("Source: " + transferAction.getSource().toString() + " Result: " + checkNetId(session, inventory, transferAction.getSource())); session.getConnector().getLogger().error("Destination: " + transferAction.getDestination().toString() + " Result: " + checkNetId(session, inventory, transferAction.getDestination())); @@ -504,7 +508,14 @@ public abstract class InventoryTranslator { } public static ItemStackResponsePacket.Response rejectRequest(ItemStackRequestPacket.Request request) { - new Throwable("DEBUGGING: ItemStackRequest rejected").printStackTrace(); //TODO: temporary debugging + return rejectRequest(request, true); + } + + public static ItemStackResponsePacket.Response rejectRequest(ItemStackRequestPacket.Request request, boolean throwError) { + if (throwError) { + // Currently for debugging, but might be worth it to keep in the future if something goes terribly wrong. + new Throwable("DEBUGGING: ItemStackRequest rejected").printStackTrace(); + } return new ItemStackResponsePacket.Response(ItemStackResponsePacket.ResponseStatus.ERROR, request.getRequestId(), Collections.emptyList()); } From c6b4d163a1634d1c94b8c027555208d546160502 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 21 Dec 2020 21:09:14 -0500 Subject: [PATCH 008/101] Improve creative support --- .../inventory/InventoryTranslator.java | 130 ++++++++++++++---- .../inventory/click/ClickPlan.java | 12 +- .../java/window/JavaSetSlotTranslator.java | 2 +- 3 files changed, 117 insertions(+), 27 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index 52fb6e96c..f532beea2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -31,10 +31,13 @@ import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.*; import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; import lombok.AllArgsConstructor; import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.Inventory; @@ -92,6 +95,7 @@ public abstract class InventoryTranslator { public static final int PLAYER_INVENTORY_SIZE = 36; public static final int PLAYER_INVENTORY_OFFSET = 9; + private static final int MAX_ITEM_STACK_SIZE = 64; public final int size; public abstract void prepareInventory(GeyserSession session, Inventory inventory); @@ -114,6 +118,7 @@ public abstract class InventoryTranslator { if (firstAction.getType() == StackRequestActionType.CRAFT_RECIPE || firstAction.getType() == StackRequestActionType.CRAFT_RECIPE_AUTO) { responsePacket.getEntries().add(translateCraftingRequest(session, inventory, request)); } else if (firstAction.getType() == StackRequestActionType.CRAFT_CREATIVE) { + // This is also used for pulling items out of creative responsePacket.getEntries().add(translateCreativeRequest(session, inventory, request)); } else { responsePacket.getEntries().add(translateRequest(session, inventory, request)); @@ -129,6 +134,7 @@ public abstract class InventoryTranslator { public ItemStackResponsePacket.Response translateRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { System.out.println(request); ClickPlan plan = new ClickPlan(session, this, inventory); + IntSet affectedSlots = new IntOpenHashSet(); for (StackRequestActionData action : request.getActions()) { GeyserItemStack cursor = session.getPlayerInventory().getCursor(); switch (action.getType()) { @@ -148,6 +154,73 @@ public abstract class InventoryTranslator { if (isCursor(transferAction.getSource()) && isCursor(transferAction.getDestination())) { //??? return rejectRequest(request); + } else if (session.getGameMode().equals(GameMode.CREATIVE) && inventory instanceof PlayerInventory) { // TODO: does the Java server use the player inventory in all instances? + // Creative acts a little differently because it just edits slots + int sourceSlot = bedrockSlotToJava(transferAction.getSource()); + int destSlot = bedrockSlotToJava(transferAction.getDestination()); + boolean sourceIsCursor = isCursor(transferAction.getSource()); + boolean destIsCursor = isCursor(transferAction.getDestination()); + + GeyserItemStack sourceItem = sourceIsCursor ? session.getPlayerInventory().getCursor() : + inventory.getItem(sourceSlot); + GeyserItemStack newItem = sourceItem.copy(); + if (sourceIsCursor) { + GeyserItemStack destItem = inventory.getItem(destSlot); + if (destItem.getId() == sourceItem.getId()) { + // Combining items + int itemsLeftOver = destItem.getAmount() + transferAction.getCount(); + if (itemsLeftOver > MAX_ITEM_STACK_SIZE) { + // Items will remain in cursor because destination slot gets set to 64 + destItem.setAmount(MAX_ITEM_STACK_SIZE); + sourceItem.setAmount(itemsLeftOver - MAX_ITEM_STACK_SIZE); + } else { + // Cursor will be emptied + destItem.setAmount(itemsLeftOver); + session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY); + } + ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( + destSlot, + destItem.getItemStack() + ); + session.sendDownstreamPacket(creativeActionPacket); + affectedSlots.add(destSlot); + break; + } + } + // Update the item count with however much the client took + newItem.setAmount(transferAction.getCount()); + // Remove that amount from the existing item + sourceItem.setAmount(sourceItem.getAmount() - transferAction.getCount()); + if (sourceItem.isEmpty()) { + // Item is basically deleted + if (sourceIsCursor) { + session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY); + } else { + inventory.setItem(sourceSlot, GeyserItemStack.EMPTY); + } + } + if (destIsCursor) { + session.getPlayerInventory().setCursor(newItem); + } else { + inventory.setItem(destSlot, newItem); + } + GeyserItemStack itemToUpdate = destIsCursor ? sourceItem : newItem; + // The Java server doesn't care about what's in the mouse in creative mode, so we just need to track + // which inventory slot the client modified + ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( + destIsCursor ? sourceSlot : destSlot, + itemToUpdate.isEmpty() ? new ItemStack(0) : itemToUpdate.getItemStack() + ); + session.sendDownstreamPacket(creativeActionPacket); + System.out.println(creativeActionPacket); + + if (!sourceIsCursor) { // Cursor is always added for us as an affected slot + affectedSlots.add(sourceSlot); + } + if (!destIsCursor) { + affectedSlots.add(destSlot); + } + } else if (isCursor(transferAction.getSource())) { //releasing cursor int sourceAmount = cursor.getAmount(); int destSlot = bedrockSlotToJava(transferAction.getDestination()); @@ -286,37 +359,38 @@ public abstract class InventoryTranslator { case CRAFT_CREATIVE: { CraftCreativeStackRequestActionData creativeAction = (CraftCreativeStackRequestActionData) action; System.out.println(creativeAction.getCreativeItemNetworkId()); + break; } case DESTROY: { - //TODO: Yeah this doesn't work yet. - // Only called when a creative client wants to destroy an item... I think - Camotoy DestroyStackRequestActionData destroyAction = (DestroyStackRequestActionData) action; - if (session.getGameMode() == GameMode.CREATIVE) { - if (isCursor(destroyAction.getSource())) { - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY); - return acceptRequest(request, makeContainerEntries(session, inventory, Collections.emptySet())); - } else { - int javaSlot = bedrockSlotToJava(destroyAction.getSource()); - inventory.setItem(javaSlot, GeyserItemStack.EMPTY); - ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( - javaSlot, - new ItemStack(0) - ); - session.sendDownstreamPacket(creativeActionPacket); - Set affectedSlots = Collections.singleton(javaSlot); - return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); - } - } else { + if (!session.getGameMode().equals(GameMode.CREATIVE)) { + // If this happens, let's throw an error and figure out why. return rejectRequest(request); } + if (!isCursor(destroyAction.getSource())) { + int javaSlot = bedrockSlotToJava(destroyAction.getSource()); + ClientCreativeInventoryActionPacket destroyItemPacket = new ClientCreativeInventoryActionPacket( + javaSlot, + new ItemStack(0) + ); + session.sendDownstreamPacket(destroyItemPacket); + System.out.println(destroyItemPacket); + inventory.setItem(javaSlot, GeyserItemStack.EMPTY); + affectedSlots.add(javaSlot); + } else { + // Just sync up the item on our end, since the server doesn't care what's in our cursor + session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY); + } + break; } default: return rejectRequest(request); } } plan.execute(false); - return acceptRequest(request, makeContainerEntries(session, inventory, plan.getAffectedSlots())); + affectedSlots.addAll(plan.getAffectedSlots()); + return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); } public ItemStackResponsePacket.Response translateCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { @@ -480,18 +554,26 @@ public abstract class InventoryTranslator { if (transferAction.getSource().getContainer() != ContainerSlotType.CREATIVE_OUTPUT) { return rejectRequest(request); } + // Reference the creative items list we send to the client to know what it's asking of us + ItemData creativeItem = ItemRegistry.CREATIVE_ITEMS[creativeId - 1]; + // Get the correct count + creativeItem = ItemData.of(creativeItem.getId(), creativeItem.getDamage(), transferAction.getCount(), creativeItem.getTag()); + ItemStack javaCreativeItem = ItemTranslator.translateToJava(creativeItem); + if (isCursor(transferAction.getDestination())) { - session.getPlayerInventory().setCursor(GeyserItemStack.from(ItemTranslator.translateToJava(ItemRegistry.CREATIVE_ITEMS[creativeId]), session.getItemNetId().getAndIncrement())); //TODO - return acceptRequest(request, makeContainerEntries(session, inventory, Collections.emptySet())); + session.getPlayerInventory().setCursor(GeyserItemStack.from(javaCreativeItem, session.getItemNetId().getAndIncrement())); + return acceptRequest(request, Collections.singletonList( + new ItemStackResponsePacket.ContainerEntry(ContainerSlotType.CURSOR, + Collections.singletonList(makeItemEntry(session, 0, session.getPlayerInventory().getCursor()))))); } else { int javaSlot = bedrockSlotToJava(transferAction.getDestination()); - ItemStack javaItem = ItemTranslator.translateToJava(ItemRegistry.CREATIVE_ITEMS[creativeId - 1]); //TODO - inventory.setItem(javaSlot, GeyserItemStack.from(javaItem, session.getItemNetId().getAndIncrement())); + inventory.setItem(javaSlot, GeyserItemStack.from(javaCreativeItem, session.getItemNetId().getAndIncrement())); ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( javaSlot, - javaItem + javaCreativeItem ); session.sendDownstreamPacket(creativeActionPacket); + System.out.println(creativeActionPacket); Set affectedSlots = Collections.singleton(javaSlot); return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java index f4cf35617..4e5c28552 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java @@ -31,6 +31,8 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientConfi import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; import lombok.Value; import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.Inventory; @@ -193,8 +195,11 @@ public class ClickPlan { } } - public Set getAffectedSlots() { - Set affectedSlots = new HashSet<>(); + /** + * @return a new set of all affected slots. This isn't a constant variable; it's newly generated each time it is run. + */ + public IntSet getAffectedSlots() { + IntSet affectedSlots = new IntOpenHashSet(); for (ClickAction action : plan) { if (translator.getSlotType(action.slot) == SlotType.NORMAL && action.slot != Click.OUTSIDE_SLOT) { affectedSlots.add(action.slot); @@ -206,6 +211,9 @@ public class ClickPlan { @Value private static class ClickAction { Click click; + /** + * Java slot + */ int slot; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java index 22a0edcac..531242fca 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java @@ -26,7 +26,6 @@ package org.geysermc.connector.network.translators.java.window; import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerSetSlotPacket; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; @@ -40,6 +39,7 @@ public class JavaSetSlotTranslator extends PacketTranslator @Override public void translate(ServerSetSlotPacket packet, GeyserSession session) { + System.out.println(packet.toString()); session.addInventoryTask(() -> { if (packet.getWindowId() == 255) { //cursor GeyserItemStack newItem = GeyserItemStack.from(packet.getItem()); From 009905184eb468212403a73375ec78157472ad7d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 21 Dec 2020 22:44:01 -0500 Subject: [PATCH 009/101] Add grindstone and smithing table --- .../inventory/InventoryTranslator.java | 17 +++- .../EnchantingInventoryTranslator.java | 35 +++++++++ .../GrindstoneInventoryTranslator.java | 78 +++++++++++++++++++ .../SmithingInventoryTranslator.java | 78 +++++++++++++++++++ 4 files changed, 205 insertions(+), 3 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GrindstoneInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/SmithingInventoryTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index f532beea2..cf63811a2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -73,9 +73,9 @@ public abstract class InventoryTranslator { put(WindowType.SHULKER_BOX, new ShulkerInventoryTranslator()); put(WindowType.BREWING_STAND, new BrewingInventoryTranslator()); //put(WindowType.ANVIL, new AnvilInventoryTranslator()); - //put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator()); + put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator()); put(WindowType.MERCHANT, new MerchantInventoryTranslator()); - //put(WindowType.SMITHING, new SmithingInventoryTranslator()); + put(WindowType.SMITHING, new SmithingInventoryTranslator()); //put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO put(WindowType.FURNACE, new FurnaceInventoryTranslator()); @@ -154,7 +154,7 @@ public abstract class InventoryTranslator { if (isCursor(transferAction.getSource()) && isCursor(transferAction.getDestination())) { //??? return rejectRequest(request); - } else if (session.getGameMode().equals(GameMode.CREATIVE) && inventory instanceof PlayerInventory) { // TODO: does the Java server use the player inventory in all instances? + } else if (session.getGameMode().equals(GameMode.CREATIVE) && inventory instanceof PlayerInventory) { // TODO: does the Java server use this stuff all the time in creative? // Creative acts a little differently because it just edits slots int sourceSlot = bedrockSlotToJava(transferAction.getSource()); int destSlot = bedrockSlotToJava(transferAction.getDestination()); @@ -369,6 +369,7 @@ public abstract class InventoryTranslator { return rejectRequest(request); } if (!isCursor(destroyAction.getSource())) { + // Item exists; let's remove it from the inventory int javaSlot = bedrockSlotToJava(destroyAction.getSource()); ClientCreativeInventoryActionPacket destroyItemPacket = new ClientCreativeInventoryActionPacket( javaSlot, @@ -384,6 +385,16 @@ public abstract class InventoryTranslator { } break; } + // These three are called for the grindstone + case CONSUME: { + break; + } + case CRAFT_NON_IMPLEMENTED_DEPRECATED: { + break; + } + case CRAFT_RESULTS_DEPRECATED: { + break; + } default: return rejectRequest(request); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java new file mode 100644 index 000000000..a8b13be4c --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators; + +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; + +public class EnchantingInventoryTranslator extends AbstractBlockInventoryTranslator { + public EnchantingInventoryTranslator() { + super(2, "minecraft:enchanting_table", ContainerType.ENCHANTMENT, CursorInventoryUpdater.INSTANCE); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GrindstoneInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GrindstoneInventoryTranslator.java new file mode 100644 index 000000000..684b25e80 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GrindstoneInventoryTranslator.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators; + +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; + +public class GrindstoneInventoryTranslator extends AbstractBlockInventoryTranslator { + public GrindstoneInventoryTranslator() { + super(3, "minecraft:grindstone[face=floor,facing=north]", ContainerType.GRINDSTONE, CursorInventoryUpdater.INSTANCE); + } + + @Override + public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { + if (slotInfoData.getContainer() == ContainerSlotType.GRINDSTONE_INPUT) { + return 0; + } + if (slotInfoData.getContainer() == ContainerSlotType.GRINDSTONE_ADDITIONAL) { + return 1; + } + if (slotInfoData.getContainer() == ContainerSlotType.GRINDSTONE_RESULT || slotInfoData.getContainer() == ContainerSlotType.CREATIVE_OUTPUT) { + return 2; + } + return super.bedrockSlotToJava(slotInfoData); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + switch (slot) { + case 0: + return new BedrockContainerSlot(ContainerSlotType.GRINDSTONE_INPUT, 16); + case 1: + return new BedrockContainerSlot(ContainerSlotType.GRINDSTONE_ADDITIONAL, 17); + case 2: + return new BedrockContainerSlot(ContainerSlotType.GRINDSTONE_RESULT, 50); + } + return super.javaSlotToBedrockContainer(slot); + } + + @Override + public int javaSlotToBedrock(int slot) { + switch (slot) { + case 0: + return 16; + case 1: + return 17; + case 2: + return 50; + } + return super.javaSlotToBedrock(slot); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/SmithingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/SmithingInventoryTranslator.java new file mode 100644 index 000000000..fba8a8d6e --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/SmithingInventoryTranslator.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators; + +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; + +public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslator { + public SmithingInventoryTranslator() { + super(3, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, CursorInventoryUpdater.INSTANCE); + } + + @Override + public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { + if (slotInfoData.getContainer() == ContainerSlotType.SMITHING_TABLE_INPUT) { + return 0; + } + if (slotInfoData.getContainer() == ContainerSlotType.SMITHING_TABLE_MATERIAL) { + return 1; + } + if (slotInfoData.getContainer() == ContainerSlotType.SMITHING_TABLE_RESULT || slotInfoData.getContainer() == ContainerSlotType.CREATIVE_OUTPUT) { + return 2; + } + return super.bedrockSlotToJava(slotInfoData); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + switch (slot) { + case 0: + return new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_INPUT, 51); + case 1: + return new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_MATERIAL, 52); + case 2: + return new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_RESULT, 50); + } + return super.javaSlotToBedrockContainer(slot); + } + + @Override + public int javaSlotToBedrock(int slot) { + switch (slot) { + case 0: + return 51; + case 1: + return 52; + case 2: + return 50; + } + return super.javaSlotToBedrock(slot); + } +} From f4f804e1ca8045f7a25c92fc470d18bb996c4de5 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 23 Dec 2020 01:21:00 -0500 Subject: [PATCH 010/101] Enchantment table works; anvil is almost there --- .../connector/inventory/AnvilContainer.java | 34 ++++ .../inventory/EnchantingContainer.java | 53 +++++ .../inventory/EnchantmentInventory.java | 40 ---- .../connector/inventory/FurnaceInventory.java | 1 + .../inventory/GeyserEnchantOption.java | 78 ++++++++ .../bedrock/BedrockFilterTextTranslator.java | 47 +++++ .../inventory/InventoryTranslator.java | 88 ++++++-- .../translators/AnvilInventoryTranslator.java | 87 ++++++++ .../CraftingInventoryTranslator.java | 4 +- .../EnchantingInventoryTranslator.java | 188 +++++++++++++++++- .../GrindstoneInventoryTranslator.java | 4 +- .../MerchantInventoryTranslator.java | 3 +- .../SmithingInventoryTranslator.java | 4 +- .../updater/CursorInventoryUpdater.java | 65 ------ .../inventory/updater/UIInventoryUpdater.java | 2 +- .../window/JavaWindowPropertyTranslator.java | 1 + 16 files changed, 566 insertions(+), 133 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/inventory/AnvilContainer.java create mode 100644 connector/src/main/java/org/geysermc/connector/inventory/EnchantingContainer.java delete mode 100644 connector/src/main/java/org/geysermc/connector/inventory/EnchantmentInventory.java create mode 100644 connector/src/main/java/org/geysermc/connector/inventory/GeyserEnchantOption.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java diff --git a/connector/src/main/java/org/geysermc/connector/inventory/AnvilContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/AnvilContainer.java new file mode 100644 index 000000000..d940ac75b --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/inventory/AnvilContainer.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019-2020 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.inventory; + +import com.github.steveice10.mc.protocol.data.game.window.WindowType; + +public class AnvilContainer extends Container { + public AnvilContainer(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) { + super(title, id, windowType, size, playerInventory); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/inventory/EnchantingContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/EnchantingContainer.java new file mode 100644 index 000000000..c8b2bef13 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/inventory/EnchantingContainer.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019-2020 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.inventory; + +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.nukkitx.protocol.bedrock.data.inventory.EnchantOptionData; +import lombok.Getter; + +public class EnchantingContainer extends Container { + /** + * A cache of what Bedrock sees + */ + @Getter + private final EnchantOptionData[] enchantOptions; + /** + * A mutable cache of what the server sends us + */ + @Getter + private final GeyserEnchantOption[] geyserEnchantOptions; + + public EnchantingContainer(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) { + super(title, id, windowType, size, playerInventory); + + enchantOptions = new EnchantOptionData[3]; + geyserEnchantOptions = new GeyserEnchantOption[3]; + for (int i = 0; i < geyserEnchantOptions.length; i++) { + geyserEnchantOptions[i] = new GeyserEnchantOption(i); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/inventory/EnchantmentInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/EnchantmentInventory.java deleted file mode 100644 index 65debc486..000000000 --- a/connector/src/main/java/org/geysermc/connector/inventory/EnchantmentInventory.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2019-2020 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.inventory; - -import com.github.steveice10.mc.protocol.data.game.window.WindowType; -import com.nukkitx.protocol.bedrock.data.inventory.EnchantOptionData; -import lombok.Getter; - -@Getter -public class EnchantmentInventory extends Inventory { - private EnchantOptionData[] enchantOptions; - - public EnchantmentInventory(String title, int id, WindowType windowType, int size) { - super(title, id, windowType, size); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java index 4dc098d89..0af76244d 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java @@ -30,6 +30,7 @@ import com.github.steveice10.mc.protocol.data.game.window.WindowType; import lombok.Getter; import lombok.Setter; +//TODO: Figure out what this is and if we should remove it @Getter public class FurnaceInventory extends Inventory { @Setter diff --git a/connector/src/main/java/org/geysermc/connector/inventory/GeyserEnchantOption.java b/connector/src/main/java/org/geysermc/connector/inventory/GeyserEnchantOption.java new file mode 100644 index 000000000..ea58372e2 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/inventory/GeyserEnchantOption.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2019-2020 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.inventory; + +import com.nukkitx.protocol.bedrock.data.inventory.EnchantData; +import com.nukkitx.protocol.bedrock.data.inventory.EnchantOptionData; +import lombok.Getter; +import lombok.Setter; +import org.geysermc.connector.network.session.GeyserSession; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * A mutable "wrapper" around {@link EnchantOptionData} + */ +@Setter +public class GeyserEnchantOption { + private static final List EMPTY = Collections.emptyList(); + /** + * This: https://cdn.discordapp.com/attachments/613168850925649981/791030657169227816/unknown.png + * is controlled by the server. + * So, of course, we have to throw in some easter eggs. ;) + */ + private static final List ENCHANT_NAMES = Arrays.asList("tougher armor", "lukeeey", "fall better", + "explode less", "camo toy", "breathe better", "rtm five one six", "armor stab", "water walk", "you are elsa", + "tim two zero three", "fast walk nether", "oof ouch owie", "enemy on fire", "spider sad", "aj ferguson", "redned", + "more items thx", "long sword reach", "fast tool", "give me block", "less breaky break", "cube craft", + "strong arrow", "fist arrow", "spicy arrow", "many many arrows", "geyser", "come here fish", "i like this", + "stabby stab", "supreme mortal", "avatar i guess", "more arrows", "fly finder seventeen", "in and out", + "xp heals tools", "dragon proxy waz here"); + + @Getter + private final int javaIndex; + + private int xpCost = 0; + private int javaEnchantIndex = -1; + private int bedrockEnchantIndex = -1; + private int enchantLevel = -1; + + public GeyserEnchantOption(int javaIndex) { + this.javaIndex = javaIndex; + } + + public EnchantOptionData build(GeyserSession session) { + if (enchantLevel == -1) { + // Should not be sent to the client, as it is supposed to be empty + return null; + } + return new EnchantOptionData(xpCost, javaIndex + 16, EMPTY, + Collections.singletonList(new EnchantData(bedrockEnchantIndex, enchantLevel)), EMPTY, + javaEnchantIndex == -1 ? "unknown" : ENCHANT_NAMES.get(javaEnchantIndex), session.getItemNetId().incrementAndGet()); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java new file mode 100644 index 000000000..cf06acf58 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019-2020 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.translators.bedrock; + +import com.nukkitx.protocol.bedrock.packet.FilterTextPacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.Translator; + +/** + * Used to send strings to the client and filter out unwanted words. + * Java doesn't care, so we don't care, and we approve all strings. + */ +@Translator(packet = FilterTextPacket.class) +public class BedrockFilterTextTranslator extends PacketTranslator { + + @Override + public void translate(FilterTextPacket packet, GeyserSession session) { + // TODO: Bedrock doesn't send this. Why? + System.out.println(packet.toString()); + packet.setFromServer(true); + session.sendUpstreamPacket(packet); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index cf63811a2..719a20922 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -62,29 +62,36 @@ public abstract class InventoryTranslator { public static final Map INVENTORY_TRANSLATORS = new HashMap() { { + /* Player Inventory */ put(null, new PlayerInventoryTranslator()); //player inventory + + /* Chest UIs */ put(WindowType.GENERIC_9X1, new SingleChestInventoryTranslator(9)); put(WindowType.GENERIC_9X2, new SingleChestInventoryTranslator(18)); put(WindowType.GENERIC_9X3, new SingleChestInventoryTranslator(27)); put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36)); put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45)); put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54)); - put(WindowType.CRAFTING, new CraftingInventoryTranslator()); - put(WindowType.SHULKER_BOX, new ShulkerInventoryTranslator()); - put(WindowType.BREWING_STAND, new BrewingInventoryTranslator()); - //put(WindowType.ANVIL, new AnvilInventoryTranslator()); - put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator()); - put(WindowType.MERCHANT, new MerchantInventoryTranslator()); - put(WindowType.SMITHING, new SmithingInventoryTranslator()); - //put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO + /* Furnaces */ put(WindowType.FURNACE, new FurnaceInventoryTranslator()); put(WindowType.BLAST_FURNACE, new BlastFurnaceInventoryTranslator()); put(WindowType.SMOKER, new SmokerInventoryTranslator()); + /* Specific Inventories */ + put(WindowType.ANVIL, new AnvilInventoryTranslator()); + put(WindowType.BREWING_STAND, new BrewingInventoryTranslator()); + put(WindowType.CRAFTING, new CraftingInventoryTranslator()); + put(WindowType.ENCHANTMENT, new EnchantingInventoryTranslator()); + put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator()); + put(WindowType.MERCHANT, new MerchantInventoryTranslator()); + put(WindowType.SHULKER_BOX, new ShulkerInventoryTranslator()); + put(WindowType.SMITHING, new SmithingInventoryTranslator()); + + /* Generics */ put(WindowType.GENERIC_3X3, new GenericBlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER)); put(WindowType.HOPPER, new GenericBlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER)); - //put(WindowType.BEACON, new AbstractBlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO*/ + //put(WindowType.BEACON, new AbstractBlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO //put(WindowType.CARTOGRAPHY //put(WindowType.STONECUTTER @@ -110,12 +117,30 @@ public abstract class InventoryTranslator { public abstract SlotType getSlotType(int javaSlot); public abstract Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory); + /** + * Should be overrided if this request matches a certain criteria and shouldn't be treated normally. + * E.G. anvil renaming or enchanting + */ + public boolean shouldHandleRequestFirst(StackRequestActionData action) { + return false; + } + + /** + * If {@link #shouldHandleRequestFirst(StackRequestActionData)} returns true, this will be called + */ + public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + return null; + } + public void translateRequests(GeyserSession session, Inventory inventory, List requests) { ItemStackResponsePacket responsePacket = new ItemStackResponsePacket(); for (ItemStackRequestPacket.Request request : requests) { if (request.getActions().length > 0) { StackRequestActionData firstAction = request.getActions()[0]; - if (firstAction.getType() == StackRequestActionType.CRAFT_RECIPE || firstAction.getType() == StackRequestActionType.CRAFT_RECIPE_AUTO) { + if (shouldHandleRequestFirst(firstAction)) { + // Some special request that shouldn't be processed normally + responsePacket.getEntries().add(translateSpecialRequest(session, inventory, request)); + } else if (firstAction.getType() == StackRequestActionType.CRAFT_RECIPE || firstAction.getType() == StackRequestActionType.CRAFT_RECIPE_AUTO) { responsePacket.getEntries().add(translateCraftingRequest(session, inventory, request)); } else if (firstAction.getType() == StackRequestActionType.CRAFT_CREATIVE) { // This is also used for pulling items out of creative @@ -335,12 +360,30 @@ public abstract class InventoryTranslator { return rejectRequest(request); if (isCursor(dropAction.getSource())) { //clicking outside of window - int sourceAmount = plan.getCursor().getAmount(); - if (dropAction.getCount() == sourceAmount) { //drop all - plan.add(Click.LEFT_OUTSIDE, Click.OUTSIDE_SLOT); - } else { //drop some - for (int i = 0; i < dropAction.getCount(); i++) { - plan.add(Click.RIGHT_OUTSIDE, Click.OUTSIDE_SLOT); //drop one until goal is met + if (session.getGameMode() == GameMode.CREATIVE && inventory instanceof PlayerInventory) { + GeyserItemStack cursorItem = session.getPlayerInventory().getCursor(); + GeyserItemStack droppingItem = cursorItem.copy(); + // Subtract the cursor item by however much is being dropped + cursorItem.setAmount(cursorItem.getAmount() - dropAction.getCount()); + if (cursorItem.isEmpty()) { + // Cursor item no longer exists + session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY); + } + droppingItem.setAmount(dropAction.getCount()); + ClientCreativeInventoryActionPacket packet = new ClientCreativeInventoryActionPacket( + Click.OUTSIDE_SLOT, + droppingItem.getItemStack() + ); + System.out.println(packet.toString()); + session.sendDownstreamPacket(packet); + } else { + int sourceAmount = plan.getCursor().getAmount(); + if (dropAction.getCount() == sourceAmount) { //drop all + plan.add(Click.LEFT_OUTSIDE, Click.OUTSIDE_SLOT); + } else { //drop some + for (int i = 0; i < dropAction.getCount(); i++) { + plan.add(Click.RIGHT_OUTSIDE, Click.OUTSIDE_SLOT); //drop one until goal is met + } } } } else { //dropping from inventory @@ -395,6 +438,10 @@ public abstract class InventoryTranslator { case CRAFT_RESULTS_DEPRECATED: { break; } + case CRAFT_RECIPE_OPTIONAL: { + // Anvils and cartography tables will handle this + break; + } default: return rejectRequest(request); } @@ -578,7 +625,14 @@ public abstract class InventoryTranslator { Collections.singletonList(makeItemEntry(session, 0, session.getPlayerInventory().getCursor()))))); } else { int javaSlot = bedrockSlotToJava(transferAction.getDestination()); - inventory.setItem(javaSlot, GeyserItemStack.from(javaCreativeItem, session.getItemNetId().getAndIncrement())); + GeyserItemStack existingItem = inventory.getItem(javaSlot); + if (existingItem.getId() == javaCreativeItem.getId()) { + // Adding more to an existing item + existingItem.setAmount(existingItem.getAmount() + transferAction.getCount()); + javaCreativeItem = existingItem.getItemStack(); + } else { + inventory.setItem(javaSlot, GeyserItemStack.from(javaCreativeItem, session.getItemNetId().getAndIncrement())); + } ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( javaSlot, javaCreativeItem diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java new file mode 100644 index 000000000..27de329c6 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators; + +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +import org.geysermc.connector.inventory.AnvilContainer; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.PlayerInventory; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; + +public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { + public AnvilInventoryTranslator() { + super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL, UIInventoryUpdater.INSTANCE); + } + + @Override + public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { + if (slotInfoData.getContainer() == ContainerSlotType.ANVIL_INPUT) { + return 0; + } + if (slotInfoData.getContainer() == ContainerSlotType.ANVIL_MATERIAL) { + return 1; + } + if (slotInfoData.getContainer() == ContainerSlotType.ANVIL_RESULT || slotInfoData.getContainer() == ContainerSlotType.CREATIVE_OUTPUT) { + return 2; + } + return super.bedrockSlotToJava(slotInfoData); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + switch (slot) { + case 0: + return new BedrockContainerSlot(ContainerSlotType.ANVIL_INPUT, 1); + case 1: + return new BedrockContainerSlot(ContainerSlotType.ANVIL_MATERIAL, 2); + case 2: + return new BedrockContainerSlot(ContainerSlotType.ANVIL_RESULT, 50); + } + return super.javaSlotToBedrockContainer(slot); + } + + @Override + public int javaSlotToBedrock(int slot) { + switch (slot) { + case 0: + return 1; + case 1: + return 2; + case 2: + return 50; + } + return super.javaSlotToBedrock(slot); + } + + @Override + public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { + return new AnvilContainer(name, windowId, windowType, this.size, playerInventory); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CraftingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CraftingInventoryTranslator.java index 99ed2ecec..77eeee17b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CraftingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CraftingInventoryTranslator.java @@ -30,11 +30,11 @@ import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; import org.geysermc.connector.network.translators.inventory.SlotType; -import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; +import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslator { public CraftingInventoryTranslator() { - super(10, "minecraft:crafting_table", ContainerType.WORKBENCH, CursorInventoryUpdater.INSTANCE); + super(10, "minecraft:crafting_table", ContainerType.WORKBENCH, UIInventoryUpdater.INSTANCE); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java index a8b13be4c..cfa024191 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java @@ -25,11 +25,195 @@ package org.geysermc.connector.network.translators.inventory.translators; +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientClickWindowButtonPacket; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; +import com.nukkitx.protocol.bedrock.data.inventory.EnchantOptionData; +import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +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.ItemStackRequestPacket; +import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; +import com.nukkitx.protocol.bedrock.packet.PlayerEnchantOptionsPacket; +import org.geysermc.connector.inventory.EnchantingContainer; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.PlayerInventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; +import org.geysermc.connector.network.translators.item.Enchantment; + +import java.util.Arrays; +import java.util.Collections; public class EnchantingInventoryTranslator extends AbstractBlockInventoryTranslator { public EnchantingInventoryTranslator() { - super(2, "minecraft:enchanting_table", ContainerType.ENCHANTMENT, CursorInventoryUpdater.INSTANCE); + super(2, "minecraft:enchanting_table", ContainerType.ENCHANTMENT, UIInventoryUpdater.INSTANCE); + } + + @Override + public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { + int slotToUpdate; + EnchantingContainer enchantingInventory = (EnchantingContainer) inventory; + boolean shouldUpdate = false; + switch (key) { + case 0: + case 1: + case 2: + // Experience required + slotToUpdate = key; + enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].setXpCost(value); + break; + case 4: + case 5: + case 6: + // Enchantment type + slotToUpdate = key - 4; + int index = value; + if (index != -1) { + Enchantment enchantment = Enchantment.getByJavaIdentifier("minecraft:" + JavaEnchantment.values()[index].name().toLowerCase()); + if (enchantment != null) { + // Convert the Java enchantment index to Bedrock's + index = enchantment.ordinal(); + } else { + index = -1; + } + } + enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].setJavaEnchantIndex(value); + enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].setBedrockEnchantIndex(index); + break; + case 7: + case 8: + case 9: + // Enchantment level + slotToUpdate = key - 7; + enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].setEnchantLevel(value); + shouldUpdate = true; // Java sends each property as its own packet, so let's only update after all properties have been sent + break; + default: + return; + } + if (shouldUpdate) { + enchantingInventory.getEnchantOptions()[slotToUpdate] = enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].build(session); + PlayerEnchantOptionsPacket packet = new PlayerEnchantOptionsPacket(); + packet.getOptions().addAll(Arrays.asList(enchantingInventory.getEnchantOptions())); + System.out.println(packet); + session.sendUpstreamPacket(packet); + } + } + + @Override + public boolean shouldHandleRequestFirst(StackRequestActionData action) { + return action.getType() == StackRequestActionType.CRAFT_RECIPE; + } + + @Override + public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + // Client has requested an item to be enchanted + CraftRecipeStackRequestActionData craftRecipeData = (CraftRecipeStackRequestActionData) request.getActions()[0]; + EnchantingContainer enchantingInventory = (EnchantingContainer) inventory; + int javaSlot = -1; + for (int i = 0; i < enchantingInventory.getEnchantOptions().length; i++) { + EnchantOptionData enchantData = enchantingInventory.getEnchantOptions()[i]; + if (enchantData != null) { + if (craftRecipeData.getRecipeNetworkId() == enchantData.getEnchantNetId()) { + // Enchant net ID is how we differentiate between what item Bedrock wants + javaSlot = enchantingInventory.getGeyserEnchantOptions()[i].getJavaIndex(); + break; + } + } + } + if (javaSlot == -1) { + // Slot should be determined as 0, 1, or 2 + throw new RuntimeException("Cannot find enchant slot for item!"); + } + ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), javaSlot); + System.out.println(packet); + session.sendDownstreamPacket(packet); + return acceptRequest(request, makeContainerEntries(session, inventory, Collections.emptySet())); + } + + @Override + public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { + if (slotInfoData.getContainer() == ContainerSlotType.ENCHANTING_INPUT) { + return 0; + } + if (slotInfoData.getContainer() == ContainerSlotType.ENCHANTING_LAPIS) { + return 1; + } + return super.bedrockSlotToJava(slotInfoData); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + if (slot == 0) { + return new BedrockContainerSlot(ContainerSlotType.ENCHANTING_INPUT, 14); + } + if (slot == 1) { + return new BedrockContainerSlot(ContainerSlotType.ENCHANTING_LAPIS, 15); + } + return super.javaSlotToBedrockContainer(slot); + } + + @Override + public int javaSlotToBedrock(int slot) { + if (slot == 0) { + return 14; + } + if (slot == 1) { + return 15; + } + return super.javaSlotToBedrock(slot); + } + + @Override + public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { + return new EnchantingContainer(name, windowId, windowType, this.size, playerInventory); + } + + /** + * Enchantments classified by their Java index + */ + public enum JavaEnchantment { + PROTECTION, + FIRE_PROTECTION, + FEATHER_FALLING, + BLAST_PROTECTION, + PROJECTILE_PROTECTION, + RESPIRATION, + AQUA_AFFINITY, + THORNS, + DEPTH_STRIDER, + FROST_WALKER, + BINDING_CURSE, + SOUL_SPEED, + SHARPNESS, + SMITE, + BANE_OF_ARTHROPODS, + KNOCKBACK, + FIRE_ASPECT, + LOOTING, + SWEEPING, + EFFICIENCY, + SILK_TOUCH, + UNBREAKING, + FORTUNE, + POWER, + PUNCH, + FLAME, + INFINITY, + LUCK_OF_THE_SEA, + LURE, + LOYALTY, + IMPALING, + RIPTIDE, + CHANNELING, + MULTISHOT, + QUICK_CHARGE, + PIERCING, + MENDING, + VANISHING_CURSE } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GrindstoneInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GrindstoneInventoryTranslator.java index 684b25e80..14e3cf1eb 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GrindstoneInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GrindstoneInventoryTranslator.java @@ -29,11 +29,11 @@ import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; -import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; +import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; public class GrindstoneInventoryTranslator extends AbstractBlockInventoryTranslator { public GrindstoneInventoryTranslator() { - super(3, "minecraft:grindstone[face=floor,facing=north]", ContainerType.GRINDSTONE, CursorInventoryUpdater.INSTANCE); + super(3, "minecraft:grindstone[face=floor,facing=north]", ContainerType.GRINDSTONE, UIInventoryUpdater.INSTANCE); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/MerchantInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/MerchantInventoryTranslator.java index e798157d6..33a4e8240 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/MerchantInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/MerchantInventoryTranslator.java @@ -44,12 +44,11 @@ import org.geysermc.connector.network.translators.inventory.updater.InventoryUpd import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; public class MerchantInventoryTranslator extends BaseInventoryTranslator { - private final InventoryUpdater updater; public MerchantInventoryTranslator() { super(3); - this.updater = new UIInventoryUpdater(); + this.updater = UIInventoryUpdater.INSTANCE; } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/SmithingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/SmithingInventoryTranslator.java index fba8a8d6e..4d708bc3b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/SmithingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/SmithingInventoryTranslator.java @@ -29,11 +29,11 @@ import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; -import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; +import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslator { public SmithingInventoryTranslator() { - super(3, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, CursorInventoryUpdater.INSTANCE); + super(3, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java deleted file mode 100644 index 5d71f7e0b..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2019-2020 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.translators.inventory.updater; - -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; -import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.InventoryTranslator; - -public class CursorInventoryUpdater extends InventoryUpdater { - public static final CursorInventoryUpdater INSTANCE = new CursorInventoryUpdater(); - - @Override - public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { - super.updateInventory(translator, session, inventory); - - for (int i = 0; i < translator.size; i++) { - final int bedrockSlot = translator.javaSlotToBedrock(i); - if (bedrockSlot == 50) - continue; - InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(ContainerId.UI); - slotPacket.setSlot(bedrockSlot); - slotPacket.setItem(inventory.getItem(i).getItemData(session)); - session.sendUpstreamPacket(slotPacket); - } - } - - @Override - public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) { - if (super.updateSlot(translator, session, inventory, javaSlot)) - return true; - - InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(ContainerId.UI); - slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); - slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); - session.sendUpstreamPacket(slotPacket); - return true; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/UIInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/UIInventoryUpdater.java index 5100ddc99..1ebad489d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/UIInventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/UIInventoryUpdater.java @@ -30,9 +30,9 @@ import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; -import org.geysermc.connector.network.translators.item.ItemTranslator; public class UIInventoryUpdater extends InventoryUpdater { + public static final UIInventoryUpdater INSTANCE = new UIInventoryUpdater(); @Override public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java index 97c4708ff..120439360 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java @@ -38,6 +38,7 @@ public class JavaWindowPropertyTranslator extends PacketTranslator { Inventory inventory = InventoryUtils.getInventory(session, packet.getWindowId()); if (inventory == null) From ff4f712eda405ff1b0e51a62f0d062d78695e024 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 23 Dec 2020 12:30:36 -0500 Subject: [PATCH 011/101] Implement beacon --- .../connector/inventory/BeaconContainer.java | 41 ++++++ .../connector/inventory/Inventory.java | 3 + .../inventory/InventoryTranslator.java | 2 +- .../holder/BlockInventoryHolder.java | 8 ++ .../BeaconInventoryTranslator.java | 134 ++++++++++++++++++ .../entity/BeaconBlockEntityTranslator.java | 41 ++++++ 6 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 connector/src/main/java/org/geysermc/connector/inventory/BeaconContainer.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BeaconBlockEntityTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/inventory/BeaconContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/BeaconContainer.java new file mode 100644 index 000000000..70ecd84f8 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/inventory/BeaconContainer.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019-2020 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.inventory; + +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class BeaconContainer extends Container { + private int primaryId; + private int secondaryId; + + public BeaconContainer(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) { + super(title, id, windowType, size, playerInventory); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java index f4aea4c90..fed94b0bf 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java @@ -50,6 +50,9 @@ public class Inventory { protected GeyserItemStack[] items; + /** + * The location of the inventory block. Will either be a fake block above the player's head, or the actual block location + */ @Getter @Setter protected Vector3i holderPosition = Vector3i.ZERO; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index 719a20922..a726e2d7a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -80,6 +80,7 @@ public abstract class InventoryTranslator { /* Specific Inventories */ put(WindowType.ANVIL, new AnvilInventoryTranslator()); + put(WindowType.BEACON, new BeaconInventoryTranslator()); put(WindowType.BREWING_STAND, new BrewingInventoryTranslator()); put(WindowType.CRAFTING, new CraftingInventoryTranslator()); put(WindowType.ENCHANTMENT, new EnchantingInventoryTranslator()); @@ -91,7 +92,6 @@ public abstract class InventoryTranslator { /* Generics */ put(WindowType.GENERIC_3X3, new GenericBlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER)); put(WindowType.HOPPER, new GenericBlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER)); - //put(WindowType.BEACON, new AbstractBlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO //put(WindowType.CARTOGRAPHY //put(WindowType.STONECUTTER diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java index 339c8a545..1b4dfb8db 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java @@ -48,6 +48,11 @@ public class BlockInventoryHolder extends InventoryHolder { @Override public void prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { + //TODO: Improve on this (for example, multiple block states). We need this for the beacon. + if (BlockTranslator.getBedrockBlockId(session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionPosition())) == blockId) { + inventory.setHolderPosition(session.getLastInteractionPosition()); + return; + } Vector3i position = session.getPlayerEntity().getPosition().toInt(); position = position.add(Vector3i.UP); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); @@ -82,6 +87,9 @@ public class BlockInventoryHolder extends InventoryHolder { @Override public void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { Vector3i holderPos = inventory.getHolderPosition(); + if (holderPos.equals(session.getLastInteractionPosition())) { + return; + } Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); int realBlock = session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java new file mode 100644 index 000000000..678d7e842 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators; + +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientSetBeaconEffectPacket; +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.BeaconPaymentStackRequestActionData; +import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionData; +import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType; +import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; +import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; +import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; +import org.geysermc.connector.inventory.BeaconContainer; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.PlayerInventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; + +import java.util.Collections; + +public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator { + public BeaconInventoryTranslator() { + super(1, "minecraft:beacon", ContainerType.BEACON, UIInventoryUpdater.INSTANCE); + } + + @Override + public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { + //FIXME?: Beacon graphics look weird after inputting an item. This might be a Bedrock bug, since it resets to nothing + // on BDS + BeaconContainer beaconContainer = (BeaconContainer) inventory; + switch (key) { + case 0: + // Power - beacon doesn't use this, and uses the block position instead + break; + case 1: + beaconContainer.setPrimaryId(value == -1 ? 0 : value); + break; + case 2: + beaconContainer.setSecondaryId(value == -1 ? 0 : value); + break; + } + + // Send a block entity data packet update to the fake beacon inventory + Vector3i position = inventory.getHolderPosition(); + NbtMapBuilder builder = NbtMap.builder() + .putInt("x", position.getX()) + .putInt("y", position.getY()) + .putInt("z", position.getZ()) + .putString("CustomName", inventory.getTitle()) + .putString("id", "Beacon") + .putInt("primary", beaconContainer.getPrimaryId()) + .putInt("secondary", beaconContainer.getSecondaryId()); + + BlockEntityDataPacket packet = new BlockEntityDataPacket(); + packet.setBlockPosition(position); + packet.setData(builder.build()); + System.out.println(packet.toString()); + session.sendUpstreamPacket(packet); + } + + @Override + public boolean shouldHandleRequestFirst(StackRequestActionData action) { + return action.getType() == StackRequestActionType.BEACON_PAYMENT; + } + + @Override + public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + // Input a beacon payment + BeaconPaymentStackRequestActionData beaconPayment = (BeaconPaymentStackRequestActionData) request.getActions()[0]; + ClientSetBeaconEffectPacket packet = new ClientSetBeaconEffectPacket(beaconPayment.getPrimaryEffect(), beaconPayment.getSecondaryEffect()); + System.out.println(packet.toString()); + session.sendDownstreamPacket(packet); + return acceptRequest(request, makeContainerEntries(session, inventory, Collections.emptySet())); + } + + @Override + public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { + if (slotInfoData.getContainer() == ContainerSlotType.BEACON_PAYMENT) { + return 0; + } + return super.bedrockSlotToJava(slotInfoData); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + if (slot == 0) { + return new BedrockContainerSlot(ContainerSlotType.BEACON_PAYMENT, 27); + } + return super.javaSlotToBedrockContainer(slot); + } + + @Override + public int javaSlotToBedrock(int slot) { + if (slot == 0) { + return 27; + } + return super.javaSlotToBedrock(slot); + } + + @Override + public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { + return new BeaconContainer(name, windowId, windowType, this.size, playerInventory); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BeaconBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BeaconBlockEntityTranslator.java new file mode 100644 index 000000000..fca6af9b4 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BeaconBlockEntityTranslator.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019-2020 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.translators.world.block.entity; + +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.nukkitx.nbt.NbtMapBuilder; + +@BlockEntity(name = "Beacon", regex = "beacon") +public class BeaconBlockEntityTranslator extends BlockEntityTranslator { + @Override + public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + int primary = getOrDefault(tag.get("Primary"), 0); + // The effects here generally map one-to-one Java <-> Bedrock. Only the newer ones get more complicated + builder.putInt("primary", primary == -1 ? 0 : primary); + int secondary = getOrDefault(tag.get("Secondary"), 0); + builder.putInt("secondary", secondary == -1 ? 0 : secondary); + } +} From 0f735a833050809b0e9b238111da49a176b570f5 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 23 Dec 2020 12:37:55 -0500 Subject: [PATCH 012/101] Block entity cleanup --- .../world/block/entity/BannerBlockEntityTranslator.java | 2 +- .../world/block/entity/BeaconBlockEntityTranslator.java | 2 +- .../world/block/entity/BedBlockEntityTranslator.java | 2 +- .../translators/world/block/entity/BlockEntity.java | 6 ------ .../world/block/entity/BlockEntityTranslator.java | 7 +++---- .../world/block/entity/CampfireBlockEntityTranslator.java | 2 +- .../block/entity/CommandBlockBlockEntityTranslator.java | 2 +- .../block/entity/DoubleChestBlockEntityTranslator.java | 4 ++-- .../world/block/entity/EmptyBlockEntityTranslator.java | 2 +- .../block/entity/EndGatewayBlockEntityTranslator.java | 2 +- .../block/entity/JigsawBlockBlockEntityTranslator.java | 2 +- .../block/entity/ShulkerBoxBlockEntityTranslator.java | 2 +- .../world/block/entity/SignBlockEntityTranslator.java | 2 +- .../world/block/entity/SkullBlockEntityTranslator.java | 2 +- .../world/block/entity/SpawnerBlockEntityTranslator.java | 2 +- 15 files changed, 17 insertions(+), 24 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java index b59794796..18209508c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java @@ -31,7 +31,7 @@ import com.nukkitx.nbt.NbtMapBuilder; import org.geysermc.connector.network.translators.item.translators.BannerTranslator; import org.geysermc.connector.network.translators.world.block.BlockStateValues; -@BlockEntity(name = "Banner", regex = "banner") +@BlockEntity(name = "Banner") public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override public boolean isBlock(int blockState) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BeaconBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BeaconBlockEntityTranslator.java index fca6af9b4..f60b0daab 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BeaconBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BeaconBlockEntityTranslator.java @@ -28,7 +28,7 @@ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.nbt.NbtMapBuilder; -@BlockEntity(name = "Beacon", regex = "beacon") +@BlockEntity(name = "Beacon") public class BeaconBlockEntityTranslator extends BlockEntityTranslator { @Override public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BedBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BedBlockEntityTranslator.java index 0067cc41f..a111274dc 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BedBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BedBlockEntityTranslator.java @@ -29,7 +29,7 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.nbt.NbtMapBuilder; import org.geysermc.connector.network.translators.world.block.BlockStateValues; -@BlockEntity(name = "Bed", regex = "bed") +@BlockEntity(name = "Bed") public class BedBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override public boolean isBlock(int blockState) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntity.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntity.java index 11bfe0ea4..3a1345ac2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntity.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntity.java @@ -36,10 +36,4 @@ public @interface BlockEntity { * @return the name of the block entity */ String name(); - - /** - * The search term used in BlockTranslator - * @return the search term used in BlockTranslator - */ - String regex(); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java index 679636524..b9373b3c5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java @@ -109,7 +109,7 @@ public abstract class BlockEntityTranslator { int y = ((IntTag) tag.getValue().get("y")).getValue(); int z = ((IntTag) tag.getValue().get("z")).getValue(); - NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(id), x, y, z).toBuilder(); + NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(id), x, y, z); translateTag(tagBuilder, tag, blockState); return tagBuilder.build(); } @@ -123,13 +123,12 @@ public abstract class BlockEntityTranslator { return tag; } - protected NbtMap getConstantBedrockTag(String bedrockId, int x, int y, int z) { + protected NbtMapBuilder getConstantBedrockTag(String bedrockId, int x, int y, int z) { return NbtMap.builder() .putInt("x", x) .putInt("y", y) .putInt("z", z) - .putString("id", bedrockId) - .build(); + .putString("id", bedrockId); } @SuppressWarnings("unchecked") diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java index 3e4f9fb90..e41bc5ff9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java @@ -32,7 +32,7 @@ import com.nukkitx.nbt.NbtMapBuilder; import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.ItemRegistry; -@BlockEntity(name = "Campfire", regex = "campfire") +@BlockEntity(name = "Campfire") public class CampfireBlockEntityTranslator extends BlockEntityTranslator { @Override public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CommandBlockBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CommandBlockBlockEntityTranslator.java index 1eb50ffe7..99e89f273 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CommandBlockBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CommandBlockBlockEntityTranslator.java @@ -30,7 +30,7 @@ import com.nukkitx.nbt.NbtMapBuilder; import org.geysermc.connector.network.translators.world.block.BlockStateValues; import org.geysermc.connector.network.translators.chat.MessageTranslator; -@BlockEntity(name = "CommandBlock", regex = "command_block") +@BlockEntity(name = "CommandBlock") public class CommandBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/DoubleChestBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/DoubleChestBlockEntityTranslator.java index 47bcf4897..a5b67ecb8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/DoubleChestBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/DoubleChestBlockEntityTranslator.java @@ -36,7 +36,7 @@ import org.geysermc.connector.utils.BlockEntityUtils; /** * Chests have more block entity properties in Bedrock, which is solved by implementing the BedrockOnlyBlockEntity */ -@BlockEntity(name = "Chest", regex = "chest") +@BlockEntity(name = "Chest") public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator implements BedrockOnlyBlockEntity, RequiresBlockState { @Override public boolean isBlock(int blockState) { @@ -46,7 +46,7 @@ public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator impl @Override public void updateBlock(GeyserSession session, int blockState, Vector3i position) { CompoundTag javaTag = getConstantJavaTag("chest", position.getX(), position.getY(), position.getZ()); - NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId("chest"), position.getX(), position.getY(), position.getZ()).toBuilder(); + NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId("chest"), position.getX(), position.getY(), position.getZ()); translateTag(tagBuilder, javaTag, blockState); BlockEntityUtils.updateBlockEntity(session, tagBuilder.build(), position); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EmptyBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EmptyBlockEntityTranslator.java index 3926b8664..0b8839055 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EmptyBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EmptyBlockEntityTranslator.java @@ -28,7 +28,7 @@ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.nbt.NbtMapBuilder; -@BlockEntity(name = "Empty", regex = "") +@BlockEntity(name = "Empty") public class EmptyBlockEntityTranslator extends BlockEntityTranslator { @Override public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EndGatewayBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EndGatewayBlockEntityTranslator.java index 0bf588226..03689ac9e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EndGatewayBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EndGatewayBlockEntityTranslator.java @@ -35,7 +35,7 @@ import it.unimi.dsi.fastutil.ints.IntList; import java.util.LinkedHashMap; -@BlockEntity(name = "EndGateway", regex = "end_gateway") +@BlockEntity(name = "EndGateway") public class EndGatewayBlockEntityTranslator extends BlockEntityTranslator { @Override public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/JigsawBlockBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/JigsawBlockBlockEntityTranslator.java index 4fcdfe54d..6f3e7b3d7 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/JigsawBlockBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/JigsawBlockBlockEntityTranslator.java @@ -29,7 +29,7 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.nukkitx.nbt.NbtMapBuilder; -@BlockEntity(name = "JigsawBlock", regex = "jigsaw") +@BlockEntity(name = "JigsawBlock") public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator { @Override public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/ShulkerBoxBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/ShulkerBoxBlockEntityTranslator.java index 69fa10845..0eb27da56 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/ShulkerBoxBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/ShulkerBoxBlockEntityTranslator.java @@ -29,7 +29,7 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.nbt.NbtMapBuilder; import org.geysermc.connector.network.translators.world.block.BlockStateValues; -@BlockEntity(name = "ShulkerBox", regex = "shulker_box") +@BlockEntity(name = "ShulkerBox") public class ShulkerBoxBlockEntityTranslator extends BlockEntityTranslator { @Override public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SignBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SignBlockEntityTranslator.java index a9641d772..31397086a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SignBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SignBlockEntityTranslator.java @@ -30,7 +30,7 @@ import com.nukkitx.nbt.NbtMapBuilder; import org.geysermc.connector.network.translators.chat.MessageTranslator; import org.geysermc.connector.utils.SignUtils; -@BlockEntity(name = "Sign", regex = "sign") +@BlockEntity(name = "Sign") public class SignBlockEntityTranslator extends BlockEntityTranslator { /** * Maps a color stored in a sign's Color tag to a Bedrock Edition formatting code. diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SkullBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SkullBlockEntityTranslator.java index 5da9c0e0d..d8249ac50 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SkullBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SkullBlockEntityTranslator.java @@ -46,7 +46,7 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; -@BlockEntity(name = "Skull", regex = "skull") +@BlockEntity(name = "Skull") public class SkullBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { public static boolean ALLOW_CUSTOM_SKULLS; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SpawnerBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SpawnerBlockEntityTranslator.java index 38507f54a..4b8b344aa 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SpawnerBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SpawnerBlockEntityTranslator.java @@ -30,7 +30,7 @@ import com.github.steveice10.opennbt.tag.builtin.Tag; import com.nukkitx.nbt.NbtMapBuilder; import org.geysermc.connector.entity.type.EntityType; -@BlockEntity(name = "MobSpawner", regex = "mob_spawner") +@BlockEntity(name = "MobSpawner") public class SpawnerBlockEntityTranslator extends BlockEntityTranslator { @Override public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { From 4d80edf6d9139914a5233493325f731038c93aba Mon Sep 17 00:00:00 2001 From: D3ATHBRINGER13 Date: Thu, 24 Dec 2020 00:48:21 +0000 Subject: [PATCH 013/101] Initial loom funtionality --- .../inventory/InventoryTranslator.java | 3 +- .../translators/LoomInventoryTranslator.java | 85 +++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index a726e2d7a..1dc8fa7d9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -93,9 +93,10 @@ public abstract class InventoryTranslator { put(WindowType.GENERIC_3X3, new GenericBlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER)); put(WindowType.HOPPER, new GenericBlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER)); + /* Workstations */ //put(WindowType.CARTOGRAPHY //put(WindowType.STONECUTTER - //put(WindowType.LOOM + put(WindowType.LOOM, new LoomInventoryTranslator()); //put(WindowType. } }; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java new file mode 100644 index 000000000..5aa716bda --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators; + +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; + +public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { + public LoomInventoryTranslator() { + super(4, "minecraft:loom[facing=north]", ContainerType.LOOM, UIInventoryUpdater.INSTANCE); + } + + @Override + public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { + if (slotInfoData.getContainer() == ContainerSlotType.LOOM_INPUT) { + return 0; + } + if (slotInfoData.getContainer() == ContainerSlotType.LOOM_DYE) { + return 1; + } + if (slotInfoData.getContainer() == ContainerSlotType.LOOM_MATERIAL) { + return 2; + } + if (slotInfoData.getContainer() == ContainerSlotType.LOOM_RESULT || slotInfoData.getContainer() == ContainerSlotType.CREATIVE_OUTPUT) { + return 3; + } + return super.bedrockSlotToJava(slotInfoData); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + switch (slot) { + case 0: + return new BedrockContainerSlot(ContainerSlotType.LOOM_INPUT, 9); + case 1: + return new BedrockContainerSlot(ContainerSlotType.LOOM_DYE, 10); + case 2: + return new BedrockContainerSlot(ContainerSlotType.LOOM_MATERIAL, 11); + case 3: + return new BedrockContainerSlot(ContainerSlotType.LOOM_RESULT, 50); + } + return super.javaSlotToBedrockContainer(slot); + } + + @Override + public int javaSlotToBedrock(int slot) { + switch (slot) { + case 0: + return 9; + case 1: + return 10; + case 2: + return 11; + case 3: + return 50; + } + return super.javaSlotToBedrock(slot); + } +} From 6ae81cce527e0446d09dbd78eca1b988f680a001 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 23 Dec 2020 22:53:54 -0500 Subject: [PATCH 014/101] Full banner loom support --- .../inventory/InventoryTranslator.java | 10 +- .../BeaconInventoryTranslator.java | 2 +- .../EnchantingInventoryTranslator.java | 2 +- .../translators/LoomInventoryTranslator.java | 92 +++++++++++++++++++ 4 files changed, 99 insertions(+), 7 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index 1dc8fa7d9..bde448ab9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -85,6 +85,7 @@ public abstract class InventoryTranslator { put(WindowType.CRAFTING, new CraftingInventoryTranslator()); put(WindowType.ENCHANTMENT, new EnchantingInventoryTranslator()); put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator()); + put(WindowType.LOOM, new LoomInventoryTranslator()); put(WindowType.MERCHANT, new MerchantInventoryTranslator()); put(WindowType.SHULKER_BOX, new ShulkerInventoryTranslator()); put(WindowType.SMITHING, new SmithingInventoryTranslator()); @@ -93,10 +94,9 @@ public abstract class InventoryTranslator { put(WindowType.GENERIC_3X3, new GenericBlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER)); put(WindowType.HOPPER, new GenericBlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER)); - /* Workstations */ + /* todo */ //put(WindowType.CARTOGRAPHY //put(WindowType.STONECUTTER - put(WindowType.LOOM, new LoomInventoryTranslator()); //put(WindowType. } }; @@ -122,12 +122,12 @@ public abstract class InventoryTranslator { * Should be overrided if this request matches a certain criteria and shouldn't be treated normally. * E.G. anvil renaming or enchanting */ - public boolean shouldHandleRequestFirst(StackRequestActionData action) { + public boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { return false; } /** - * If {@link #shouldHandleRequestFirst(StackRequestActionData)} returns true, this will be called + * If {@link #shouldHandleRequestFirst(StackRequestActionData, Inventory)} returns true, this will be called */ public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { return null; @@ -138,7 +138,7 @@ public abstract class InventoryTranslator { for (ItemStackRequestPacket.Request request : requests) { if (request.getActions().length > 0) { StackRequestActionData firstAction = request.getActions()[0]; - if (shouldHandleRequestFirst(firstAction)) { + if (shouldHandleRequestFirst(firstAction, inventory)) { // Some special request that shouldn't be processed normally responsePacket.getEntries().add(translateSpecialRequest(session, inventory, request)); } else if (firstAction.getType() == StackRequestActionType.CRAFT_RECIPE || firstAction.getType() == StackRequestActionType.CRAFT_RECIPE_AUTO) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java index 678d7e842..8ffc3e1a9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java @@ -89,7 +89,7 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator } @Override - public boolean shouldHandleRequestFirst(StackRequestActionData action) { + public boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { return action.getType() == StackRequestActionType.BEACON_PAYMENT; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java index cfa024191..ea836e3bd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java @@ -105,7 +105,7 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla } @Override - public boolean shouldHandleRequestFirst(StackRequestActionData action) { + public boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { return action.getType() == StackRequestActionType.CRAFT_RECIPE; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java index 5aa716bda..db5fc963d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java @@ -25,17 +25,109 @@ package org.geysermc.connector.network.translators.inventory.translators; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientClickWindowButtonPacket; +import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; 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.StackRequestActionData; +import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType; +import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; +import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; +import java.util.List; + public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { + /** + * A map of Bedrock patterns to Java index. Used to request for a specific banner pattern. + */ + private static final Object2IntMap PATTERN_TO_INDEX = new Object2IntOpenHashMap<>(); + + static { + // Added from left-to-right then up-to-down in the order Java presents it + int index = 1; + PATTERN_TO_INDEX.put("bl", index++); + PATTERN_TO_INDEX.put("br", index++); + PATTERN_TO_INDEX.put("tl", index++); + PATTERN_TO_INDEX.put("tr", index++); + PATTERN_TO_INDEX.put("bs", index++); + PATTERN_TO_INDEX.put("ts", index++); + PATTERN_TO_INDEX.put("ls", index++); + PATTERN_TO_INDEX.put("rs", index++); + PATTERN_TO_INDEX.put("cs", index++); + PATTERN_TO_INDEX.put("ms", index++); + PATTERN_TO_INDEX.put("drs", index++); + PATTERN_TO_INDEX.put("dls", index++); + PATTERN_TO_INDEX.put("ss", index++); + PATTERN_TO_INDEX.put("cr", index++); + PATTERN_TO_INDEX.put("sc", index++); + PATTERN_TO_INDEX.put("bt", index++); + PATTERN_TO_INDEX.put("tt", index++); + PATTERN_TO_INDEX.put("bts", index++); + PATTERN_TO_INDEX.put("tts", index++); + PATTERN_TO_INDEX.put("ld", index++); + PATTERN_TO_INDEX.put("rd", index++); + PATTERN_TO_INDEX.put("lud", index++); + PATTERN_TO_INDEX.put("rud", index++); + PATTERN_TO_INDEX.put("mc", index++); + PATTERN_TO_INDEX.put("mr", index++); + PATTERN_TO_INDEX.put("vh", index++); + PATTERN_TO_INDEX.put("hh", index++); + PATTERN_TO_INDEX.put("vhr", index++); + PATTERN_TO_INDEX.put("hhb", index++); + PATTERN_TO_INDEX.put("bo", index++); + index++; // Bordure indented, does not appear to exist in Bedrock? + PATTERN_TO_INDEX.put("gra", index++); + PATTERN_TO_INDEX.put("gru", index); + // Bricks do not appear to be a pattern on Bedrock, either + } + public LoomInventoryTranslator() { super(4, "minecraft:loom[facing=north]", ContainerType.LOOM, UIInventoryUpdater.INSTANCE); } + @Override + public boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { + // If the LOOM_MATERIAL slot is not empty, we are crafting a pattern that does not come from an item + return action.getType() == StackRequestActionType.CRAFT_NON_IMPLEMENTED_DEPRECATED && inventory.getItem(2).isEmpty(); + } + + @Override + public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + // TODO: I anticipate this will be changed in the future to use something non-deprecated. Keep an eye out. + // Also TODO: Shift-clicking doesn't work here. + StackRequestActionData data = request.getActions()[1]; + if (!(data instanceof CraftResultsDeprecatedStackRequestActionData)) { + return rejectRequest(request); + } + CraftResultsDeprecatedStackRequestActionData craftData = (CraftResultsDeprecatedStackRequestActionData) data; + // Get the patterns compound tag + List blockEntityTag = craftData.getResultItems()[0].getTag().getList("Patterns", NbtType.COMPOUND); + // Get the pattern that the Bedrock client requests - the last pattern in the Patterns list + String pattern = blockEntityTag.get(blockEntityTag.size() - 1).getString("Pattern"); + // Get the Java index of this pattern + int index = PATTERN_TO_INDEX.getOrDefault(pattern, -1); + if (index == -1) { + return rejectRequest(request); + } + // Java's formula: 4 * row + col + // 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. :) + ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), index); + System.out.println(packet); + session.sendDownstreamPacket(packet); + + return translateRequest(session, inventory, request); + } + @Override public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { if (slotInfoData.getContainer() == ContainerSlotType.LOOM_INPUT) { From 617a1216d5f6226b23344a36f617d433462cd24c Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 24 Dec 2020 11:23:47 -0500 Subject: [PATCH 015/101] Initial work on stonecutters --- .../network/session/GeyserSession.java | 19 +-- .../inventory/InventoryTranslator.java | 4 +- .../StonecutterInventoryTranslator.java | 118 ++++++++++++++++++ .../java/JavaDeclareRecipesTranslator.java | 23 ++++ 4 files changed, 153 insertions(+), 11 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 9f29acbb5..5d0e26040 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -32,8 +32,8 @@ import com.github.steveice10.mc.protocol.MinecraftConstants; import com.github.steveice10.mc.protocol.MinecraftProtocol; import com.github.steveice10.mc.protocol.data.SubProtocol; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.statistic.Statistic; import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; +import com.github.steveice10.mc.protocol.data.game.statistic.Statistic; import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket; @@ -53,6 +53,7 @@ import com.nukkitx.protocol.bedrock.data.command.CommandPermission; import com.nukkitx.protocol.bedrock.packet.*; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMaps; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; @@ -93,15 +94,8 @@ import java.net.InetSocketAddress; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; @Getter @@ -218,6 +212,13 @@ public class GeyserSession implements CommandSender { @Setter private Int2ObjectMap craftingRecipes; + /** + * Saves a list of all stonecutter recipes, for use in a stonecutter inventory. + * The key is the Java ID of the item; the values are all the possible outputs' Java IDs + */ + @Setter + private Int2ObjectMap stonecutterRecipes; + /** * The current attack speed of the player. Used for sending proper cooldown timings. * Setting a default fixes cooldowns not showing up on a fresh world. diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index bde448ab9..d2fb12a01 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -89,6 +89,7 @@ public abstract class InventoryTranslator { put(WindowType.MERCHANT, new MerchantInventoryTranslator()); put(WindowType.SHULKER_BOX, new ShulkerInventoryTranslator()); put(WindowType.SMITHING, new SmithingInventoryTranslator()); + put(WindowType.STONECUTTER, new StonecutterInventoryTranslator()); /* Generics */ put(WindowType.GENERIC_3X3, new GenericBlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER)); @@ -96,8 +97,7 @@ public abstract class InventoryTranslator { /* todo */ //put(WindowType.CARTOGRAPHY - //put(WindowType.STONECUTTER - //put(WindowType. + // horse } }; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java new file mode 100644 index 000000000..dd6c3b365 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientClickWindowButtonPacket; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +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.StackRequestActionData; +import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType; +import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; +import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; +import it.unimi.dsi.fastutil.ints.IntSet; +import org.geysermc.connector.inventory.GeyserItemStack; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; +import org.geysermc.connector.network.translators.item.ItemTranslator; + +import java.util.stream.Collectors; + +public class StonecutterInventoryTranslator extends AbstractBlockInventoryTranslator { + public StonecutterInventoryTranslator() { + super(2, "minecraft:stonecutter[facing=north]", ContainerType.STONECUTTER, UIInventoryUpdater.INSTANCE); + } + + @Override + public boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { + return action.getType() == StackRequestActionType.CRAFT_NON_IMPLEMENTED_DEPRECATED; + } + + @Override + public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + // TODO: Also surely to change in the future + StackRequestActionData data = request.getActions()[1]; + if (!(data instanceof CraftResultsDeprecatedStackRequestActionData)) { + return rejectRequest(request); + } + CraftResultsDeprecatedStackRequestActionData craftData = (CraftResultsDeprecatedStackRequestActionData) data; + // Get the ID of the item we are cutting + int id = inventory.getItem(0).getId(); + // Look up all possible options of cutting from this ID + IntSet results = session.getStonecutterRecipes().get(id); + if (results == null) { + return rejectRequest(request); + } + ItemStack javaOutput = ItemTranslator.translateToJava(craftData.getResultItems()[0]); + // TODO bruh + // Getting the index of the item in the Java stonecutter list + // We do need to sort them by their Java ID to preserve index, though + int index = results.stream().sorted().collect(Collectors.toList()).indexOf(javaOutput.getId()); + ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), index + 1); + System.out.println(packet.toString()); + session.sendDownstreamPacket(packet); + // We don't know there is an output here, so we tell ourselves that there is + inventory.setItem(1, GeyserItemStack.from(javaOutput, session.getItemNetId().incrementAndGet())); + return translateRequest(session, inventory, request); + } + + @Override + public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { + if (slotInfoData.getContainer() == ContainerSlotType.STONECUTTER_INPUT) { + return 0; + } + if (slotInfoData.getContainer() == ContainerSlotType.STONECUTTER_RESULT || slotInfoData.getContainer() == ContainerSlotType.CREATIVE_OUTPUT) { + return 1; + } + return super.bedrockSlotToJava(slotInfoData); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + if (slot == 0) { + return new BedrockContainerSlot(ContainerSlotType.STONECUTTER_INPUT, 3); + } + if (slot == 1) { + return new BedrockContainerSlot(ContainerSlotType.STONECUTTER_RESULT, 50); + } + return super.javaSlotToBedrockContainer(slot); + } + + @Override + public int javaSlotToBedrock(int slot) { + if (slot == 0) { + return 3; + } + if (slot == 1) { + return 50; + } + return super.javaSlotToBedrock(slot); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java index 824b5acde..c475396c5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -25,10 +25,12 @@ package org.geysermc.connector.network.translators.java; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; +import com.github.steveice10.mc.protocol.data.game.recipe.data.StoneCuttingRecipeData; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerDeclareRecipesPacket; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; @@ -56,6 +58,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator recipeMap = new Int2ObjectOpenHashMap<>(); + Int2ObjectMap stonecutterRecipeMap = new Int2ObjectOpenHashMap<>(); CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); craftingDataPacket.setCleanRecipes(true); for (Recipe recipe : packet.getRecipes()) { @@ -136,11 +139,31 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator Date: Thu, 24 Dec 2020 18:29:25 -0500 Subject: [PATCH 016/101] Stonecutter fixed; Loom improved --- .../network/session/GeyserSession.java | 6 +- .../inventory/InventoryTranslator.java | 24 ++++++-- .../EnchantingInventoryTranslator.java | 2 +- .../translators/LoomInventoryTranslator.java | 51 +++++++++++++++-- .../StonecutterInventoryTranslator.java | 28 ++++++---- .../item/translators/BannerTranslator.java | 5 +- .../java/JavaDeclareRecipesTranslator.java | 55 ++++++++++++------- 7 files changed, 129 insertions(+), 42 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 5d0e26040..880e87128 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -53,7 +53,7 @@ import com.nukkitx.protocol.bedrock.data.command.CommandPermission; import com.nukkitx.protocol.bedrock.packet.*; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMaps; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; @@ -214,10 +214,10 @@ public class GeyserSession implements CommandSender { /** * Saves a list of all stonecutter recipes, for use in a stonecutter inventory. - * The key is the Java ID of the item; the values are all the possible outputs' Java IDs + * 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; /** * The current attack speed of the player. Used for sending proper cooldown timings. diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index d2fb12a01..b3f2475d8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -118,6 +118,16 @@ public abstract class InventoryTranslator { public abstract SlotType getSlotType(int javaSlot); public abstract Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory); + /** + * Should be overwritten in cases where specific inventories should reject an item being in a specific spot. + * For examples, looms use this to reject items that are dyes in Bedrock but not in Java. + * + * @return true if this transfer should be rejected + */ + public boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, int javaDestinationSlot) { + return false; + } + /** * Should be overrided if this request matches a certain criteria and shouldn't be treated normally. * E.G. anvil renaming or enchanting @@ -178,12 +188,18 @@ public abstract class InventoryTranslator { return rejectRequest(request); } + int destSlot = bedrockSlotToJava(transferAction.getDestination()); + + if (shouldRejectItemPlace(session, inventory, destSlot)) { + // This item would not be here in Java + return rejectRequest(request, false); + } + if (isCursor(transferAction.getSource()) && isCursor(transferAction.getDestination())) { //??? return rejectRequest(request); } else if (session.getGameMode().equals(GameMode.CREATIVE) && inventory instanceof PlayerInventory) { // TODO: does the Java server use this stuff all the time in creative? // Creative acts a little differently because it just edits slots int sourceSlot = bedrockSlotToJava(transferAction.getSource()); - int destSlot = bedrockSlotToJava(transferAction.getDestination()); boolean sourceIsCursor = isCursor(transferAction.getSource()); boolean destIsCursor = isCursor(transferAction.getDestination()); @@ -249,7 +265,6 @@ public abstract class InventoryTranslator { } else if (isCursor(transferAction.getSource())) { //releasing cursor int sourceAmount = cursor.getAmount(); - int destSlot = bedrockSlotToJava(transferAction.getDestination()); if (transferAction.getCount() == sourceAmount) { //release all plan.add(Click.LEFT, destSlot); } else { //release some @@ -279,7 +294,9 @@ public abstract class InventoryTranslator { if (transferAction.getCount() != sourceAmount) { //TODO: handle partially picking up into non-empty cursor (temp slot) return rejectRequest(request); } - plan.add(Click.LEFT, sourceSlot); //release cursor onto source slot + if (getSlotType(sourceSlot).equals(SlotType.NORMAL)) { + plan.add(Click.LEFT, sourceSlot); //release cursor onto source slot + } plan.add(Click.LEFT, sourceSlot); //pickup combined cursor and source } } else { //transfer from one slot to another @@ -288,7 +305,6 @@ public abstract class InventoryTranslator { } int sourceSlot = bedrockSlotToJava(transferAction.getSource()); int sourceAmount = plan.getItem(sourceSlot).getAmount(); - int destSlot = bedrockSlotToJava(transferAction.getDestination()); if (transferAction.getCount() == sourceAmount) { //transfer all plan.add(Click.LEFT, sourceSlot); //pickup source plan.add(Click.LEFT, destSlot); //let go of all items and done diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java index ea836e3bd..c8ae8e2df 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java @@ -127,7 +127,7 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla } if (javaSlot == -1) { // Slot should be determined as 0, 1, or 2 - throw new RuntimeException("Cannot find enchant slot for item!"); + return rejectRequest(request); } ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), javaSlot); System.out.println(packet); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java index db5fc963d..bacc83a02 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java @@ -26,6 +26,8 @@ package org.geysermc.connector.network.translators.inventory.translators; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientClickWindowButtonPacket; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; @@ -38,11 +40,15 @@ import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; +import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.network.translators.item.translators.BannerTranslator; +import java.util.Collections; import java.util.List; public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { @@ -94,6 +100,20 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { super(4, "minecraft:loom[facing=north]", ContainerType.LOOM, UIInventoryUpdater.INSTANCE); } + @Override + public boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, int javaDestinationSlot) { + if (javaDestinationSlot != 1) { + return false; + } + GeyserItemStack itemStack = session.getPlayerInventory().getCursor(); + if (itemStack.isEmpty()) { + return false; + } + + // Reject the item if Bedrock is attempting to put in a dye that is not a dye in Java Edition + return !ItemRegistry.getItem(itemStack.getItemStack()).getJavaIdentifier().contains("_dye"); + } + @Override public boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { // If the LOOM_MATERIAL slot is not empty, we are crafting a pattern that does not come from an item @@ -103,18 +123,17 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { @Override public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { // TODO: I anticipate this will be changed in the future to use something non-deprecated. Keep an eye out. - // Also TODO: Shift-clicking doesn't work here. StackRequestActionData data = request.getActions()[1]; if (!(data instanceof CraftResultsDeprecatedStackRequestActionData)) { return rejectRequest(request); } CraftResultsDeprecatedStackRequestActionData craftData = (CraftResultsDeprecatedStackRequestActionData) data; // Get the patterns compound tag - List blockEntityTag = craftData.getResultItems()[0].getTag().getList("Patterns", NbtType.COMPOUND); + List newblockEntityTag = craftData.getResultItems()[0].getTag().getList("Patterns", NbtType.COMPOUND); // Get the pattern that the Bedrock client requests - the last pattern in the Patterns list - String pattern = blockEntityTag.get(blockEntityTag.size() - 1).getString("Pattern"); + NbtMap pattern = newblockEntityTag.get(newblockEntityTag.size() - 1); // Get the Java index of this pattern - int index = PATTERN_TO_INDEX.getOrDefault(pattern, -1); + int index = PATTERN_TO_INDEX.getOrDefault(pattern.getString("Pattern"), -1); if (index == -1) { return rejectRequest(request); } @@ -124,6 +143,30 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), index); System.out.println(packet); session.sendDownstreamPacket(packet); + GeyserItemStack inputCopy = inventory.getItem(0).copy(); + inputCopy.setNetId(session.getItemNetId().incrementAndGet()); + // Add the pattern manually, for better item synchronization + if (inputCopy.getNbt() == null) { + inputCopy.setNbt(new CompoundTag("")); + } + CompoundTag blockEntityTag = inputCopy.getNbt().get("BlockEntityTag"); + CompoundTag javaBannerPattern = BannerTranslator.getJavaBannerPattern(pattern); + if (blockEntityTag != null) { + ListTag patternsList = blockEntityTag.get("Patterns"); + if (patternsList != null) { + patternsList.add(javaBannerPattern); + } else { + patternsList = new ListTag("Patterns", Collections.singletonList(javaBannerPattern)); + blockEntityTag.put(patternsList); + } + } else { + blockEntityTag = new CompoundTag("BlockEntityTag"); + ListTag patternsList = new ListTag("Patterns", Collections.singletonList(javaBannerPattern)); + blockEntityTag.put(patternsList); + inputCopy.getNbt().put(blockEntityTag); + } + // Set the new item as the output + inventory.setItem(3, inputCopy); return translateRequest(session, inventory, request); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java index dd6c3b365..7bac3c650 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java @@ -35,16 +35,15 @@ import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequ import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType; import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; -import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.ints.IntList; import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.SlotType; import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; import org.geysermc.connector.network.translators.item.ItemTranslator; -import java.util.stream.Collectors; - public class StonecutterInventoryTranslator extends AbstractBlockInventoryTranslator { public StonecutterInventoryTranslator() { super(2, "minecraft:stonecutter[facing=north]", ContainerType.STONECUTTER, UIInventoryUpdater.INSTANCE); @@ -66,20 +65,21 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl // Get the ID of the item we are cutting int id = inventory.getItem(0).getId(); // Look up all possible options of cutting from this ID - IntSet results = session.getStonecutterRecipes().get(id); + IntList results = session.getStonecutterRecipes().get(id); if (results == null) { return rejectRequest(request); } + System.out.println(id + " " + results); ItemStack javaOutput = ItemTranslator.translateToJava(craftData.getResultItems()[0]); - // TODO bruh + System.out.println(javaOutput); // Getting the index of the item in the Java stonecutter list - // We do need to sort them by their Java ID to preserve index, though - int index = results.stream().sorted().collect(Collectors.toList()).indexOf(javaOutput.getId()); - ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), index + 1); + ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), results.indexOf(javaOutput.getId())); System.out.println(packet.toString()); session.sendDownstreamPacket(packet); - // We don't know there is an output here, so we tell ourselves that there is - inventory.setItem(1, GeyserItemStack.from(javaOutput, session.getItemNetId().incrementAndGet())); + if (inventory.getItem(1).getId() != javaOutput.getId()) { + // We don't know there is an output here, so we tell ourselves that there is + inventory.setItem(1, GeyserItemStack.from(javaOutput, session.getItemNetId().incrementAndGet())); + } return translateRequest(session, inventory, request); } @@ -115,4 +115,12 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl } return super.javaSlotToBedrock(slot); } + + @Override + public SlotType getSlotType(int javaSlot) { + if (javaSlot == 1) { + return SlotType.OUTPUT; + } + return super.getSlotType(javaSlot); + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java index 5e5bc3542..1870a1279 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java @@ -32,6 +32,7 @@ import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtType; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.translators.ItemRemapper; import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.ItemRegistry; @@ -181,6 +182,7 @@ public class BannerTranslator extends ItemTranslator { @Override public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { + GeyserConnector.getInstance().getLogger().warning(itemEntry.toString()); if (itemData.getTag() == null) { return super.translateToJava(itemData, itemEntry); } @@ -195,13 +197,14 @@ public class BannerTranslator extends ItemTranslator { blockEntityTag.put(OMINOUS_BANNER_PATTERN); itemStack.getNbt().put(blockEntityTag); - } else if (nbtTag.containsKey("Patterns", NbtType.COMPOUND)) { + } else if (nbtTag.containsKey("Patterns", NbtType.LIST)) { List patterns = nbtTag.getList("Patterns", NbtType.COMPOUND); CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); blockEntityTag.put(convertBannerPattern(patterns)); itemStack.getNbt().put(blockEntityTag); + itemStack.getNbt().remove("Patterns"); // Remove the old Bedrock patterns list } return itemStack; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java index c475396c5..e74a82324 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -36,10 +36,7 @@ import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; -import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.ints.*; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import org.geysermc.connector.network.session.GeyserSession; @@ -58,7 +55,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator recipeMap = new Int2ObjectOpenHashMap<>(); - Int2ObjectMap stonecutterRecipeMap = new Int2ObjectOpenHashMap<>(); + Int2ObjectMap> unsortedStonecutterData = new Int2ObjectOpenHashMap<>(); CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); craftingDataPacket.setCleanRecipes(true); for (Recipe recipe : packet.getRecipes()) { @@ -141,26 +138,46 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator data = unsortedStonecutterData.get(ingredient.getId()); + if (data == null) { + data = new ArrayList<>(); + unsortedStonecutterData.put(ingredient.getId(), data); } - // Add the ingredient as the key and all possible values as the value - outputs.add(stoneCuttingData.getResult().getId()); + data.add(stoneCuttingData); + // Save for processing after all recipes have been received } } } craftingDataPacket.getPotionMixData().addAll(PotionMixRegistry.POTION_MIXES); + + Int2ObjectMap stonecutterRecipeMap = new Int2ObjectOpenHashMap<>(); + for (Int2ObjectMap.Entry> data : unsortedStonecutterData.int2ObjectEntrySet()) { + data.getValue().sort(Comparator.comparing((stoneCuttingRecipeData -> + // 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 + ItemRegistry.getItem(stoneCuttingRecipeData.getResult()).getJavaIdentifier()))); + // Now that it's sorted, let's translate these recipes + for (StoneCuttingRecipeData stoneCuttingData : data.getValue()) { + // As of 1.16.4, all stonecutter recipes have one ingredient option + ItemStack ingredient = stoneCuttingData.getIngredient().getOptions()[0]; + ItemData input = ItemTranslator.translateToBedrock(session, ingredient); + ItemData output = ItemTranslator.translateToBedrock(session, stoneCuttingData.getResult()); + UUID uuid = UUID.randomUUID(); + // We need to register stonecutting recipes so they show up on Bedrock + craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(), + Collections.singletonList(input), Collections.singletonList(output), uuid, "stonecutter", 0, netId++)); + // Save the recipe list for reference when crafting + IntList outputs = stonecutterRecipeMap.get(ingredient.getId()); + if (outputs == null) { + outputs = new IntArrayList(); + // Add the ingredient as the key and all possible values as the value + stonecutterRecipeMap.put(ingredient.getId(), outputs); + } + outputs.add(stoneCuttingData.getResult().getId()); + } + } + session.sendUpstreamPacket(craftingDataPacket); session.setCraftingRecipes(recipeMap); session.setStonecutterRecipes(stonecutterRecipeMap); From c7fade295ea93d31752f38dcf879ad70ce8c23d5 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 24 Dec 2020 20:43:24 -0500 Subject: [PATCH 017/101] Add swap support for creative mode; start on cartography table --- .../inventory/InventoryTranslator.java | 53 +++++++++-- .../CartographyInventoryTranslator.java | 95 +++++++++++++++++++ .../translators/LoomInventoryTranslator.java | 8 +- 3 files changed, 145 insertions(+), 11 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CartographyInventoryTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index b3f2475d8..3e5bf0c67 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -82,6 +82,7 @@ public abstract class InventoryTranslator { put(WindowType.ANVIL, new AnvilInventoryTranslator()); put(WindowType.BEACON, new BeaconInventoryTranslator()); put(WindowType.BREWING_STAND, new BrewingInventoryTranslator()); + put(WindowType.CARTOGRAPHY, new CartographyInventoryTranslator()); put(WindowType.CRAFTING, new CraftingInventoryTranslator()); put(WindowType.ENCHANTMENT, new EnchantingInventoryTranslator()); put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator()); @@ -96,7 +97,6 @@ public abstract class InventoryTranslator { put(WindowType.HOPPER, new GenericBlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER)); /* todo */ - //put(WindowType.CARTOGRAPHY // horse } }; @@ -122,9 +122,11 @@ public abstract class InventoryTranslator { * Should be overwritten in cases where specific inventories should reject an item being in a specific spot. * For examples, looms use this to reject items that are dyes in Bedrock but not in Java. * + * javaSourceSlot will be -1 if the cursor is the source + * * @return true if this transfer should be rejected */ - public boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, int javaDestinationSlot) { + public boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, int javaSourceSlot, int javaDestinationSlot) { return false; } @@ -188,9 +190,10 @@ public abstract class InventoryTranslator { return rejectRequest(request); } + int sourceSlot = bedrockSlotToJava(transferAction.getSource()); int destSlot = bedrockSlotToJava(transferAction.getDestination()); - if (shouldRejectItemPlace(session, inventory, destSlot)) { + if (shouldRejectItemPlace(session, inventory, isCursor(transferAction.getSource()) ? -1 :sourceSlot, destSlot)) { // This item would not be here in Java return rejectRequest(request, false); } @@ -199,7 +202,6 @@ public abstract class InventoryTranslator { return rejectRequest(request); } else if (session.getGameMode().equals(GameMode.CREATIVE) && inventory instanceof PlayerInventory) { // TODO: does the Java server use this stuff all the time in creative? // Creative acts a little differently because it just edits slots - int sourceSlot = bedrockSlotToJava(transferAction.getSource()); boolean sourceIsCursor = isCursor(transferAction.getSource()); boolean destIsCursor = isCursor(transferAction.getDestination()); @@ -228,6 +230,15 @@ public abstract class InventoryTranslator { affectedSlots.add(destSlot); break; } + } else { + // Delete the source since we're moving it + inventory.setItem(sourceSlot, GeyserItemStack.EMPTY); + ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( + sourceSlot, + new ItemStack(0) + ); + session.sendDownstreamPacket(creativeActionPacket); + affectedSlots.add(sourceSlot); } // Update the item count with however much the client took newItem.setAmount(transferAction.getCount()); @@ -273,7 +284,6 @@ public abstract class InventoryTranslator { } } } else if (isCursor(transferAction.getDestination())) { //picking up into cursor - int sourceSlot = bedrockSlotToJava(transferAction.getSource()); GeyserItemStack sourceItem = plan.getItem(sourceSlot); int sourceAmount = sourceItem.getAmount(); if (cursor.isEmpty()) { //picking up into empty cursor @@ -303,7 +313,6 @@ public abstract class InventoryTranslator { if (!cursor.isEmpty()) { //TODO: handle slot transfer when cursor is already in use (temp slot) return rejectRequest(request); } - int sourceSlot = bedrockSlotToJava(transferAction.getSource()); int sourceAmount = plan.getItem(sourceSlot).getAmount(); if (transferAction.getCount() == sourceAmount) { //transfer all plan.add(Click.LEFT, sourceSlot); //pickup source @@ -339,7 +348,37 @@ public abstract class InventoryTranslator { if (!(checkNetId(session, inventory, swapAction.getSource()) && checkNetId(session, inventory, swapAction.getDestination()))) return rejectRequest(request); - if (isCursor(swapAction.getSource()) && isCursor(swapAction.getDestination())) { //??? + if (session.getGameMode().equals(GameMode.CREATIVE) && inventory instanceof PlayerInventory) { + int destSlot = bedrockSlotToJava(swapAction.getDestination()); + GeyserItemStack oldSourceItem; + GeyserItemStack oldDestinationItem = inventory.getItem(destSlot); + if (isCursor(swapAction.getSource())) { + oldSourceItem = session.getPlayerInventory().getCursor(); + session.getPlayerInventory().setCursor(oldDestinationItem); + } else { + int sourceSlot = bedrockSlotToJava(swapAction.getSource()); + oldSourceItem = inventory.getItem(sourceSlot); + ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( + sourceSlot, + oldDestinationItem.isEmpty() ? new ItemStack(0) : oldDestinationItem.getItemStack() // isEmpty check... just in case + ); + System.out.println(creativeActionPacket); + session.sendDownstreamPacket(creativeActionPacket); + inventory.setItem(sourceSlot, oldDestinationItem); + } + if (isCursor(swapAction.getDestination())) { + session.getPlayerInventory().setCursor(oldSourceItem); + } else { + ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( + destSlot, + oldSourceItem.isEmpty() ? new ItemStack(0) : oldSourceItem.getItemStack() + ); + System.out.println(creativeActionPacket); + session.sendDownstreamPacket(creativeActionPacket); + inventory.setItem(destSlot, oldSourceItem); + } + + } else if (isCursor(swapAction.getSource()) && isCursor(swapAction.getDestination())) { //??? return rejectRequest(request); } else if (isCursor(swapAction.getSource())) { //swap cursor int destSlot = bedrockSlotToJava(swapAction.getDestination()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CartographyInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CartographyInventoryTranslator.java new file mode 100644 index 000000000..1ce6d078a --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CartographyInventoryTranslator.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators; + +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +import org.geysermc.connector.inventory.GeyserItemStack; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; +import org.geysermc.connector.network.translators.item.ItemRegistry; + +public class CartographyInventoryTranslator extends AbstractBlockInventoryTranslator { + public CartographyInventoryTranslator() { + super(3, "minecraft:cartography_table", ContainerType.CARTOGRAPHY, UIInventoryUpdater.INSTANCE); + } + + @Override + public boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, int javaSourceSlot, int javaDestinationSlot) { + if (javaDestinationSlot == 1) { + // Bedrock Edition can use a compass to create locator maps in the ADDITIONAL slot + GeyserItemStack itemStack = javaSourceSlot == -1 ? session.getPlayerInventory().getCursor() : inventory.getItem(javaSourceSlot); + return ItemRegistry.getItem(itemStack.getItemStack()).getJavaIdentifier().equals("minecraft:compass"); + } else if (javaSourceSlot == 2) { + // Java doesn't allow an item to be renamed; this is why CARTOGRAPHY_ADDITIONAL could remain empty for Bedrock + return inventory.getItem(1).isEmpty(); + } + return false; + } + + @Override + public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { + if (slotInfoData.getContainer() == ContainerSlotType.CARTOGRAPHY_INPUT) { + return 0; + } + if (slotInfoData.getContainer() == ContainerSlotType.CARTOGRAPHY_ADDITIONAL) { + return 1; + } + if (slotInfoData.getContainer() == ContainerSlotType.CARTOGRAPHY_RESULT || slotInfoData.getContainer() == ContainerSlotType.CREATIVE_OUTPUT) { + return 2; + } + return super.bedrockSlotToJava(slotInfoData); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + switch (slot) { + case 0: + return new BedrockContainerSlot(ContainerSlotType.CARTOGRAPHY_INPUT, 12); + case 1: + return new BedrockContainerSlot(ContainerSlotType.CARTOGRAPHY_ADDITIONAL, 13); + case 2: + return new BedrockContainerSlot(ContainerSlotType.CARTOGRAPHY_RESULT, 50); + } + return super.javaSlotToBedrockContainer(slot); + } + + @Override + public int javaSlotToBedrock(int slot) { + switch (slot) { + case 0: + return 12; + case 1: + return 13; + case 2: + return 50; + } + return super.javaSlotToBedrock(slot); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java index bacc83a02..47f213799 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java @@ -101,11 +101,11 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { } @Override - public boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, int javaDestinationSlot) { + public boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, int javaSourceSlot, int javaDestinationSlot) { if (javaDestinationSlot != 1) { return false; } - GeyserItemStack itemStack = session.getPlayerInventory().getCursor(); + GeyserItemStack itemStack = javaSourceSlot == -1 ? session.getPlayerInventory().getCursor() : inventory.getItem(javaSourceSlot); if (itemStack.isEmpty()) { return false; } @@ -129,9 +129,9 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { } CraftResultsDeprecatedStackRequestActionData craftData = (CraftResultsDeprecatedStackRequestActionData) data; // Get the patterns compound tag - List newblockEntityTag = craftData.getResultItems()[0].getTag().getList("Patterns", NbtType.COMPOUND); + List newBlockEntityTag = craftData.getResultItems()[0].getTag().getList("Patterns", NbtType.COMPOUND); // Get the pattern that the Bedrock client requests - the last pattern in the Patterns list - NbtMap pattern = newblockEntityTag.get(newblockEntityTag.size() - 1); + NbtMap pattern = newBlockEntityTag.get(newBlockEntityTag.size() - 1); // Get the Java index of this pattern int index = PATTERN_TO_INDEX.getOrDefault(pattern.getString("Pattern"), -1); if (index == -1) { From c1f5380ed1777ebd717991832578a6847b320e10 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 26 Dec 2020 12:20:59 -0500 Subject: [PATCH 018/101] Add horse inventory support --- .../animal/horse/AbstractHorseEntity.java | 7 + .../animal/horse/ChestedHorseEntity.java | 3 + .../living/animal/horse/LlamaEntity.java | 4 +- .../connector/inventory/AnvilContainer.java | 6 +- .../connector/inventory/BeaconContainer.java | 5 +- .../connector/inventory/Container.java | 5 +- .../inventory/EnchantingContainer.java | 5 +- .../connector/inventory/FurnaceInventory.java | 5 +- .../connector/inventory/Inventory.java | 11 +- .../inventory/MerchantContainer.java | 5 +- .../connector/inventory/PlayerInventory.java | 2 +- .../network/session/GeyserSession.java | 4 + .../BedrockItemStackRequestTranslator.java | 2 +- .../player/BedrockInteractTranslator.java | 24 ++- .../inventory/InventoryTranslator.java | 8 +- .../translators/AnvilInventoryTranslator.java | 2 +- .../translators/BaseInventoryTranslator.java | 2 +- .../BeaconInventoryTranslator.java | 2 +- .../EnchantingInventoryTranslator.java | 2 +- .../translators/LoomInventoryTranslator.java | 1 + .../MerchantInventoryTranslator.java | 2 +- .../StonecutterInventoryTranslator.java | 1 + .../AbstractHorseInventoryTranslator.java | 66 +++++++++ .../ChestedHorseInventoryTranslator.java | 112 ++++++++++++++ .../horse/DonkeyInventoryTranslator.java | 32 ++++ .../horse/HorseInventoryTranslator.java | 52 +++++++ .../horse/LlamaInventoryTranslator.java | 32 ++++ .../updater/HorseInventoryUpdater.java | 69 +++++++++ .../inventory/updater/InventoryUpdater.java | 1 - .../window/JavaCloseWindowTranslator.java | 5 +- .../window/JavaOpenHorseWindowTranslator.java | 139 ++++++++++++++++++ .../java/window/JavaOpenWindowTranslator.java | 3 +- .../java/window/JavaSetSlotTranslator.java | 2 +- .../window/JavaWindowItemsTranslator.java | 3 +- .../window/JavaWindowPropertyTranslator.java | 2 +- .../connector/utils/InventoryUtils.java | 5 +- 36 files changed, 572 insertions(+), 59 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/AbstractHorseInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/ChestedHorseInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/DonkeyInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/HorseInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/LlamaInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/HorseInventoryUpdater.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenHorseWindowTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/AbstractHorseEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/AbstractHorseEntity.java index cf9f84b42..8913da0da 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/AbstractHorseEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/AbstractHorseEntity.java @@ -30,6 +30,7 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityEventType; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; import org.geysermc.connector.entity.living.animal.AnimalEntity; import org.geysermc.connector.entity.type.EntityType; @@ -40,6 +41,9 @@ public class AbstractHorseEntity extends AnimalEntity { public AbstractHorseEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); + + // Specifies the size of the entity's inventory. Required to place slots in the entity. + metadata.put(EntityData.CONTAINER_BASE_SIZE, 2); } @Override @@ -75,6 +79,9 @@ public class AbstractHorseEntity extends AnimalEntity { entityEventPacket.setData(ItemRegistry.WHEAT.getBedrockId() << 16); session.sendUpstreamPacket(entityEventPacket); } + + // Set container type if tamed + metadata.put(EntityData.CONTAINER_TYPE, ((xd & 0x02) == 0x02) ? (byte) ContainerType.HORSE.getId() : (byte) 0); } // Needed to control horses diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/ChestedHorseEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/ChestedHorseEntity.java index 7343f5e84..7b78aabb7 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/ChestedHorseEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/ChestedHorseEntity.java @@ -27,6 +27,7 @@ package org.geysermc.connector.entity.living.animal.horse; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -35,6 +36,8 @@ public class ChestedHorseEntity extends AbstractHorseEntity { public ChestedHorseEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); + + metadata.put(EntityData.CONTAINER_BASE_SIZE, 16); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/LlamaEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/LlamaEntity.java index ddac4a63f..d33624e20 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/LlamaEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/LlamaEntity.java @@ -38,6 +38,8 @@ public class LlamaEntity extends ChestedHorseEntity { public LlamaEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); + + metadata.put(EntityData.CONTAINER_STRENGTH_MODIFIER, 3); // Presumably 3 slots for every 1 strength } @Override @@ -56,7 +58,7 @@ public class LlamaEntity extends ChestedHorseEntity { // The damage value is the dye color that Java sends us // Always going to be a carpet so we can hardcode 171 in BlockTranslator // The int then short conversion is required or we get a ClassCastException - equipmentPacket.setChestplate(ItemData.of(BlockTranslator.CARPET, (short)((int) entityMetadata.getValue()), 1)); + equipmentPacket.setChestplate(ItemData.of(BlockTranslator.CARPET, (short) ((int) entityMetadata.getValue()), 1)); } else { equipmentPacket.setChestplate(ItemData.AIR); } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/AnvilContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/AnvilContainer.java index d940ac75b..0b6482f29 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/AnvilContainer.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/AnvilContainer.java @@ -25,10 +25,8 @@ package org.geysermc.connector.inventory; -import com.github.steveice10.mc.protocol.data.game.window.WindowType; - public class AnvilContainer extends Container { - public AnvilContainer(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) { - super(title, id, windowType, size, playerInventory); + public AnvilContainer(String title, int id, int size, PlayerInventory playerInventory) { + super(title, id, size, playerInventory); } } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/BeaconContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/BeaconContainer.java index 70ecd84f8..267565b8d 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/BeaconContainer.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/BeaconContainer.java @@ -25,7 +25,6 @@ package org.geysermc.connector.inventory; -import com.github.steveice10.mc.protocol.data.game.window.WindowType; import lombok.Getter; import lombok.Setter; @@ -35,7 +34,7 @@ public class BeaconContainer extends Container { private int primaryId; private int secondaryId; - public BeaconContainer(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) { - super(title, id, windowType, size, playerInventory); + public BeaconContainer(String title, int id,int size, PlayerInventory playerInventory) { + super(title, id, size, playerInventory); } } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Container.java b/connector/src/main/java/org/geysermc/connector/inventory/Container.java index acf450e14..eb1d9c3de 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Container.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Container.java @@ -25,7 +25,6 @@ package org.geysermc.connector.inventory; -import com.github.steveice10.mc.protocol.data.game.window.WindowType; import lombok.Getter; import lombok.NonNull; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; @@ -38,8 +37,8 @@ public class Container extends Inventory { private final PlayerInventory playerInventory; private final int containerSize; - public Container(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) { - super(title, id, windowType, size); + public Container(String title, int id, int size, PlayerInventory playerInventory) { + super(title, id, size); this.playerInventory = playerInventory; this.containerSize = this.size + InventoryTranslator.PLAYER_INVENTORY_SIZE; } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/EnchantingContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/EnchantingContainer.java index c8b2bef13..ab0e544d2 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/EnchantingContainer.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/EnchantingContainer.java @@ -25,7 +25,6 @@ package org.geysermc.connector.inventory; -import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.nukkitx.protocol.bedrock.data.inventory.EnchantOptionData; import lombok.Getter; @@ -41,8 +40,8 @@ public class EnchantingContainer extends Container { @Getter private final GeyserEnchantOption[] geyserEnchantOptions; - public EnchantingContainer(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) { - super(title, id, windowType, size, playerInventory); + public EnchantingContainer(String title, int id, int size, PlayerInventory playerInventory) { + super(title, id, size, playerInventory); enchantOptions = new EnchantOptionData[3]; geyserEnchantOptions = new GeyserEnchantOption[3]; diff --git a/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java index 0af76244d..6574374be 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java @@ -26,7 +26,6 @@ package org.geysermc.connector.inventory; -import com.github.steveice10.mc.protocol.data.game.window.WindowType; import lombok.Getter; import lombok.Setter; @@ -36,7 +35,7 @@ public class FurnaceInventory extends Inventory { @Setter private int test; - public FurnaceInventory(String title, int id, WindowType windowType, int size) { - super(title, id, windowType, size); + public FurnaceInventory(String title, int id, int size) { + super(title, id, size); } } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java index fed94b0bf..14d80c385 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java @@ -25,7 +25,6 @@ package org.geysermc.connector.inventory; -import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.nukkitx.math.vector.Vector3i; import lombok.Getter; import lombok.NonNull; @@ -38,9 +37,6 @@ public class Inventory { @Getter protected int id; - @Getter - protected WindowType windowType; - @Getter protected final int size; @@ -64,14 +60,13 @@ public class Inventory { @Getter protected short transactionId = 0; - protected Inventory(int id, WindowType windowType, int size) { - this("Inventory", id, windowType, size); + protected Inventory(int id, int size) { + this("Inventory", id, size); } - protected Inventory(String title, int id, WindowType windowType, int size) { + protected Inventory(String title, int id, int size) { this.title = title; this.id = id; - this.windowType = windowType; this.size = size; this.items = new GeyserItemStack[size]; Arrays.fill(items, GeyserItemStack.EMPTY); diff --git a/connector/src/main/java/org/geysermc/connector/inventory/MerchantContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/MerchantContainer.java index 03ae8ac3a..a33f81477 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/MerchantContainer.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/MerchantContainer.java @@ -27,7 +27,6 @@ package org.geysermc.connector.inventory; import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; -import com.github.steveice10.mc.protocol.data.game.window.WindowType; import lombok.Getter; import lombok.Setter; import org.geysermc.connector.entity.Entity; @@ -38,7 +37,7 @@ public class MerchantContainer extends Container { private Entity villager; private VillagerTrade[] villagerTrades; - public MerchantContainer(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) { - super(title, id, windowType, size, playerInventory); + public MerchantContainer(String title, int id, int size, PlayerInventory playerInventory) { + super(title, id, size, playerInventory); } } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java index e6aeb5cab..52066a806 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java @@ -45,7 +45,7 @@ public class PlayerInventory extends Inventory { private GeyserItemStack cursor = GeyserItemStack.EMPTY; public PlayerInventory() { - super(0, null, 46); + super(0, 46); heldItemSlot = 0; } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 880e87128..df2936303 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -83,6 +83,7 @@ import org.geysermc.connector.network.translators.EntityIdentifierRegistry; import org.geysermc.connector.network.translators.PacketTranslatorRegistry; import org.geysermc.connector.network.translators.chat.MessageTranslator; import org.geysermc.connector.network.translators.collision.CollisionManager; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.skin.SkinManager; import org.geysermc.connector.utils.*; @@ -123,6 +124,9 @@ public class GeyserSession implements CommandSender { @Setter private Inventory openInventory; + @Setter + private InventoryTranslator inventoryTranslator = InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR; + private final AtomicInteger itemNetId = new AtomicInteger(1); @Getter(AccessLevel.NONE) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java index 1ab68106e..65083ddef 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java @@ -43,7 +43,7 @@ public class BedrockItemStackRequestTranslator extends PacketTranslator translator.translateRequests(session, inventory, packet.getRequests())); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java index a2739cd8c..86f30c2fe 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java @@ -38,6 +38,7 @@ import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.InteractPacket; import lombok.Getter; import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.entity.living.animal.horse.AbstractHorseEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.network.session.GeyserSession; @@ -357,14 +358,23 @@ public class BedrockInteractTranslator extends PacketTranslator break; case OPEN_INVENTORY: if (session.getOpenInventory() == null) { - session.setOpenInventory(session.getPlayerInventory()); + Entity ridingEntity = session.getRidingVehicleEntity(); + if (ridingEntity instanceof AbstractHorseEntity) { + if (ridingEntity.getMetadata().getFlags().getFlag(EntityFlag.TAMED)) { + // We should request to open the horse inventory instead + ClientPlayerStatePacket openHorseWindowPacket = new ClientPlayerStatePacket((int)session.getPlayerEntity().getEntityId(), PlayerState.OPEN_HORSE_INVENTORY); + session.sendDownstreamPacket(openHorseWindowPacket); + } + } else { + session.setOpenInventory(session.getPlayerInventory()); - ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); - containerOpenPacket.setId((byte) 0); - containerOpenPacket.setType(ContainerType.INVENTORY); - containerOpenPacket.setUniqueEntityId(-1); - containerOpenPacket.setBlockPosition(entity.getPosition().toInt()); - session.sendUpstreamPacket(containerOpenPacket); + ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); + containerOpenPacket.setId((byte) 0); + containerOpenPacket.setType(ContainerType.INVENTORY); + containerOpenPacket.setUniqueEntityId(-1); + containerOpenPacket.setBlockPosition(entity.getPosition().toInt()); + session.sendUpstreamPacket(containerOpenPacket); + } } break; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index 3e5bf0c67..dc09d922a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -60,10 +60,11 @@ import java.util.*; @AllArgsConstructor public abstract class InventoryTranslator { + public static final InventoryTranslator PLAYER_INVENTORY_TRANSLATOR = new PlayerInventoryTranslator(); public static final Map INVENTORY_TRANSLATORS = new HashMap() { { /* Player Inventory */ - put(null, new PlayerInventoryTranslator()); //player inventory + put(null, PLAYER_INVENTORY_TRANSLATOR); /* Chest UIs */ put(WindowType.GENERIC_9X1, new SingleChestInventoryTranslator(9)); @@ -95,9 +96,6 @@ public abstract class InventoryTranslator { /* Generics */ put(WindowType.GENERIC_3X3, new GenericBlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER)); put(WindowType.HOPPER, new GenericBlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER)); - - /* todo */ - // horse } }; @@ -193,7 +191,7 @@ public abstract class InventoryTranslator { int sourceSlot = bedrockSlotToJava(transferAction.getSource()); int destSlot = bedrockSlotToJava(transferAction.getDestination()); - if (shouldRejectItemPlace(session, inventory, isCursor(transferAction.getSource()) ? -1 :sourceSlot, destSlot)) { + if (shouldRejectItemPlace(session, inventory, isCursor(transferAction.getSource()) ? -1 : sourceSlot, destSlot)) { // This item would not be here in Java return rejectRequest(request, false); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java index 27de329c6..d4684057c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java @@ -82,6 +82,6 @@ public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { @Override public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { - return new AnvilContainer(name, windowId, windowType, this.size, playerInventory); + return new AnvilContainer(name, windowId, this.size, playerInventory); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BaseInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BaseInventoryTranslator.java index 48d2ac109..32381d9ba 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BaseInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BaseInventoryTranslator.java @@ -96,6 +96,6 @@ public abstract class BaseInventoryTranslator extends InventoryTranslator { @Override public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { - return new Container(name, windowId, windowType, this.size, playerInventory); + return new Container(name, windowId, this.size, playerInventory); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java index 8ffc3e1a9..6407b9b39 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java @@ -129,6 +129,6 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator @Override public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { - return new BeaconContainer(name, windowId, windowType, this.size, playerInventory); + return new BeaconContainer(name, windowId, this.size, playerInventory); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java index c8ae8e2df..50e8ec6ac 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java @@ -170,7 +170,7 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla @Override public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { - return new EnchantingContainer(name, windowId, windowType, this.size, playerInventory); + return new EnchantingContainer(name, windowId, this.size, playerInventory); } /** diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java index 47f213799..31388700b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java @@ -143,6 +143,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), index); System.out.println(packet); session.sendDownstreamPacket(packet); + GeyserItemStack inputCopy = inventory.getItem(0).copy(); inputCopy.setNetId(session.getItemNetId().incrementAndGet()); // Add the pattern manually, for better item synchronization diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/MerchantInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/MerchantInventoryTranslator.java index 33a4e8240..c19a81be6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/MerchantInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/MerchantInventoryTranslator.java @@ -149,6 +149,6 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator { @Override public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { - return new MerchantContainer(name, windowId, windowType, this.size, playerInventory); + return new MerchantContainer(name, windowId, this.size, playerInventory); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java index 7bac3c650..42e09400c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java @@ -57,6 +57,7 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl @Override public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { // TODO: Also surely to change in the future + // TODO: don't spam the ClickWindowButtonPacket? StackRequestActionData data = request.getActions()[1]; if (!(data instanceof CraftResultsDeprecatedStackRequestActionData)) { return rejectRequest(request); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/AbstractHorseInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/AbstractHorseInventoryTranslator.java new file mode 100644 index 000000000..b33542d39 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/AbstractHorseInventoryTranslator.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators.horse; + +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.translators.BaseInventoryTranslator; +import org.geysermc.connector.network.translators.inventory.updater.HorseInventoryUpdater; +import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; + +public abstract class AbstractHorseInventoryTranslator extends BaseInventoryTranslator { + private final InventoryUpdater updater; + + public AbstractHorseInventoryTranslator(int size) { + super(size); + this.updater = HorseInventoryUpdater.INSTANCE; + } + + @Override + public void prepareInventory(GeyserSession session, Inventory inventory) { + + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + + } + + @Override + public void closeInventory(GeyserSession session, Inventory inventory) { + + } + + @Override + public void updateInventory(GeyserSession session, Inventory inventory) { + updater.updateInventory(this, session, inventory); + } + + @Override + public void updateSlot(GeyserSession session, Inventory inventory, int slot) { + updater.updateSlot(this, session, inventory, slot); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/ChestedHorseInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/ChestedHorseInventoryTranslator.java new file mode 100644 index 000000000..65fc9dd7e --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/ChestedHorseInventoryTranslator.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators.horse; + +import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; + +import java.util.Arrays; + +public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInventoryTranslator { + private final int chestSize; + private final int equipSlot; + + /** + * @param size the total Java size of the inventory + * @param equipSlot the Java equipment slot. For + */ + public ChestedHorseInventoryTranslator(int size, int equipSlot) { + super(size); + this.chestSize = size - 2; + this.equipSlot = equipSlot; + } + + @Override + public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { + if (slotInfoData.getContainer() == ContainerSlotType.HORSE_EQUIP) { + return this.equipSlot; + } + if (slotInfoData.getContainer() == ContainerSlotType.CONTAINER) { + return slotInfoData.getSlot() + 1; + } + return super.bedrockSlotToJava(slotInfoData); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + if (slot == this.equipSlot) { + return new BedrockContainerSlot(ContainerSlotType.HORSE_EQUIP, 0); + } + if (slot <= this.size) { + return new BedrockContainerSlot(ContainerSlotType.CONTAINER, slot - 1); + } + return super.javaSlotToBedrockContainer(slot); + } + + @Override + public int javaSlotToBedrock(int slot) { + if (slot == 0 && this.equipSlot == 0) { + return 0; + } + if (slot <= this.size) { + return slot - 1; + } + return super.javaSlotToBedrock(slot); + } + + @Override + public void updateInventory(GeyserSession session, Inventory inventory) { + ItemData[] bedrockItems = new ItemData[36]; + for (int i = 0; i < 36; i++) { + final int offset = i < 9 ? 27 : -9; + bedrockItems[i] = inventory.getItem(this.size + i + offset).getItemData(session); + } + InventoryContentPacket contentPacket = new InventoryContentPacket(); + contentPacket.setContainerId(ContainerId.INVENTORY); + contentPacket.setContents(Arrays.asList(bedrockItems)); + session.sendUpstreamPacket(contentPacket); + + ItemData[] horseItems = new ItemData[chestSize + 1]; + // Manually specify the first slot - Java always has two slots (armor and saddle) and one is invisible. + // Bedrock doesn't have this invisible slot. + horseItems[0] = inventory.getItem(this.equipSlot).getItemData(session); + for (int i = 1; i < horseItems.length; i++) { + horseItems[i] = inventory.getItem(i + 1).getItemData(session); + } + + InventoryContentPacket llamaPacket = new InventoryContentPacket(); + llamaPacket.setContainerId(inventory.getId()); + llamaPacket.setContents(Arrays.asList(horseItems)); + System.out.println(llamaPacket); + session.sendUpstreamPacket(llamaPacket); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/DonkeyInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/DonkeyInventoryTranslator.java new file mode 100644 index 000000000..61a8d6926 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/DonkeyInventoryTranslator.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators.horse; + +public class DonkeyInventoryTranslator extends ChestedHorseInventoryTranslator { + public DonkeyInventoryTranslator(int size) { + super(size, 0); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/HorseInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/HorseInventoryTranslator.java new file mode 100644 index 000000000..957933a02 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/HorseInventoryTranslator.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators.horse; + +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; + +public class HorseInventoryTranslator extends AbstractHorseInventoryTranslator { + public HorseInventoryTranslator(int size) { + super(size); + } + + @Override + public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { + if (slotInfoData.getContainer() == ContainerSlotType.HORSE_EQUIP) { + return slotInfoData.getSlot(); + } + return super.bedrockSlotToJava(slotInfoData); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { + if (slot == 0 || slot == 1) { + return new BedrockContainerSlot(ContainerSlotType.HORSE_EQUIP, slot); + } + return super.javaSlotToBedrockContainer(slot); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/LlamaInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/LlamaInventoryTranslator.java new file mode 100644 index 000000000..523a1d3e7 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/LlamaInventoryTranslator.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators.horse; + +public class LlamaInventoryTranslator extends ChestedHorseInventoryTranslator { + public LlamaInventoryTranslator(int size) { + super(size, 1); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/HorseInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/HorseInventoryUpdater.java new file mode 100644 index 000000000..2f88c49cd --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/HorseInventoryUpdater.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.updater; + +import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; +import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; + +import java.util.Arrays; + +public class HorseInventoryUpdater extends InventoryUpdater { + public static final HorseInventoryUpdater INSTANCE = new HorseInventoryUpdater(); + + @Override + public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { + super.updateInventory(translator, session, inventory); + + ItemData[] bedrockItems = new ItemData[translator.size]; + for (int i = 0; i < bedrockItems.length; i++) { + bedrockItems[translator.javaSlotToBedrock(i)] = inventory.getItem(i).getItemData(session); + } + + InventoryContentPacket contentPacket = new InventoryContentPacket(); + contentPacket.setContainerId(inventory.getId()); + contentPacket.setContents(Arrays.asList(bedrockItems)); + session.sendUpstreamPacket(contentPacket); + } + + @Override + public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) { + if (super.updateSlot(translator, session, inventory, javaSlot)) + return true; + + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(4); // Horse GUI? + slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); + slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); + session.sendUpstreamPacket(slotPacket); + System.out.println(slotPacket); + return true; + } + +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java index e7d14f13a..d4026a23b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java @@ -32,7 +32,6 @@ import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; -import org.geysermc.connector.network.translators.item.ItemTranslator; import java.util.Arrays; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java index 68f1dda91..e84fd4380 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java @@ -26,7 +26,6 @@ package org.geysermc.connector.network.translators.java.window; import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerCloseWindowPacket; -import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; @@ -37,8 +36,6 @@ public class JavaCloseWindowTranslator extends PacketTranslator { - InventoryUtils.closeInventory(session, packet.getWindowId()); - }); + session.addInventoryTask(() -> InventoryUtils.closeInventory(session, packet.getWindowId())); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenHorseWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenHorseWindowTranslator.java new file mode 100644 index 000000000..3d205d2a9 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenHorseWindowTranslator.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2019-2020 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.translators.java.window; + +import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerOpenHorseWindowPacket; +import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.NbtType; +import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.packet.UpdateEquipPacket; +import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.entity.living.animal.horse.ChestedHorseEntity; +import org.geysermc.connector.entity.living.animal.horse.LlamaEntity; +import org.geysermc.connector.inventory.Container; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.Translator; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.network.translators.inventory.translators.horse.DonkeyInventoryTranslator; +import org.geysermc.connector.network.translators.inventory.translators.horse.HorseInventoryTranslator; +import org.geysermc.connector.network.translators.inventory.translators.horse.LlamaInventoryTranslator; +import org.geysermc.connector.utils.InventoryUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Translator(packet = ServerOpenHorseWindowPacket.class) +public class JavaOpenHorseWindowTranslator extends PacketTranslator { + + private static final NbtMap ARMOR_SLOT; + private static final NbtMap CARPET_SLOT; + private static final NbtMap SADDLE_SLOT; + + static { + // Build the NBT mappings that Bedrock wants to lay out the GUI + String[] acceptedHorseArmorIdentifiers = new String[] {"minecraft:horsearmorleather", "minecraft:horsearmoriron", + "minecraft:horsearmorgold", "minecraft:horsearmordiamond"}; + NbtMapBuilder armorBuilder = NbtMap.builder(); + List acceptedArmors = new ArrayList<>(); + for (String identifier : acceptedHorseArmorIdentifiers) { + NbtMapBuilder acceptedItemBuilder = NbtMap.builder() + .putShort("Aux", Short.MAX_VALUE) + .putString("Name", identifier); + acceptedArmors.add(NbtMap.builder().putCompound("slotItem", acceptedItemBuilder.build()).build()); + } + armorBuilder.putList("acceptedItems", NbtType.COMPOUND, acceptedArmors); + NbtMapBuilder armorItem = NbtMap.builder() + .putShort("Aux", Short.MAX_VALUE) + .putString("Name", "minecraft:horsearmoriron"); + armorBuilder.putCompound("item", armorItem.build()); + armorBuilder.putInt("slotNumber", 1); + ARMOR_SLOT = armorBuilder.build(); + + NbtMapBuilder carpetBuilder = NbtMap.builder(); + NbtMapBuilder carpetItem = NbtMap.builder() + .putShort("Aux", Short.MAX_VALUE) + .putString("Name", "minecraft:carpet"); + List acceptedCarpet = Collections.singletonList(NbtMap.builder().putCompound("slotItem", carpetItem.build()).build()); + carpetBuilder.putList("acceptedItems", NbtType.COMPOUND, acceptedCarpet); + carpetBuilder.putCompound("item", carpetItem.build()); + carpetBuilder.putInt("slotNumber", 1); + CARPET_SLOT = carpetBuilder.build(); + + NbtMapBuilder saddleBuilder = NbtMap.builder(); + NbtMapBuilder acceptedSaddle = NbtMap.builder() + .putShort("Aux", Short.MAX_VALUE) + .putString("Name", "minecraft:saddle"); + List acceptedItem = Collections.singletonList(NbtMap.builder().putCompound("slotItem", acceptedSaddle.build()).build()); + saddleBuilder.putList("acceptedItems", NbtType.COMPOUND, acceptedItem); + saddleBuilder.putCompound("item", acceptedSaddle.build()); + saddleBuilder.putInt("slotNumber", 0); + SADDLE_SLOT = saddleBuilder.build(); + } + + @Override + public void translate(ServerOpenHorseWindowPacket packet, GeyserSession session) { + System.out.println(packet.toString()); + Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); + if (entity == null) { + return; + } + + UpdateEquipPacket updateEquipPacket = new UpdateEquipPacket(); + updateEquipPacket.setWindowId((short) packet.getWindowId()); + updateEquipPacket.setWindowType((short) ContainerType.HORSE.getId()); + updateEquipPacket.setUniqueEntityId(entity.getGeyserId()); + + NbtMapBuilder builder = NbtMap.builder(); + List slots = new ArrayList<>(); + + InventoryTranslator inventoryTranslator; + if (entity instanceof LlamaEntity) { + inventoryTranslator = new LlamaInventoryTranslator(packet.getNumberOfSlots()); + slots.add(CARPET_SLOT); + } else if (entity instanceof ChestedHorseEntity) { + inventoryTranslator = new DonkeyInventoryTranslator(packet.getNumberOfSlots()); + slots.add(SADDLE_SLOT); + } else { + inventoryTranslator = new HorseInventoryTranslator(packet.getNumberOfSlots()); + slots.add(SADDLE_SLOT); + slots.add(ARMOR_SLOT); + } + + // Build the NbtMap that sets the icons for Bedrock (e.g. sets the saddle outline on the saddle slot) + builder.putList("slots", NbtType.COMPOUND, slots); + + updateEquipPacket.setTag(builder.build()); + System.out.println(updateEquipPacket); + session.sendUpstreamPacket(updateEquipPacket); + + session.setInventoryTranslator(inventoryTranslator); + InventoryUtils.openInventory(session, new Container(entity.getMetadata().getString(EntityData.NAMETAG), packet.getWindowId(), packet.getNumberOfSlots(), session.getPlayerInventory())); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java index 89982dbb7..d32014280 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java @@ -63,12 +63,13 @@ public class JavaOpenWindowTranslator extends PacketTranslator if (inventory == null) return; - InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()); + InventoryTranslator translator = session.getInventoryTranslator(); if (translator != null) { GeyserItemStack newItem = GeyserItemStack.from(packet.getItem()); GeyserItemStack oldItem = inventory.getItem(packet.getSlot()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java index 26aab47b3..7e88f067d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java @@ -26,7 +26,6 @@ package org.geysermc.connector.network.translators.java.window; import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerWindowItemsPacket; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; @@ -56,7 +55,7 @@ public class JavaWindowItemsTranslator extends PacketTranslator Date: Sat, 26 Dec 2020 13:24:50 -0500 Subject: [PATCH 019/101] Fix offset issue --- .../translators/horse/ChestedHorseInventoryTranslator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/ChestedHorseInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/ChestedHorseInventoryTranslator.java index 65fc9dd7e..2450f18de 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/ChestedHorseInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/ChestedHorseInventoryTranslator.java @@ -66,7 +66,7 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven if (slot == this.equipSlot) { return new BedrockContainerSlot(ContainerSlotType.HORSE_EQUIP, 0); } - if (slot <= this.size) { + if (slot <= this.size - 1) { // Accommodate for the lack of one slot (saddle or armor) return new BedrockContainerSlot(ContainerSlotType.CONTAINER, slot - 1); } return super.javaSlotToBedrockContainer(slot); @@ -77,7 +77,7 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven if (slot == 0 && this.equipSlot == 0) { return 0; } - if (slot <= this.size) { + if (slot <= this.size - 1) { return slot - 1; } return super.javaSlotToBedrock(slot); From 078af592491f2c0580030c63b8b11a1c73cfecf3 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 26 Dec 2020 16:41:50 -0500 Subject: [PATCH 020/101] Streamline Item Net ID getting; cartography table finished --- .../connector/inventory/GeyserEnchantOption.java | 2 +- .../connector/network/session/GeyserSession.java | 13 +++++++++++-- .../bedrock/BedrockFilterTextTranslator.java | 2 +- .../translators/inventory/InventoryTranslator.java | 11 ++++++----- .../translators/CartographyInventoryTranslator.java | 9 ++++++--- .../translators/LoomInventoryTranslator.java | 5 ++--- .../translators/StonecutterInventoryTranslator.java | 2 +- .../horse/ChestedHorseInventoryTranslator.java | 13 +++++++------ .../network/translators/item/RecipeRegistry.java | 11 +++++++++++ .../java/JavaDeclareRecipesTranslator.java | 3 +++ .../java/window/JavaSetSlotTranslator.java | 4 ++-- .../java/window/JavaWindowItemsTranslator.java | 2 +- 12 files changed, 52 insertions(+), 25 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/inventory/GeyserEnchantOption.java b/connector/src/main/java/org/geysermc/connector/inventory/GeyserEnchantOption.java index ea58372e2..ae4a9cf4e 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/GeyserEnchantOption.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/GeyserEnchantOption.java @@ -73,6 +73,6 @@ public class GeyserEnchantOption { } return new EnchantOptionData(xpCost, javaIndex + 16, EMPTY, Collections.singletonList(new EnchantData(bedrockEnchantIndex, enchantLevel)), EMPTY, - javaEnchantIndex == -1 ? "unknown" : ENCHANT_NAMES.get(javaEnchantIndex), session.getItemNetId().incrementAndGet()); + javaEnchantIndex == -1 ? "unknown" : ENCHANT_NAMES.get(javaEnchantIndex), session.getNextItemNetId()); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index df2936303..bbbdf99c9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -127,6 +127,10 @@ public class GeyserSession implements CommandSender { @Setter private InventoryTranslator inventoryTranslator = InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR; + /** + * Use {@link #getNextItemNetId()} instead for consistency + */ + @Getter(AccessLevel.NONE) private final AtomicInteger itemNetId = new AtomicInteger(1); @Getter(AccessLevel.NONE) @@ -727,12 +731,10 @@ public class GeyserSession implements CommandSender { startGamePacket.setLevelName(serverName); startGamePacket.setPremiumWorldTemplateId("00000000-0000-0000-0000-000000000000"); - // startGamePacket.setCurrentTick(0); startGamePacket.setEnchantmentSeed(0); startGamePacket.setMultiplayerCorrelationId(""); startGamePacket.setItemEntries(ItemRegistry.ITEMS); startGamePacket.setVanillaVersion("*"); - // startGamePacket.setMovementServerAuthoritative(true); startGamePacket.setInventoriesServerAuthoritative(true); startGamePacket.setAuthoritativeMovementMode(AuthoritativeMovementMode.CLIENT); upstream.sendPacket(startGamePacket); @@ -773,6 +775,13 @@ public class GeyserSession implements CommandSender { } } + /** + * @return the next Bedrock item network ID to use for a new item + */ + public int getNextItemNetId() { + return itemNetId.getAndIncrement(); + } + public void addTeleport(TeleportCache teleportCache) { teleportMap.put(teleportCache.getTeleportConfirmId(), teleportCache); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java index cf06acf58..438be6b0b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java @@ -40,7 +40,7 @@ public class BedrockFilterTextTranslator extends PacketTranslator TIPPED_ARROW_RECIPES = new ObjectArrayList<>(); + /** + * Recipe data that, when sent to the client, enables cartography features. + * This does not have a Java equivalent. + */ + public static final List CARTOGRAPHY_RECIPE_DATA = new ObjectArrayList<>(); + /** * Recipe data that, when sent to the client, enables book cloning */ @@ -108,6 +114,11 @@ public class RecipeRegistry { MAP_EXTENDING_RECIPE_DATA = CraftingData.fromMulti(UUID.fromString("d392b075-4ba1-40ae-8789-af868d56f6ce"), LAST_RECIPE_NET_ID++); MAP_CLONING_RECIPE_DATA = CraftingData.fromMulti(UUID.fromString("85939755-ba10-4d9d-a4cc-efb7a8e943c4"), LAST_RECIPE_NET_ID++); BANNER_DUPLICATING_RECIPE_DATA = CraftingData.fromMulti(UUID.fromString("b5c5d105-75a2-4076-af2b-923ea2bf4bf0"), LAST_RECIPE_NET_ID++); + + CARTOGRAPHY_RECIPE_DATA.add(CraftingData.fromMulti(UUID.fromString("8b36268c-1829-483c-a0f1-993b7156a8f2"), LAST_RECIPE_NET_ID++)); // Map extending + CARTOGRAPHY_RECIPE_DATA.add(CraftingData.fromMulti(UUID.fromString("442d85ed-8272-4543-a6f1-418f90ded05d"), LAST_RECIPE_NET_ID++)); // Map cloning + CARTOGRAPHY_RECIPE_DATA.add(CraftingData.fromMulti(UUID.fromString("98c84b38-1085-46bd-b1ce-dd38c159e6cc"), LAST_RECIPE_NET_ID++)); // Map upgrading + CARTOGRAPHY_RECIPE_DATA.add(CraftingData.fromMulti(UUID.fromString("602234e4-cac1-4353-8bb7-b1ebff70024b"), LAST_RECIPE_NET_ID++)); // Map locking // https://github.com/pmmp/PocketMine-MP/blob/stable/src/pocketmine/inventory/MultiRecipe.php // Get all recipes that are not directly sent from a Java server diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java index e74a82324..0c459133f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -149,6 +149,9 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator stonecutterRecipeMap = new Int2ObjectOpenHashMap<>(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java index 11dc7a48a..5d311fe3d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java @@ -47,7 +47,7 @@ public class JavaSetSlotTranslator extends PacketTranslator if (newItem.getItemData(session).equals(oldItem.getItemData(session))) { newItem.setNetId(oldItem.getNetId()); } else { - newItem.setNetId(session.getItemNetId().getAndIncrement()); + newItem.setNetId(session.getNextItemNetId()); } session.getPlayerInventory().setCursor(newItem); InventoryUtils.updateCursor(session); @@ -67,7 +67,7 @@ public class JavaSetSlotTranslator extends PacketTranslator newItem.setNetId(oldItem.getNetId()); System.out.println("OLD: " + newItem.getNetId()); } else { - newItem.setNetId(session.getItemNetId().getAndIncrement()); + newItem.setNetId(session.getNextItemNetId()); System.out.println("NEW: " + newItem.getNetId()); } inventory.setItem(packet.getSlot(), newItem); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java index 7e88f067d..b87f1de80 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java @@ -50,7 +50,7 @@ public class JavaWindowItemsTranslator extends PacketTranslator Date: Sat, 26 Dec 2020 19:16:35 -0500 Subject: [PATCH 021/101] Cleanup and delete FilterTextPacket - PRing to the main branch --- .../connector/inventory/BeaconContainer.java | 2 +- .../bedrock/BedrockFilterTextTranslator.java | 47 ------------------- .../item/translators/BannerTranslator.java | 2 - 3 files changed, 1 insertion(+), 50 deletions(-) delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/inventory/BeaconContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/BeaconContainer.java index 267565b8d..768a49662 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/BeaconContainer.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/BeaconContainer.java @@ -34,7 +34,7 @@ public class BeaconContainer extends Container { private int primaryId; private int secondaryId; - public BeaconContainer(String title, int id,int size, PlayerInventory playerInventory) { + public BeaconContainer(String title, int id, int size, PlayerInventory playerInventory) { super(title, id, size, playerInventory); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java deleted file mode 100644 index 438be6b0b..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2019-2020 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.translators.bedrock; - -import com.nukkitx.protocol.bedrock.packet.FilterTextPacket; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; - -/** - * Used to send strings to the client and filter out unwanted words. - * Java doesn't care, so we don't care, and we approve all strings. - */ -@Translator(packet = FilterTextPacket.class) -public class BedrockFilterTextTranslator extends PacketTranslator { - - @Override - public void translate(FilterTextPacket packet, GeyserSession session) { - // TODO: Bedrock doesn't send this. Why? - session.getConnector().getLogger().error(packet.toString()); - packet.setFromServer(true); - session.sendUpstreamPacket(packet); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java index 1870a1279..d5f5c6103 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java @@ -32,7 +32,6 @@ import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtType; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; -import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.translators.ItemRemapper; import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.ItemRegistry; @@ -182,7 +181,6 @@ public class BannerTranslator extends ItemTranslator { @Override public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { - GeyserConnector.getInstance().getLogger().warning(itemEntry.toString()); if (itemData.getTag() == null) { return super.translateToJava(itemData, itemEntry); } From 60da3b94320d4e751837e487f40b21a2eabb7ef4 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sat, 26 Dec 2020 18:44:48 -0900 Subject: [PATCH 022/101] Temp slot --- .../inventory/InventoryTranslator.java | 88 +++++++++++++++++-- 1 file changed, 79 insertions(+), 9 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index dc36ed177..3a201cdcd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -300,17 +300,33 @@ public abstract class InventoryTranslator { if (!InventoryUtils.canStack(cursor, plan.getItem(sourceSlot))) { //doesn't make sense, reject return rejectRequest(request); } - if (transferAction.getCount() != sourceAmount) { //TODO: handle partially picking up into non-empty cursor (temp slot) - return rejectRequest(request); + if (transferAction.getCount() != sourceAmount) { + int tempSlot = findTempSlot(inventory, cursor, false, sourceSlot); + if (tempSlot == -1) { + return rejectRequest(request); + } + plan.add(Click.LEFT, tempSlot); //place cursor into temp slot + plan.add(Click.LEFT, sourceSlot); //pickup source items into cursor + for (int i = 0; i < transferAction.getCount(); i++) { + plan.add(Click.RIGHT, tempSlot); //partially transfer source items into temp slot (original cursor) + } + plan.add(Click.LEFT, sourceSlot); //return remaining source items + plan.add(Click.LEFT, tempSlot); //retrieve original cursor items from temp slot + } else { + if (getSlotType(sourceSlot).equals(SlotType.NORMAL)) { + plan.add(Click.LEFT, sourceSlot); //release cursor onto source slot + } + plan.add(Click.LEFT, sourceSlot); //pickup combined cursor and source } - if (getSlotType(sourceSlot).equals(SlotType.NORMAL)) { - plan.add(Click.LEFT, sourceSlot); //release cursor onto source slot - } - plan.add(Click.LEFT, sourceSlot); //pickup combined cursor and source } } else { //transfer from one slot to another - if (!cursor.isEmpty()) { //TODO: handle slot transfer when cursor is already in use (temp slot) - return rejectRequest(request); + int tempSlot = -1; + if (!cursor.isEmpty()) { + tempSlot = findTempSlot(inventory, cursor, false, sourceSlot, destSlot); + if (tempSlot == -1) { + return rejectRequest(request); + } + plan.add(Click.LEFT, tempSlot); //place cursor into temp slot } int sourceAmount = plan.getItem(sourceSlot).getAmount(); if (transferAction.getCount() == sourceAmount) { //transfer all @@ -318,7 +334,7 @@ public abstract class InventoryTranslator { plan.add(Click.LEFT, destSlot); //let go of all items and done } else { //transfer some //try to transfer items with least clicks possible - int halfSource = sourceAmount / 2; //smaller half + int halfSource = sourceAmount - (sourceAmount / 2); //larger half int holding; if (transferAction.getCount() <= halfSource) { //faster to take only half plan.add(Click.RIGHT, sourceSlot); @@ -339,6 +355,9 @@ public abstract class InventoryTranslator { plan.add(Click.LEFT, sourceSlot); //return extra items to source slot } } + if (tempSlot != -1) { + plan.add(Click.LEFT, tempSlot); //retrieve original cursor + } } break; } @@ -724,11 +743,62 @@ public abstract class InventoryTranslator { public boolean checkNetId(GeyserSession session, Inventory inventory, StackRequestSlotInfoData slotInfoData) { if (slotInfoData.getStackNetworkId() < 0) return true; + if (slotInfoData.getContainer() == ContainerSlotType.CURSOR) //TODO: temporary + return true; GeyserItemStack currentItem = isCursor(slotInfoData) ? session.getPlayerInventory().getCursor() : inventory.getItem(bedrockSlotToJava(slotInfoData)); return currentItem.getNetId() == slotInfoData.getStackNetworkId(); } + /** + * Try to find a slot that can temporarily store the given item. + * Only looks in the main inventory and hotbar (excluding offhand). + * Only slots that are empty or contain a different type of item are valid. + * + * @return java id for the temporary slot, or -1 if no viable slot was found + */ + //TODO: compatibility for simulated inventory (ClickPlan) + private static int findTempSlot(Inventory inventory, GeyserItemStack item, boolean emptyOnly, int... slotBlacklist) { + int offset = inventory.getId() == 0 ? 1 : 0; //offhand is not a viable temp slot + HashSet itemBlacklist = new HashSet<>(slotBlacklist.length + 1); + itemBlacklist.add(item); + + IntSet potentialSlots = new IntOpenHashSet(36); + for (int i = inventory.getSize() - (36 + offset); i < inventory.getSize() - offset; i++) { + potentialSlots.add(i); + } + for (int i : slotBlacklist) { + potentialSlots.remove(i); + GeyserItemStack blacklistedItem = inventory.getItem(i); + if (!blacklistedItem.isEmpty()) { + itemBlacklist.add(blacklistedItem); + } + } + + for (int i : potentialSlots) { + GeyserItemStack testItem = inventory.getItem(i); + if ((emptyOnly && !testItem.isEmpty())) { + continue; + } + + boolean viable = true; + for (GeyserItemStack blacklistedItem : itemBlacklist) { + if (InventoryUtils.canStack(testItem, blacklistedItem)) { + viable = false; + break; + } + } + if (!viable) { + continue; + } + + System.out.println("TEMP SLOT CHOSEN: " + i + " => " + inventory.getItem(i)); + return i; + } + //could not find a viable temp slot + return -1; + } + public List makeContainerEntries(GeyserSession session, Inventory inventory, Set affectedSlots) { Map> containerMap = new HashMap<>(); for (int slot : affectedSlots) { From 956d264c3e68e8cb29281df29eb5bd59961615bb Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 26 Dec 2020 22:55:14 -0500 Subject: [PATCH 023/101] Anvil renaming works; other things --- .../connector/inventory/AnvilContainer.java | 3 ++ .../inventory/CartographyContainer.java | 32 +++++++++++++++++++ .../bedrock/BedrockFilterTextTranslator.java | 14 ++++++++ .../inventory/InventoryTranslator.java | 20 +++++++++++- .../CartographyInventoryTranslator.java | 13 +++++--- 5 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/inventory/CartographyContainer.java diff --git a/connector/src/main/java/org/geysermc/connector/inventory/AnvilContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/AnvilContainer.java index 0b6482f29..aba360a0d 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/AnvilContainer.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/AnvilContainer.java @@ -25,6 +25,9 @@ package org.geysermc.connector.inventory; +/** + * Used to determine if rename packets should be sent. + */ public class AnvilContainer extends Container { public AnvilContainer(String title, int id, int size, PlayerInventory playerInventory) { super(title, id, size, playerInventory); diff --git a/connector/src/main/java/org/geysermc/connector/inventory/CartographyContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/CartographyContainer.java new file mode 100644 index 000000000..7e6d1cc79 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/inventory/CartographyContainer.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019-2020 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.inventory; + +public class CartographyContainer extends Container { + public CartographyContainer(String title, int id, int size, PlayerInventory playerInventory) { + super(title, id, size, playerInventory); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java index 8c9630764..a7400ff03 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java @@ -25,7 +25,10 @@ package org.geysermc.connector.network.translators.bedrock; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientRenameItemPacket; import com.nukkitx.protocol.bedrock.packet.FilterTextPacket; +import org.geysermc.connector.inventory.AnvilContainer; +import org.geysermc.connector.inventory.CartographyContainer; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; @@ -39,7 +42,18 @@ public class BedrockFilterTextTranslator extends PacketTranslator Date: Sun, 27 Dec 2020 11:08:48 -0500 Subject: [PATCH 024/101] Add TODO --- .../network/translators/inventory/InventoryTranslator.java | 1 + 1 file changed, 1 insertion(+) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index b960f09e2..95516dc26 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -462,6 +462,7 @@ public abstract class InventoryTranslator { } case DESTROY: { // Only called when a creative client wants to destroy an item... I think - Camotoy + //TODO there is a Count here we don't use DestroyStackRequestActionData destroyAction = (DestroyStackRequestActionData) action; if (!session.getGameMode().equals(GameMode.CREATIVE)) { // If this happens, let's throw an error and figure out why. From 2265de3ae90132148aecaa48a5547f4a7f08a2eb Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 28 Dec 2020 00:29:27 -0500 Subject: [PATCH 025/101] lecterns --- .../platform/spigot/GeyserSpigotPlugin.java | 10 +- .../GeyserSpigot1_12NativeWorldManager.java | 4 +- .../manager/GeyserSpigot1_12WorldManager.java | 5 +- .../GeyserSpigotFallbackWorldManager.java | 5 +- .../GeyserSpigotLegacyNativeWorldManager.java | 2 +- .../GeyserSpigotNativeWorldManager.java | 5 +- .../manager/GeyserSpigotWorldManager.java | 70 +++++++- .../connector/inventory/LecternContainer.java | 44 +++++ .../network/session/GeyserSession.java | 10 ++ .../BedrockContainerCloseTranslator.java | 2 +- .../BedrockLecternUpdateTranslator.java | 95 +++++++++++ .../inventory/InventoryTranslator.java | 3 + .../LecternInventoryTranslator.java | 159 ++++++++++++++++++ .../java/world/JavaUnloadChunkTranslator.java | 11 +- .../translators/world/GeyserWorldManager.java | 26 +++ .../translators/world/WorldManager.java | 27 +++ .../world/block/BlockStateValues.java | 10 ++ .../geysermc/connector/utils/ChunkUtils.java | 33 +++- .../connector/utils/DimensionUtils.java | 1 + 19 files changed, 502 insertions(+), 20 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/inventory/LecternContainer.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockLecternUpdateTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java index 39d4f993b..c63c65d38 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java @@ -157,14 +157,14 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { if (isViaVersion && isViaVersionNeeded()) { if (isLegacy) { // Pre-1.13 - this.geyserWorldManager = new GeyserSpigot1_12NativeWorldManager(); + this.geyserWorldManager = new GeyserSpigot1_12NativeWorldManager(this); } else { // Post-1.13 this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this, use3dBiomes); } } else { // No ViaVersion - this.geyserWorldManager = new GeyserSpigotNativeWorldManager(use3dBiomes); + this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this, use3dBiomes); } geyserLogger.debug("Using NMS adapter: " + this.geyserWorldManager.getClass() + ", " + nmsVersion); } catch (Exception e) { @@ -180,13 +180,13 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { // No NMS adapter if (isLegacy && isViaVersion) { // Use ViaVersion for converting pre-1.13 block states - this.geyserWorldManager = new GeyserSpigot1_12WorldManager(); + this.geyserWorldManager = new GeyserSpigot1_12WorldManager(this); } else if (isLegacy) { // Not sure how this happens - without ViaVersion, we don't know any block states, so just assume everything is air - this.geyserWorldManager = new GeyserSpigotFallbackWorldManager(); + this.geyserWorldManager = new GeyserSpigotFallbackWorldManager(this); } else { // Post-1.13 - this.geyserWorldManager = new GeyserSpigotWorldManager(use3dBiomes); + this.geyserWorldManager = new GeyserSpigotWorldManager(this, use3dBiomes); } geyserLogger.debug("Using default world manager: " + this.geyserWorldManager.getClass()); } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java index f58b75cdd..67e114c47 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java @@ -27,6 +27,7 @@ package org.geysermc.platform.spigot.world.manager; import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; import org.geysermc.adapters.spigot.SpigotAdapters; import org.geysermc.adapters.spigot.SpigotWorldAdapter; import org.geysermc.connector.network.session.GeyserSession; @@ -40,7 +41,8 @@ import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.storage.BlockStorage; public class GeyserSpigot1_12NativeWorldManager extends GeyserSpigot1_12WorldManager { private final SpigotWorldAdapter adapter; - public GeyserSpigot1_12NativeWorldManager() { + public GeyserSpigot1_12NativeWorldManager(Plugin plugin) { + super(plugin); this.adapter = SpigotAdapters.getWorldAdapter(); // Unlike post-1.13, we can't build up a cache of block states, because block entities need some special conversion } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java index b00ddafaa..881dece24 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java @@ -30,6 +30,7 @@ import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockTranslator; import us.myles.ViaVersion.api.Pair; @@ -61,8 +62,8 @@ public class GeyserSpigot1_12WorldManager extends GeyserSpigotWorldManager { */ private final List> protocolList; - public GeyserSpigot1_12WorldManager() { - super(false); + public GeyserSpigot1_12WorldManager(Plugin plugin) { + super(plugin, false); this.mappingData1_12to1_13 = ProtocolRegistry.getProtocol(Protocol1_13To1_12_2.class).getMappingData(); this.protocolList = ProtocolRegistry.getProtocolPath(CLIENT_PROTOCOL_VERSION, ProtocolVersion.v1_13.getVersion()); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java index 49c675a1d..dc0146baa 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java @@ -26,6 +26,7 @@ package org.geysermc.platform.spigot.world.manager; import com.github.steveice10.mc.protocol.data.game.chunk.Chunk; +import org.bukkit.plugin.Plugin; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockTranslator; @@ -35,9 +36,9 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator; * If this occurs to you somehow, please let us know!! */ public class GeyserSpigotFallbackWorldManager extends GeyserSpigotWorldManager { - public GeyserSpigotFallbackWorldManager() { + public GeyserSpigotFallbackWorldManager(Plugin plugin) { // Since this is pre-1.13 (and thus pre-1.15), there will never be 3D biomes. - super(false); + super(plugin, false); } @Override diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java index dec9b4141..376df3fd1 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java @@ -47,7 +47,7 @@ public class GeyserSpigotLegacyNativeWorldManager extends GeyserSpigotNativeWorl private final Int2IntMap oldToNewBlockId; public GeyserSpigotLegacyNativeWorldManager(GeyserSpigotPlugin plugin, boolean use3dBiomes) { - super(use3dBiomes); + super(plugin, use3dBiomes); IntList allBlockStates = adapter.getAllBlockStates(); oldToNewBlockId = new Int2IntOpenHashMap(allBlockStates.size()); ProtocolVersion serverVersion = plugin.getServerProtocolVersion(); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java index f703ecdb5..a23fc7b53 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java @@ -27,6 +27,7 @@ package org.geysermc.platform.spigot.world.manager; import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; import org.geysermc.adapters.spigot.SpigotAdapters; import org.geysermc.adapters.spigot.SpigotWorldAdapter; import org.geysermc.connector.network.session.GeyserSession; @@ -35,8 +36,8 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator; public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager { protected final SpigotWorldAdapter adapter; - public GeyserSpigotNativeWorldManager(boolean use3dBiomes) { - super(use3dBiomes); + public GeyserSpigotNativeWorldManager(Plugin plugin, boolean use3dBiomes) { + super(plugin, use3dBiomes); adapter = SpigotAdapters.getWorldAdapter(); } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java index cd1774baf..9b765fd6e 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -28,23 +28,35 @@ package org.geysermc.platform.spigot.world.manager; import com.fasterxml.jackson.databind.JsonNode; import com.github.steveice10.mc.protocol.MinecraftConstants; import com.github.steveice10.mc.protocol.data.game.chunk.Chunk; +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.NbtType; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.block.Block; +import org.bukkit.block.Lectern; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BookMeta; +import org.bukkit.plugin.Plugin; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.translators.LecternInventoryTranslator; import org.geysermc.connector.network.translators.world.GeyserWorldManager; import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.utils.BlockEntityUtils; import org.geysermc.connector.utils.FileUtils; import org.geysermc.connector.utils.GameRule; import org.geysermc.connector.utils.LanguageUtils; import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; /** * The base world manager to use when there is no supported NMS revision @@ -72,8 +84,11 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager { */ private final Int2IntMap biomeToIdMap = new Int2IntOpenHashMap(Biome.values().length); - public GeyserSpigotWorldManager(boolean use3dBiomes) { + private final Plugin plugin; + + public GeyserSpigotWorldManager(Plugin plugin, boolean use3dBiomes) { this.use3dBiomes = use3dBiomes; + this.plugin = plugin; // Load the values into the biome-to-ID map InputStream biomeStream = FileUtils.getResource("biomes.json"); @@ -132,9 +147,6 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager { @Override @SuppressWarnings("deprecation") public int[] getBiomeDataAt(GeyserSession session, int x, int z) { - if (session.getPlayerEntity() == null) { - return new int[1024]; - } int[] biomeData = new int[1024]; World world = Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld(); int chunkX = x << 4; @@ -167,6 +179,56 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager { return biomeData; } + @Override + public NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad) { + // Run as a task to prevent async issues + Bukkit.getScheduler().runTask(this.plugin, () -> { + Player bukkitPlayer; + if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) { + return; + } + Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z); + if (!(block.getState() instanceof Lectern)) { + session.getConnector().getLogger().error("Lectern expected at: " + Vector3i.from(x, y, z).toString() + " but was not! " + block.toString()); + return; + } + Lectern lectern = (Lectern) block.getState(); + ItemStack itemStack = lectern.getInventory().getItem(0); + if (itemStack == null || !(itemStack.getItemMeta() instanceof BookMeta)) { + if (!isChunkLoad) { + // We need to update the lectern since it's not going to be updated otherwise + BlockEntityUtils.updateBlockEntity(session, LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build(), Vector3i.from(x, y, z)); + } + // We don't care; return + return; + } + BookMeta bookMeta = (BookMeta) itemStack.getItemMeta(); + NbtMapBuilder lecternTag = LecternInventoryTranslator.getBaseLecternTag(x, y, z, bookMeta.getPageCount()); + lecternTag.putInt("page", lectern.getPage() / 2); + NbtMapBuilder bookTag = NbtMap.builder() + .putByte("Count", (byte) itemStack.getAmount()) + .putShort("Damage", (short) 0) + .putString("Name", "minecraft:writable_book"); + List pages = new ArrayList<>(); + for (String page : bookMeta.getPages()) { + NbtMapBuilder pageBuilder = NbtMap.builder() + .putString("photoname", "") + .putString("text", page); + pages.add(pageBuilder.build()); + } + bookTag.putCompound("tag", NbtMap.builder().putList("pages", NbtType.COMPOUND, pages).build()); + lecternTag.putCompound("book", bookTag.build()); + NbtMap blockEntityTag = lecternTag.build(); + BlockEntityUtils.updateBlockEntity(session, blockEntityTag, Vector3i.from(x, y, z)); + }); + return LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build(); // Will be updated later + } + + @Override + public boolean shouldExpectLecternHandled() { + return true; + } + public Boolean getGameRuleBool(GeyserSession session, GameRule gameRule) { return Boolean.parseBoolean(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getGameRuleValue(gameRule.getJavaID())); } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/LecternContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/LecternContainer.java new file mode 100644 index 000000000..0ce9217d7 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/inventory/LecternContainer.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019-2020 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.inventory; + +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.NbtMap; +import lombok.Getter; +import lombok.Setter; + +public class LecternContainer extends Container { + @Getter @Setter + private int currentBedrockPage = 0; + @Getter @Setter + private NbtMap blockEntityTag; + @Getter @Setter + private Vector3i position; + + public LecternContainer(String title, int id, int size, PlayerInventory playerInventory) { + super(title, id, size, playerInventory); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 436887d35..f00e9f0b1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -153,6 +153,16 @@ public class GeyserSession implements CommandSender { */ private final Object2LongMap itemFrameCache = new Object2LongOpenHashMap<>(); + /** + * Stores a list of all lectern locations and their block entity tags. + * See {@link org.geysermc.connector.network.translators.world.WorldManager#getLecternDataAt(GeyserSession, int, int, int, boolean)} + * for more information. + */ + private final List lecternCache = new ArrayList<>(); + + @Setter + private boolean droppingLecternBook; + @Setter private Vector2i lastChunkPosition = null; private int renderDistance; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java index 5571ff8b9..93837c204 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java @@ -50,7 +50,7 @@ public class BedrockContainerCloseTranslator extends PacketTranslator { + + @Override + public void translate(LecternUpdatePacket packet, GeyserSession session) { + session.getConnector().getLogger().error(packet.toString()); + if (packet.isDroppingBook()) { + // Bedrock drops the book outside of the GUI. Java drops it in the GUI + // So, we enter the GUI and then drop it! :) + session.setDroppingLecternBook(true); + + Vector3f diff = session.getPlayerEntity().getPosition().sub(packet.getBlockPosition().toFloat()); + System.out.println(diff); + // Emulate an interact packet + ClientPlayerPlaceBlockPacket blockPacket = new ClientPlayerPlaceBlockPacket( + new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()), + BlockFace.values()[0], + Hand.MAIN_HAND, + packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ(), //TODO + false); + session.sendDownstreamPacket(blockPacket); + } else { + // Bedrock wants to either move a page or exit + LecternContainer lecternContainer = (LecternContainer) session.getOpenInventory(); + if (lecternContainer.getCurrentBedrockPage() == packet.getPage()) { + // The same page means Bedrock is closing the window + ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(lecternContainer.getId()); + session.sendDownstreamPacket(closeWindowPacket); + InventoryUtils.closeInventory(session, lecternContainer.getId()); + } else { + // Each "page" Bedrock gives to us actually represents two pages (think opening a book and seeing two pages) + // Each "page" on Java is just one page (think a spiral notebook folded back to only show one page) + int newJavaPage = (packet.getPage() * 2); + int currentJavaPage = (lecternContainer.getCurrentBedrockPage() * 2); + // Send as many click button packets as we need to + // Java has the option to specify exact page numbers by adding 100 to the number, but buttonId variable + // is a byte and therefore this stops us at 128 + if (newJavaPage > currentJavaPage) { + for (int i = currentJavaPage; i < newJavaPage; i++) { + ClientClickWindowButtonPacket clickButtonPacket = new ClientClickWindowButtonPacket(session.getOpenInventory().getId(), 2); + System.out.println(clickButtonPacket); + session.sendDownstreamPacket(clickButtonPacket); + } + } else { + for (int i = currentJavaPage; i > newJavaPage; i--) { + ClientClickWindowButtonPacket clickButtonPacket = new ClientClickWindowButtonPacket(session.getOpenInventory().getId(), 1); + System.out.println(clickButtonPacket); + session.sendDownstreamPacket(clickButtonPacket); + } + } + } + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index 95516dc26..396d1e090 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -97,6 +97,9 @@ public abstract class InventoryTranslator { /* Generics */ put(WindowType.GENERIC_3X3, new GenericBlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER)); put(WindowType.HOPPER, new GenericBlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER)); + + /* Lectern */ + put(WindowType.LECTERN, new LecternInventoryTranslator()); } }; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java new file mode 100644 index 000000000..28562bb9a --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2019-2020 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.translators.inventory.translators; + +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientClickWindowButtonPacket; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCloseWindowPacket; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.ListTag; +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import org.geysermc.connector.inventory.GeyserItemStack; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.LecternContainer; +import org.geysermc.connector.inventory.PlayerInventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; +import org.geysermc.connector.utils.BlockEntityUtils; +import org.geysermc.connector.utils.InventoryUtils; + +public class LecternInventoryTranslator extends BaseInventoryTranslator { + private final InventoryUpdater updater; + + public LecternInventoryTranslator() { + super(1); + this.updater = new LecternInventoryUpdater(); + } + + @Override + public void prepareInventory(GeyserSession session, Inventory inventory) { + + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + + } + + @Override + public void closeInventory(GeyserSession session, Inventory inventory) { + + } + + @Override + public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { + if (key == 0) { // Lectern page update + LecternContainer lecternContainer = (LecternContainer) inventory; + lecternContainer.setCurrentBedrockPage(value / 2); + lecternContainer.setBlockEntityTag(lecternContainer.getBlockEntityTag().toBuilder().putInt("page", lecternContainer.getCurrentBedrockPage()).build()); + System.out.println(lecternContainer.getBlockEntityTag()); + BlockEntityUtils.updateBlockEntity(session, lecternContainer.getBlockEntityTag(), lecternContainer.getPosition()); + } + } + + @Override + public void updateInventory(GeyserSession session, Inventory inventory) { + + } + + @Override + public void updateSlot(GeyserSession session, Inventory inventory, int slot) { + this.updater.updateSlot(this, session, inventory, slot); + if (slot == 0) { + LecternContainer lecternContainer = (LecternContainer) inventory; + if (session.isDroppingLecternBook()) { + // We have to enter the inventory GUI to eject the book + ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), 3); + session.sendDownstreamPacket(packet); + session.setDroppingLecternBook(false); + InventoryUtils.closeInventory(session, inventory.getId()); + } else if (lecternContainer.getBlockEntityTag() == null) { + // If the method returns true, this is already handled for us + GeyserItemStack geyserItemStack = inventory.getItem(0); + CompoundTag tag = geyserItemStack.getNbt(); + if (tag != null) { + // Position has to be the last interacted position... right? + Vector3i position = session.getLastInteractionPosition(); + // shouldRefresh means that we should boot out the + boolean shouldRefresh = !session.getConnector().getWorldManager().shouldExpectLecternHandled() && !session.getLecternCache().contains(position); + int pagesSize = ((ListTag) tag.get("pages")).size(); + ItemData itemData = geyserItemStack.getItemData(session); + NbtMapBuilder lecternTag = getBaseLecternTag(position.getX(), position.getY(), position.getZ(), pagesSize); + lecternTag.putCompound("book", NbtMap.builder() + .putByte("Count", (byte) itemData.getCount()) + .putShort("Damage", (short) 0) + .putString("Name", "minecraft:written_book") + .putCompound("tag", itemData.getTag()) + .build()); + lecternTag.putInt("page", lecternContainer.getCurrentBedrockPage()); + NbtMap blockEntityTag = lecternTag.build(); + // Even with serverside access to lecterns, we don't easily know which lectern this is, so we need to rebuild + // the block entity tag + lecternContainer.setBlockEntityTag(blockEntityTag); + System.out.println(blockEntityTag); + lecternContainer.setPosition(position); + if (shouldRefresh) { + // Update the lectern because it's not updated client-side + BlockEntityUtils.updateBlockEntity(session, blockEntityTag, position); + session.getLecternCache().add(position); + // Close the window - we will reopen it once the client has this data synced + ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(lecternContainer.getId()); + session.sendDownstreamPacket(closeWindowPacket); + InventoryUtils.closeInventory(session, inventory.getId()); + session.getConnector().getLogger().warning("Closing inventory"); + } + } + } + } + } + + @Override + public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { + return new LecternContainer(name, windowId, this.size, playerInventory); + } + + public static NbtMapBuilder getBaseLecternTag(int x, int y, int z, int totalPages) { + NbtMapBuilder builder = NbtMap.builder() + .putInt("x", x) + .putInt("y", y) + .putInt("z", z) + .putString("id", "Lectern"); + if (totalPages != 0) { + builder.putByte("hasBook", (byte) 1); + builder.putInt("totalPages", totalPages); + } else { + builder.putByte("hasBook", (byte) 0); + } + return builder; + } + + private static class LecternInventoryUpdater extends InventoryUpdater { + + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUnloadChunkTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUnloadChunkTranslator.java index 1dba72868..a4a661cd9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUnloadChunkTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUnloadChunkTranslator.java @@ -44,10 +44,19 @@ public class JavaUnloadChunkTranslator extends PacketTranslator iterator = session.getSkullCache().keySet().iterator(); while (iterator.hasNext()) { Vector3i position = iterator.next(); - if (Math.floor(position.getX() / 16) == packet.getX() && Math.floor(position.getZ() / 16) == packet.getZ()) { + if (Math.floor((double) position.getX() / 16) == packet.getX() && Math.floor((double) position.getZ() / 16) == packet.getZ()) { session.getSkullCache().get(position).despawnEntity(session); iterator.remove(); } } + + // Do the same thing with lecterns + iterator = session.getLecternCache().iterator(); + while (iterator.hasNext()) { + Vector3i position = iterator.next(); + if (Math.floor((double) position.getX() / 16) == packet.getX() && Math.floor((double) position.getZ() / 16) == packet.getZ()) { + iterator.remove(); + } + } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/GeyserWorldManager.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/GeyserWorldManager.java index 2ab3c0108..6248a4944 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/GeyserWorldManager.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/GeyserWorldManager.java @@ -30,10 +30,13 @@ import com.github.steveice10.mc.protocol.data.game.chunk.Column; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; import com.github.steveice10.mc.protocol.packet.ingame.client.ClientChatPacket; +import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtMapBuilder; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.cache.ChunkCache; +import org.geysermc.connector.network.translators.inventory.translators.LecternInventoryTranslator; import org.geysermc.connector.utils.GameRule; public class GeyserWorldManager extends WorldManager { @@ -88,6 +91,29 @@ public class GeyserWorldManager extends WorldManager { return new int[1024]; } + @Override + public NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad) { + // Without direct server access, we can't get lectern information on-the-fly. + // I should have set this up so it's only called when there is a book in the block state. - Camotoy + NbtMapBuilder lecternTag = LecternInventoryTranslator.getBaseLecternTag(x, y, z, 1); + lecternTag.putCompound("book", NbtMap.builder() + .putByte("Count", (byte) 1) + .putShort("Damage", (short) 0) + .putString("Name", "minecraft:written_book") + .putCompound("tag", NbtMap.builder() + .putString("photoname", "") + .putString("text", "") + .build()) + .build()); + lecternTag.putInt("page", -1); // I'm surprisingly glad this exists - it forces Bedrock to stop reading immediately + return lecternTag.build(); + } + + @Override + public boolean shouldExpectLecternHandled() { + return false; + } + @Override public void setGameRule(GeyserSession session, String name, Object value) { session.sendDownstreamPacket(new ClientChatPacket("/gamerule " + name + " " + value)); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/WorldManager.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/WorldManager.java index aaafe2fe9..b17af92a9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/WorldManager.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/WorldManager.java @@ -30,6 +30,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.NbtMap; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.utils.GameRule; @@ -106,6 +107,32 @@ public abstract class WorldManager { */ public abstract int[] getBiomeDataAt(GeyserSession session, int x, int z); + /** + * Sigh.
+ * + * So, on Java Edition, the lectern is an inventory. Java opens it and gets the contents of the book there. + * On Bedrock, the lectern contents are part of the block entity tag. Therefore, Bedrock expects to have the contents + * of the lectern ready and present in the world. If the contents are not there, it takes at least two clicks for the + * lectern to update the tag and then present itself.
+ * + * We solve this problem by querying all loaded lecterns, where possible, and sending their information in a block entity + * tag. + * + * @param session the session of the player + * @param x the x coordinate of the lectern + * @param y the y coordinate of the lectern + * @param z the z coordinate of the lectern + * @param isChunkLoad if this is called during a chunk load or not. Changes behavior in certain instances. + * @return the Bedrock lectern block entity tag. This may not be the exact block entity tag - for example, Spigot's + * block handled must be done on the server thread, so we send the tag manually there. + */ + public abstract NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad); + + /** + * @return whether we should expect lectern data to update, or if we have to fall back on a workaround. + */ + public abstract boolean shouldExpectLecternHandled(); + /** * Updates a gamerule value on the Java server * diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockStateValues.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockStateValues.java index 2701f82fd..3c8dd2c7a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockStateValues.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockStateValues.java @@ -42,6 +42,7 @@ public class BlockStateValues { private static final Int2ObjectMap DOUBLE_CHEST_VALUES = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap FLOWER_POT_VALUES = new Int2ObjectOpenHashMap<>(); private static final Map FLOWER_POT_BLOCKS = new HashMap<>(); + private static final Int2BooleanMap LECTERN_BOOK_STATES = new Int2BooleanOpenHashMap(); private static final Int2IntMap NOTEBLOCK_PITCHES = new Int2IntOpenHashMap(); private static final Int2BooleanMap IS_STICKY_PISTON = new Int2BooleanOpenHashMap(); private static final Int2BooleanMap PISTON_VALUES = new Int2BooleanOpenHashMap(); @@ -88,6 +89,11 @@ public class BlockStateValues { return; } + if (entry.getKey().startsWith("minecraft:lectern")) { + LECTERN_BOOK_STATES.put(javaBlockState, entry.getKey().contains("has_book=true")); + return; + } + JsonNode notePitch = entry.getValue().get("note_pitch"); if (notePitch != null) { NOTEBLOCK_PITCHES.put(javaBlockState, entry.getValue().get("note_pitch").intValue()); @@ -197,6 +203,10 @@ public class BlockStateValues { return FLOWER_POT_BLOCKS; } + public static Int2BooleanMap getLecternBookStates() { + return LECTERN_BOOK_STATES; + } + /** * The note that noteblocks output when hit is part of the block state in Java but sent as a BlockEventPacket in Bedrock. * This gives an integer pitch that Bedrock can use. diff --git a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java index 8950601a8..0175450da 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java @@ -53,6 +53,7 @@ import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.ItemFrameEntity; import org.geysermc.connector.entity.player.SkullPlayerEntity; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.translators.LecternInventoryTranslator; import org.geysermc.connector.network.translators.world.block.BlockStateValues; import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.network.translators.world.block.entity.BedrockOnlyBlockEntity; @@ -282,7 +283,6 @@ public class ChunkUtils { } String id = BlockEntityUtils.getBedrockBlockEntityId(tagName); - BlockEntityTranslator blockEntityTranslator = BlockEntityUtils.getBlockEntityTranslator(id); Position pos = new Position((int) tag.get("x").getValue(), (int) tag.get("y").getValue(), (int) tag.get("z").getValue()); // Get Java blockstate ID from block entity position @@ -292,6 +292,14 @@ public class ChunkUtils { blockState = section.get(pos.getX() & 0xF, pos.getY() & 0xF, pos.getZ() & 0xF); } + if (tagName.equals("minecraft:lectern") && BlockStateValues.getLecternBookStates().get(blockState)) { + // If getLecternBookStates is false, let's just treat it like a normal block entity + bedrockBlockEntities[i] = session.getConnector().getWorldManager().getLecternDataAt(session, pos.getX(), pos.getY(), pos.getZ(), true); + i++; + continue; + } + + BlockEntityTranslator blockEntityTranslator = BlockEntityUtils.getBlockEntityTranslator(id); bedrockBlockEntities[i] = blockEntityTranslator.getBlockEntityTag(tagName, tag, blockState); // Check for custom skulls @@ -388,6 +396,29 @@ public class ChunkUtils { } session.sendUpstreamPacket(waterPacket); + if (BlockStateValues.getLecternBookStates().containsKey(blockState)) { + boolean lecternCachedHasBook = session.getLecternCache().contains(position); + boolean newLecternHasBook = BlockStateValues.getLecternBookStates().get(blockState); + if (!session.getConnector().getWorldManager().shouldExpectLecternHandled() && lecternCachedHasBook != newLecternHasBook) { + // Refresh the block entirely - it either has a book or no longer has a book + session.getConnector().getLogger().warning("Refreshing lectern entirely"); + NbtMap newLecternTag; + if (newLecternHasBook) { + newLecternTag = session.getConnector().getWorldManager().getLecternDataAt(session, position.getX(), position.getY(), position.getZ(), false); + } else { + session.getLecternCache().remove(position); + newLecternTag = LecternInventoryTranslator.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), 0).build(); + } + BlockEntityUtils.updateBlockEntity(session, newLecternTag, position); + } else { + // As of right now, no tag can be added asynchronously + session.getConnector().getWorldManager().getLecternDataAt(session, position.getX(), position.getY(), position.getZ(), false); + } + } else { + // Lectern has been destroyed, if it existed + session.getLecternCache().remove(position); + } + // Since Java stores bed colors/skull information as part of the namespaced ID and Bedrock stores it as a tag // This is the only place I could find that interacts with the Java block state and block updates // Iterates through all block entity translators and determines if the block state needs to be saved diff --git a/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java index de9bcf884..e0118b431 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java @@ -66,6 +66,7 @@ public class DimensionUtils { session.getEntityCache().removeAllEntities(); session.getItemFrameCache().clear(); + session.getLecternCache().clear(); session.getSkullCache().clear(); if (session.getPendingDimSwitches().getAndIncrement() > 0) { ChunkUtils.sendEmptyChunks(session, player.getPosition().toInt(), 3, true); From 3ba396e6259219e41092457d03d76a8773d67734 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 28 Dec 2020 00:47:10 -0500 Subject: [PATCH 026/101] Fix some temporary inventory blocks not disappearing --- .../translators/inventory/holder/BlockInventoryHolder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java index 1b4dfb8db..7785c4a80 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java @@ -96,6 +96,7 @@ public class BlockInventoryHolder extends InventoryHolder { blockPacket.setDataLayer(0); blockPacket.setBlockPosition(holderPos); blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock)); + blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); } } From a5c020e7eeff3527f82700026278f8a20edafa01 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 28 Dec 2020 13:16:17 -0500 Subject: [PATCH 027/101] More comments --- .../inventory/translators/LecternInventoryTranslator.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java index 28562bb9a..0eabf951f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java @@ -72,7 +72,6 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { LecternContainer lecternContainer = (LecternContainer) inventory; lecternContainer.setCurrentBedrockPage(value / 2); lecternContainer.setBlockEntityTag(lecternContainer.getBlockEntityTag().toBuilder().putInt("page", lecternContainer.getCurrentBedrockPage()).build()); - System.out.println(lecternContainer.getBlockEntityTag()); BlockEntityUtils.updateBlockEntity(session, lecternContainer.getBlockEntityTag(), lecternContainer.getPosition()); } } @@ -100,7 +99,7 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { if (tag != null) { // Position has to be the last interacted position... right? Vector3i position = session.getLastInteractionPosition(); - // shouldRefresh means that we should boot out the + // shouldRefresh means that we should boot out the client on our side because their lectern GUI isn't updated yet boolean shouldRefresh = !session.getConnector().getWorldManager().shouldExpectLecternHandled() && !session.getLecternCache().contains(position); int pagesSize = ((ListTag) tag.get("pages")).size(); ItemData itemData = geyserItemStack.getItemData(session); @@ -116,7 +115,6 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { // Even with serverside access to lecterns, we don't easily know which lectern this is, so we need to rebuild // the block entity tag lecternContainer.setBlockEntityTag(blockEntityTag); - System.out.println(blockEntityTag); lecternContainer.setPosition(position); if (shouldRefresh) { // Update the lectern because it's not updated client-side @@ -148,6 +146,7 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { builder.putByte("hasBook", (byte) 1); builder.putInt("totalPages", totalPages); } else { + // Not usually needed, but helps with kicking out Bedrock players from reading the UI builder.putByte("hasBook", (byte) 0); } return builder; From 3c1a40c56af6a708b48c8077a90379176b6f876d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 29 Dec 2020 19:59:22 -0500 Subject: [PATCH 028/101] Better net ID handling --- .../org/geysermc/connector/entity/Entity.java | 6 +-- .../connector/inventory/Container.java | 7 ++-- .../connector/inventory/GeyserItemStack.java | 37 +++++++++++-------- .../connector/inventory/Inventory.java | 13 ++++++- ...BedrockInventoryTransactionTranslator.java | 2 +- .../entity/BedrockEntityEventTranslator.java | 2 +- .../player/BedrockInteractTranslator.java | 2 +- .../inventory/InventoryTranslator.java | 36 +++++++++--------- .../inventory/click/ClickPlan.java | 2 +- .../translators/LoomInventoryTranslator.java | 2 +- .../StonecutterInventoryTranslator.java | 6 +-- .../java/window/JavaSetSlotTranslator.java | 10 +---- .../window/JavaWindowItemsTranslator.java | 8 +--- .../connector/utils/InventoryUtils.java | 2 +- 14 files changed, 68 insertions(+), 67 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/entity/Entity.java b/connector/src/main/java/org/geysermc/connector/entity/Entity.java index 68b2b2666..921d5e142 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -286,11 +286,11 @@ public class Entity { // Shield code if (session.getPlayerEntity().getEntityId() == entityId && metadata.getFlags().getFlag(EntityFlag.SNEAKING)) { PlayerInventory playerInv = session.getPlayerInventory(); - if ((playerInv.getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) || - (playerInv.getOffhand().getId() == ItemRegistry.SHIELD.getJavaId())) { + if ((playerInv.getItemInHand().getJavaId() == ItemRegistry.SHIELD.getJavaId()) || + (playerInv.getOffhand().getJavaId() == ItemRegistry.SHIELD.getJavaId())) { ClientPlayerUseItemPacket useItemPacket; metadata.getFlags().setFlag(EntityFlag.BLOCKING, true); - if (playerInv.getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) { + if (playerInv.getItemInHand().getJavaId() == ItemRegistry.SHIELD.getJavaId()) { useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); } // Else we just assume it's the offhand, to simplify logic and to assure the packet gets sent diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Container.java b/connector/src/main/java/org/geysermc/connector/inventory/Container.java index eb1d9c3de..9768520bd 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Container.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Container.java @@ -27,6 +27,7 @@ package org.geysermc.connector.inventory; import lombok.Getter; import lombok.NonNull; +import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; /** @@ -53,11 +54,11 @@ public class Container extends Inventory { } @Override - public void setItem(int slot, @NonNull GeyserItemStack item) { + public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) { if (slot < this.size) { - super.setItem(slot, item); + super.setItem(slot, newItem, session); } else { - playerInventory.setItem(slot - this.size + InventoryTranslator.PLAYER_INVENTORY_OFFSET, item); + playerInventory.setItem(slot - this.size + InventoryTranslator.PLAYER_INVENTORY_OFFSET, newItem, session); } } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java index c935fcdb4..46cf8529a 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java @@ -39,32 +39,34 @@ import org.geysermc.connector.network.translators.item.ItemTranslator; public class GeyserItemStack { public static final GeyserItemStack EMPTY = new GeyserItemStack(0, 0, null); - private final int id; + private final int javaId; private int amount; private CompoundTag nbt; private int netId; + private boolean netIdWasUpdated; - public GeyserItemStack(int id) { - this(id, 1); + public GeyserItemStack(int javaId) { + this(javaId, 1); } - public GeyserItemStack(int id, int amount) { - this(id, amount, null); + public GeyserItemStack(int javaId, int amount) { + this(javaId, amount, null); } - public GeyserItemStack(int id, int amount, CompoundTag nbt) { - this(id, amount, nbt, 1); + public GeyserItemStack(int javaId, int amount, CompoundTag nbt) { + this(javaId, amount, nbt, 1); } - public GeyserItemStack(int id, int amount, CompoundTag nbt, int netId) { - this.id = id; + public GeyserItemStack(int javaId, int amount, CompoundTag nbt, int netId) { + this.javaId = javaId; this.amount = amount; this.nbt = nbt; this.netId = netId; + this.netIdWasUpdated = !this.isEmpty(); } - public int getId() { - return isEmpty() ? 0 : id; + public int getJavaId() { + return isEmpty() ? 0 : javaId; } public int getAmount() { @@ -75,6 +77,11 @@ public class GeyserItemStack { return isEmpty() ? null : nbt; } + public void setNetId(int netId) { + this.netId = netId; + this.netIdWasUpdated = true; + } + public int getNetId() { return isEmpty() ? 0 : netId; } @@ -96,7 +103,7 @@ public class GeyserItemStack { } public ItemStack getItemStack() { - return isEmpty() ? null : new ItemStack(id, amount, nbt); + return isEmpty() ? null : new ItemStack(javaId, amount, nbt); } public ItemData getItemData(GeyserSession session) { @@ -106,11 +113,11 @@ public class GeyserItemStack { } public ItemEntry getItemEntry() { - return ItemRegistry.ITEM_ENTRIES.get(getId()); + return ItemRegistry.ITEM_ENTRIES.get(getJavaId()); } public boolean isEmpty() { - return amount <= 0 || id == 0; + return amount <= 0 || javaId == 0; } public GeyserItemStack copy() { @@ -118,6 +125,6 @@ public class GeyserItemStack { } public GeyserItemStack copy(int newAmount) { - return isEmpty() ? EMPTY : new GeyserItemStack(id, newAmount, nbt == null ? null : nbt.clone(), netId); + return isEmpty() ? EMPTY : new GeyserItemStack(javaId, newAmount, nbt == null ? null : nbt.clone(), netId); } } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java index 14d80c385..53d0905ce 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java @@ -29,6 +29,7 @@ import com.nukkitx.math.vector.Vector3i; import lombok.Getter; import lombok.NonNull; import lombok.Setter; +import org.geysermc.connector.network.session.GeyserSession; import java.util.Arrays; @@ -76,8 +77,16 @@ public class Inventory { return items[slot]; } - public void setItem(int slot, @NonNull GeyserItemStack item) { - items[slot] = item; + public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) { + GeyserItemStack oldItem = items[slot]; + if (!newItem.isEmpty()) { + if (newItem.getItemData(session).equals(oldItem.getItemData(session), false, false, false)) { + newItem.setNetId(oldItem.getNetId()); + } else { + newItem.setNetId(session.getNextItemNetId()); + } + } + items[slot] = newItem; } public short getNextTransactionId() { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index 54221b4ad..9e71455c5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -186,7 +186,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator= 0 && packet.getData() < trades.length) { VillagerTrade trade = merchantInventory.getVillagerTrades()[packet.getData()]; - openInventory.setItem(2, GeyserItemStack.from(trade.getOutput())); + openInventory.setItem(2, GeyserItemStack.from(trade.getOutput()), session); villager.getMetadata().put(EntityData.TRADE_XP, trade.getXp() + villager.getMetadata().getInt(EntityData.TRADE_XP)); villager.updateBedrockMetadata(session); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java index 86f30c2fe..0c694fb9d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java @@ -100,7 +100,7 @@ public class BedrockInteractTranslator extends PacketTranslator switch (packet.getAction()) { case INTERACT: - if (session.getPlayerInventory().getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) { + if (session.getPlayerInventory().getItemInHand().getJavaId() == ItemRegistry.SHIELD.getJavaId()) { break; } ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index ef052409f..7e626955a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -213,7 +213,7 @@ public abstract class InventoryTranslator { GeyserItemStack newItem = sourceItem.copy(); if (sourceIsCursor) { GeyserItemStack destItem = inventory.getItem(destSlot); - if (destItem.getId() == sourceItem.getId()) { + if (destItem.getJavaId() == sourceItem.getJavaId()) { // Combining items int itemsLeftOver = destItem.getAmount() + transferAction.getCount(); if (itemsLeftOver > MAX_ITEM_STACK_SIZE) { @@ -235,7 +235,7 @@ public abstract class InventoryTranslator { } } else { // Delete the source since we're moving it - inventory.setItem(sourceSlot, GeyserItemStack.EMPTY); + inventory.setItem(sourceSlot, GeyserItemStack.EMPTY, session); ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( sourceSlot, new ItemStack(0) @@ -252,13 +252,13 @@ public abstract class InventoryTranslator { if (sourceIsCursor) { session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY); } else { - inventory.setItem(sourceSlot, GeyserItemStack.EMPTY); + inventory.setItem(sourceSlot, GeyserItemStack.EMPTY, session); } } if (destIsCursor) { session.getPlayerInventory().setCursor(newItem); } else { - inventory.setItem(destSlot, newItem); + inventory.setItem(destSlot, newItem, session); } GeyserItemStack itemToUpdate = destIsCursor ? sourceItem : newItem; // The Java server doesn't care about what's in the mouse in creative mode, so we just need to track @@ -386,7 +386,7 @@ public abstract class InventoryTranslator { ); System.out.println(creativeActionPacket); session.sendDownstreamPacket(creativeActionPacket); - inventory.setItem(sourceSlot, oldDestinationItem); + inventory.setItem(sourceSlot, oldDestinationItem, session); } if (isCursor(swapAction.getDestination())) { session.getPlayerInventory().setCursor(oldSourceItem); @@ -397,7 +397,7 @@ public abstract class InventoryTranslator { ); System.out.println(creativeActionPacket); session.sendDownstreamPacket(creativeActionPacket); - inventory.setItem(destSlot, oldSourceItem); + inventory.setItem(destSlot, oldSourceItem, session); } } else if (isCursor(swapAction.getSource()) && isCursor(swapAction.getDestination())) { //??? @@ -499,7 +499,7 @@ public abstract class InventoryTranslator { ); session.sendDownstreamPacket(destroyItemPacket); System.out.println(destroyItemPacket); - inventory.setItem(javaSlot, GeyserItemStack.EMPTY); + inventory.setItem(javaSlot, GeyserItemStack.EMPTY, session); affectedSlots.add(javaSlot); } else { // Just sync up the item on our end, since the server doesn't care what's in our cursor @@ -522,7 +522,7 @@ public abstract class InventoryTranslator { GeyserItemStack item = inventory.getItem(sourceSlot); item.setAmount(item.getAmount() - consumeData.getCount()); if (item.isEmpty()) { - inventory.setItem(sourceSlot, GeyserItemStack.EMPTY); + inventory.setItem(sourceSlot, GeyserItemStack.EMPTY, session); } affectedSlots.add(sourceSlot); } @@ -718,16 +718,16 @@ public abstract class InventoryTranslator { session.getPlayerInventory().setCursor(GeyserItemStack.from(javaCreativeItem, session.getNextItemNetId())); return acceptRequest(request, Collections.singletonList( new ItemStackResponsePacket.ContainerEntry(ContainerSlotType.CURSOR, - Collections.singletonList(makeItemEntry(session, 0, session.getPlayerInventory().getCursor()))))); + Collections.singletonList(makeItemEntry(0, session.getPlayerInventory().getCursor()))))); } else { int javaSlot = bedrockSlotToJava(transferAction.getDestination()); GeyserItemStack existingItem = inventory.getItem(javaSlot); - if (existingItem.getId() == javaCreativeItem.getId()) { + if (existingItem.getJavaId() == javaCreativeItem.getId()) { // Adding more to an existing item existingItem.setAmount(existingItem.getAmount() + transferAction.getCount()); javaCreativeItem = existingItem.getItemStack(); } else { - inventory.setItem(javaSlot, GeyserItemStack.from(javaCreativeItem, session.getNextItemNetId())); + inventory.setItem(javaSlot, GeyserItemStack.from(javaCreativeItem, session.getNextItemNetId()), session); } ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( javaSlot, @@ -765,8 +765,8 @@ public abstract class InventoryTranslator { public boolean checkNetId(GeyserSession session, Inventory inventory, StackRequestSlotInfoData slotInfoData) { if (slotInfoData.getStackNetworkId() < 0) return true; - if (slotInfoData.getContainer() == ContainerSlotType.CURSOR) //TODO: temporary - return true; +// if (slotInfoData.getContainer() == ContainerSlotType.CURSOR) //TODO: temporary +// return true; GeyserItemStack currentItem = isCursor(slotInfoData) ? session.getPlayerInventory().getCursor() : inventory.getItem(bedrockSlotToJava(slotInfoData)); return currentItem.getNetId() == slotInfoData.getStackNetworkId(); @@ -826,7 +826,7 @@ public abstract class InventoryTranslator { for (int slot : affectedSlots) { BedrockContainerSlot bedrockSlot = javaSlotToBedrockContainer(slot); List list = containerMap.computeIfAbsent(bedrockSlot.getContainer(), k -> new ArrayList<>()); - list.add(makeItemEntry(session, bedrockSlot.getSlot(), inventory.getItem(slot))); + list.add(makeItemEntry(bedrockSlot.getSlot(), inventory.getItem(slot))); } List containerEntries = new ArrayList<>(); @@ -834,18 +834,16 @@ public abstract class InventoryTranslator { containerEntries.add(new ItemStackResponsePacket.ContainerEntry(entry.getKey(), entry.getValue())); } - ItemStackResponsePacket.ItemEntry cursorEntry = makeItemEntry(session, 0, session.getPlayerInventory().getCursor()); + ItemStackResponsePacket.ItemEntry cursorEntry = makeItemEntry(0, session.getPlayerInventory().getCursor()); containerEntries.add(new ItemStackResponsePacket.ContainerEntry(ContainerSlotType.CURSOR, Collections.singletonList(cursorEntry))); return containerEntries; } - public static ItemStackResponsePacket.ItemEntry makeItemEntry(GeyserSession session, int bedrockSlot, GeyserItemStack itemStack) { + public static ItemStackResponsePacket.ItemEntry makeItemEntry(int bedrockSlot, GeyserItemStack itemStack) { ItemStackResponsePacket.ItemEntry itemEntry; if (!itemStack.isEmpty()) { - int newNetId = session.getNextItemNetId(); - itemStack.setNetId(newNetId); - itemEntry = new ItemStackResponsePacket.ItemEntry((byte) bedrockSlot, (byte) bedrockSlot, (byte) itemStack.getAmount(), newNetId, ""); + itemEntry = new ItemStackResponsePacket.ItemEntry((byte) bedrockSlot, (byte) bedrockSlot, (byte) itemStack.getAmount(), itemStack.getNetId(), ""); } else { itemEntry = new ItemStackResponsePacket.ItemEntry((byte) bedrockSlot, (byte) bedrockSlot, (byte) 0, 0, ""); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java index 4e5c28552..5bfe197e5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java @@ -127,7 +127,7 @@ public class ClickPlan { if (simulating) { simulatedItems.put(slot, item); } else { - inventory.setItem(slot, item); + inventory.setItem(slot, item, session); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java index 59dd7d742..7fbca6e92 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java @@ -166,7 +166,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { inputCopy.getNbt().put(blockEntityTag); } // Set the new item as the output - inventory.setItem(3, inputCopy); + inventory.setItem(3, inputCopy, session); return translateRequest(session, inventory, request); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java index 16aefc744..4ffe87eb0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java @@ -64,7 +64,7 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl } CraftResultsDeprecatedStackRequestActionData craftData = (CraftResultsDeprecatedStackRequestActionData) data; // Get the ID of the item we are cutting - int id = inventory.getItem(0).getId(); + 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) { @@ -77,9 +77,9 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), results.indexOf(javaOutput.getId())); System.out.println(packet.toString()); session.sendDownstreamPacket(packet); - if (inventory.getItem(1).getId() != javaOutput.getId()) { + if (inventory.getItem(1).getJavaId() != javaOutput.getId()) { // We don't know there is an output here, so we tell ourselves that there is - inventory.setItem(1, GeyserItemStack.from(javaOutput, session.getNextItemNetId())); + inventory.setItem(1, GeyserItemStack.from(javaOutput, session.getNextItemNetId()), session); } return translateRequest(session, inventory, request); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java index 5d311fe3d..94c572712 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java @@ -62,15 +62,7 @@ public class JavaSetSlotTranslator extends PacketTranslator InventoryTranslator translator = session.getInventoryTranslator(); if (translator != null) { GeyserItemStack newItem = GeyserItemStack.from(packet.getItem()); - GeyserItemStack oldItem = inventory.getItem(packet.getSlot()); - if (newItem.getItemData(session).equals(oldItem.getItemData(session), false, false, false)) { - newItem.setNetId(oldItem.getNetId()); - System.out.println("OLD: " + newItem.getNetId()); - } else { - newItem.setNetId(session.getNextItemNetId()); - System.out.println("NEW: " + newItem.getNetId()); - } - inventory.setItem(packet.getSlot(), newItem); + inventory.setItem(packet.getSlot(), newItem, session); translator.updateSlot(session, inventory, packet.getSlot()); } }); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java index b87f1de80..c8afd1c53 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java @@ -46,13 +46,7 @@ public class JavaWindowItemsTranslator extends PacketTranslator Date: Tue, 29 Dec 2020 20:31:48 -0500 Subject: [PATCH 029/101] Optimize stonecutter button code --- .../connector/inventory/FurnaceInventory.java | 41 -------------- .../inventory/StonecutterContainer.java | 53 +++++++++++++++++++ .../StonecutterInventoryTranslator.java | 29 +++++++--- 3 files changed, 74 insertions(+), 49 deletions(-) delete mode 100644 connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java create mode 100644 connector/src/main/java/org/geysermc/connector/inventory/StonecutterContainer.java diff --git a/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java deleted file mode 100644 index 6574374be..000000000 --- a/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2019-2020 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.inventory; - -import lombok.Getter; -import lombok.Setter; - -//TODO: Figure out what this is and if we should remove it -@Getter -public class FurnaceInventory extends Inventory { - @Setter - private int test; - - public FurnaceInventory(String title, int id, int size) { - super(title, id, size); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/inventory/StonecutterContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/StonecutterContainer.java new file mode 100644 index 000000000..46db48b16 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/inventory/StonecutterContainer.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019-2020 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.inventory; + +import lombok.Getter; +import lombok.NonNull; +import lombok.Setter; +import org.geysermc.connector.network.session.GeyserSession; + +public class StonecutterContainer extends Container { + /** + * The button that has currently been pressed Java-side + */ + @Getter + @Setter + private int stonecutterButton = -1; + + public StonecutterContainer(String title, int id, int size, PlayerInventory playerInventory) { + super(title, id, size, playerInventory); + } + + @Override + public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) { + if (slot == 0 && newItem.getJavaId() != items[slot].getJavaId()) { + // The pressed stonecutter button output resets whenever the input item changes + this.stonecutterButton = -1; + } + super.setItem(slot, newItem, session); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java index 4ffe87eb0..419e80603 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java @@ -26,6 +26,7 @@ package org.geysermc.connector.network.translators.inventory.translators; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientClickWindowButtonPacket; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; @@ -38,6 +39,8 @@ import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import it.unimi.dsi.fastutil.ints.IntList; import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.PlayerInventory; +import org.geysermc.connector.inventory.StonecutterContainer; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; import org.geysermc.connector.network.translators.inventory.SlotType; @@ -57,12 +60,12 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl @Override public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { // TODO: Also surely to change in the future - // TODO: don't spam the ClickWindowButtonPacket? StackRequestActionData data = request.getActions()[1]; if (!(data instanceof CraftResultsDeprecatedStackRequestActionData)) { return rejectRequest(request); } CraftResultsDeprecatedStackRequestActionData craftData = (CraftResultsDeprecatedStackRequestActionData) data; + 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 @@ -73,13 +76,18 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl System.out.println(id + " " + results); ItemStack javaOutput = ItemTranslator.translateToJava(craftData.getResultItems()[0]); System.out.println(javaOutput); - // Getting the index of the item in the Java stonecutter list - ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), results.indexOf(javaOutput.getId())); - System.out.println(packet.toString()); - session.sendDownstreamPacket(packet); - if (inventory.getItem(1).getJavaId() != javaOutput.getId()) { - // We don't know there is an output here, so we tell ourselves that there is - inventory.setItem(1, GeyserItemStack.from(javaOutput, session.getNextItemNetId()), session); + int button = results.indexOf(javaOutput.getId()); + // If we've already pressed the button with this item, no need to press it again! + if (container.getStonecutterButton() != button) { + // Getting the index of the item in the Java stonecutter list + ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), button); + System.out.println(packet.toString()); + session.sendDownstreamPacket(packet); + container.setStonecutterButton(button); + if (inventory.getItem(1).getJavaId() != javaOutput.getId()) { + // We don't know there is an output here, so we tell ourselves that there is + inventory.setItem(1, GeyserItemStack.from(javaOutput, session.getNextItemNetId()), session); + } } return translateRequest(session, inventory, request); } @@ -124,4 +132,9 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl } return super.getSlotType(javaSlot); } + + @Override + public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { + return new StonecutterContainer(name, windowId, this.size, playerInventory); + } } From b7b3278d8bf3d19a6dd35b64a3fceb56f0c53fd0 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Thu, 31 Dec 2020 17:39:54 -0900 Subject: [PATCH 030/101] item painting. cursor net id --- .../connector/inventory/GeyserItemStack.java | 3 --- .../connector/inventory/Inventory.java | 6 +++++- .../connector/inventory/PlayerInventory.java | 7 ++++++- .../inventory/InventoryTranslator.java | 18 +++++++++--------- .../translators/inventory/click/ClickPlan.java | 18 +++++++++++++++--- .../JavaConfirmTransactionTranslator.java | 1 + .../java/window/JavaSetSlotTranslator.java | 8 +------- .../connector/utils/InventoryUtils.java | 2 +- 8 files changed, 38 insertions(+), 25 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java index 46cf8529a..c84439657 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java @@ -43,7 +43,6 @@ public class GeyserItemStack { private int amount; private CompoundTag nbt; private int netId; - private boolean netIdWasUpdated; public GeyserItemStack(int javaId) { this(javaId, 1); @@ -62,7 +61,6 @@ public class GeyserItemStack { this.amount = amount; this.nbt = nbt; this.netId = netId; - this.netIdWasUpdated = !this.isEmpty(); } public int getJavaId() { @@ -79,7 +77,6 @@ public class GeyserItemStack { public void setNetId(int netId) { this.netId = netId; - this.netIdWasUpdated = true; } public int getNetId() { diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java index 53d0905ce..1088f6f94 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java @@ -79,6 +79,11 @@ public class Inventory { public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) { GeyserItemStack oldItem = items[slot]; + updateItemNetId(oldItem, newItem, session); + items[slot] = newItem; + } + + protected static void updateItemNetId(GeyserItemStack oldItem, GeyserItemStack newItem, GeyserSession session) { if (!newItem.isEmpty()) { if (newItem.getItemData(session).equals(oldItem.getItemData(session), false, false, false)) { newItem.setNetId(oldItem.getNetId()); @@ -86,7 +91,6 @@ public class Inventory { newItem.setNetId(session.getNextItemNetId()); } } - items[slot] = newItem; } public short getNextTransactionId() { diff --git a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java index 52066a806..b9f00b5f7 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java @@ -28,6 +28,7 @@ package org.geysermc.connector.inventory; import lombok.Getter; import lombok.NonNull; import lombok.Setter; +import org.geysermc.connector.network.session.GeyserSession; public class PlayerInventory extends Inventory { @@ -40,7 +41,6 @@ public class PlayerInventory extends Inventory { private int heldItemSlot; @Getter - @Setter @NonNull private GeyserItemStack cursor = GeyserItemStack.EMPTY; @@ -49,6 +49,11 @@ public class PlayerInventory extends Inventory { heldItemSlot = 0; } + public void setCursor(@NonNull GeyserItemStack newCursor, GeyserSession session) { + updateItemNetId(cursor, newCursor, session); + cursor = newCursor; + } + public GeyserItemStack getItemInHand() { return items[36 + heldItemSlot]; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index 7e626955a..11ce68e49 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -223,7 +223,7 @@ public abstract class InventoryTranslator { } else { // Cursor will be emptied destItem.setAmount(itemsLeftOver); - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY); + session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); } ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( destSlot, @@ -250,13 +250,13 @@ public abstract class InventoryTranslator { if (sourceItem.isEmpty()) { // Item is basically deleted if (sourceIsCursor) { - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY); + session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); } else { inventory.setItem(sourceSlot, GeyserItemStack.EMPTY, session); } } if (destIsCursor) { - session.getPlayerInventory().setCursor(newItem); + session.getPlayerInventory().setCursor(newItem, session); } else { inventory.setItem(destSlot, newItem, session); } @@ -340,7 +340,7 @@ public abstract class InventoryTranslator { //try to transfer items with least clicks possible int halfSource = sourceAmount - (sourceAmount / 2); //larger half int holding; - if (transferAction.getCount() <= halfSource) { //faster to take only half + if (plan.getCursor().isEmpty() && transferAction.getCount() <= halfSource) { //faster to take only half. CURSOR MUST BE EMPTY plan.add(Click.RIGHT, sourceSlot); holding = halfSource; } else { //need all @@ -376,7 +376,7 @@ public abstract class InventoryTranslator { GeyserItemStack oldDestinationItem = inventory.getItem(destSlot); if (isCursor(swapAction.getSource())) { oldSourceItem = session.getPlayerInventory().getCursor(); - session.getPlayerInventory().setCursor(oldDestinationItem); + session.getPlayerInventory().setCursor(oldDestinationItem, session); } else { int sourceSlot = bedrockSlotToJava(swapAction.getSource()); oldSourceItem = inventory.getItem(sourceSlot); @@ -389,7 +389,7 @@ public abstract class InventoryTranslator { inventory.setItem(sourceSlot, oldDestinationItem, session); } if (isCursor(swapAction.getDestination())) { - session.getPlayerInventory().setCursor(oldSourceItem); + session.getPlayerInventory().setCursor(oldSourceItem, session); } else { ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( destSlot, @@ -445,7 +445,7 @@ public abstract class InventoryTranslator { cursorItem.setAmount(cursorItem.getAmount() - dropAction.getCount()); if (cursorItem.isEmpty()) { // Cursor item no longer exists - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY); + session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); } droppingItem.setAmount(dropAction.getCount()); ClientCreativeInventoryActionPacket packet = new ClientCreativeInventoryActionPacket( @@ -503,7 +503,7 @@ public abstract class InventoryTranslator { affectedSlots.add(javaSlot); } else { // Just sync up the item on our end, since the server doesn't care what's in our cursor - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY); + session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); } break; } @@ -715,7 +715,7 @@ public abstract class InventoryTranslator { ItemStack javaCreativeItem = ItemTranslator.translateToJava(creativeItem); if (isCursor(transferAction.getDestination())) { - session.getPlayerInventory().setCursor(GeyserItemStack.from(javaCreativeItem, session.getNextItemNetId())); + session.getPlayerInventory().setCursor(GeyserItemStack.from(javaCreativeItem, session.getNextItemNetId()), session); return acceptRequest(request, Collections.singletonList( new ItemStackResponsePacket.ContainerEntry(ContainerSlotType.CURSOR, Collections.singletonList(makeItemEntry(0, session.getPlayerInventory().getCursor()))))); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java index 5bfe197e5..64174c496 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java @@ -63,6 +63,11 @@ public class ClickPlan { this.simulating = true; } + private void resetSimulation() { + this.simulatedItems.clear(); + this.simulatedCursor = session.getPlayerInventory().getCursor().copy(); + } + public void add(Click click, int slot) { if (!simulating) throw new UnsupportedOperationException("ClickPlan already executed"); @@ -77,7 +82,8 @@ public class ClickPlan { } public void execute(boolean refresh) { - simulating = false; + //update geyser inventory after simulation to avoid net id desync + resetSimulation(); ListIterator planIter = plan.listIterator(); while (planIter.hasNext()) { ClickAction action = planIter.next(); @@ -92,7 +98,7 @@ public class ClickPlan { } else if (action.click.windowAction == WindowAction.DROP_ITEM || action.slot == Click.OUTSIDE_SLOT) { clickedItemStack = null; } else { - clickedItemStack = inventory.getItem(action.slot).getItemStack(); + clickedItemStack = getItem(action.slot).getItemStack(); } short actionId = inventory.getNextTransactionId(); @@ -113,6 +119,12 @@ public class ClickPlan { } System.out.println(clickPacket); } + + session.getPlayerInventory().setCursor(simulatedCursor, session); + for (Int2ObjectMap.Entry simulatedSlot : simulatedItems.int2ObjectEntrySet()) { + inventory.setItem(simulatedSlot.getIntKey(), simulatedSlot.getValue(), session); + } + simulating = false; } public GeyserItemStack getItem(int slot) { @@ -135,7 +147,7 @@ public class ClickPlan { if (simulating) { simulatedCursor = item; } else { - session.getPlayerInventory().setCursor(item); + session.getPlayerInventory().setCursor(item, session); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java index 6d6c1686c..69e9b4ad0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java @@ -41,6 +41,7 @@ public class JavaConfirmTransactionTranslator extends PacketTranslator session.addInventoryTask(() -> { if (packet.getWindowId() == 255) { //cursor GeyserItemStack newItem = GeyserItemStack.from(packet.getItem()); - GeyserItemStack oldItem = session.getPlayerInventory().getCursor(); - if (newItem.getItemData(session).equals(oldItem.getItemData(session))) { - newItem.setNetId(oldItem.getNetId()); - } else { - newItem.setNetId(session.getNextItemNetId()); - } - session.getPlayerInventory().setCursor(newItem); + session.getPlayerInventory().setCursor(newItem, session); InventoryUtils.updateCursor(session); return; } diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java index a15b5a1c7..854654fb7 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -79,7 +79,7 @@ public class InventoryUtils { } public static void closeInventory(GeyserSession session, int windowId) { - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY); + session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); updateCursor(session); Inventory inventory = getInventory(session, windowId); From 2a5c134ea7cc2d86bede701a7f53fa46dbd07029 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 1 Jan 2021 14:22:26 -0500 Subject: [PATCH 031/101] Update server inventory copyrights to 2021 --- .../connector/inventory/AnvilContainer.java | 2 +- .../inventory/CartographyContainer.java | 2 +- .../connector/inventory/Container.java | 2 +- .../inventory/EnchantingContainer.java | 2 +- .../inventory/GeyserEnchantOption.java | 2 +- .../connector/inventory/GeyserItemStack.java | 37 +++++++++---------- .../connector/inventory/LecternContainer.java | 2 +- .../inventory/MerchantContainer.java | 37 +++++++++---------- .../BedrockItemStackRequestTranslator.java | 37 +++++++++---------- .../BedrockLecternUpdateTranslator.java | 2 +- .../inventory/BedrockContainerSlot.java | 37 +++++++++---------- .../translators/inventory/click/Click.java | 2 +- .../inventory/click/ClickPlan.java | 2 +- .../translators/AnvilInventoryTranslator.java | 2 +- .../BeaconInventoryTranslator.java | 2 +- .../CartographyInventoryTranslator.java | 2 +- .../CraftingInventoryTranslator.java | 2 +- .../EnchantingInventoryTranslator.java | 2 +- .../GenericBlockInventoryTranslator.java | 2 +- .../LecternInventoryTranslator.java | 2 +- .../translators/LoomInventoryTranslator.java | 2 +- .../MerchantInventoryTranslator.java | 2 +- .../ShulkerInventoryTranslator.java | 2 +- .../StonecutterInventoryTranslator.java | 2 +- .../BlastFurnaceInventoryTranslator.java | 2 +- .../furnace/FurnaceInventoryTranslator.java | 2 +- .../furnace/SmokerInventoryTranslator.java | 2 +- .../AbstractHorseInventoryTranslator.java | 2 +- .../ChestedHorseInventoryTranslator.java | 2 +- .../horse/DonkeyInventoryTranslator.java | 2 +- .../horse/HorseInventoryTranslator.java | 2 +- .../horse/LlamaInventoryTranslator.java | 2 +- .../updater/HorseInventoryUpdater.java | 2 +- .../window/JavaOpenHorseWindowTranslator.java | 2 +- .../entity/BeaconBlockEntityTranslator.java | 2 +- 35 files changed, 103 insertions(+), 107 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/inventory/AnvilContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/AnvilContainer.java index aba360a0d..02e1c225e 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/AnvilContainer.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/AnvilContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/inventory/CartographyContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/CartographyContainer.java index 7e6d1cc79..be4abd9e1 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/CartographyContainer.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/CartographyContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Container.java b/connector/src/main/java/org/geysermc/connector/inventory/Container.java index 9768520bd..520a76ef3 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Container.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Container.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/inventory/EnchantingContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/EnchantingContainer.java index ab0e544d2..8638e6eab 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/EnchantingContainer.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/EnchantingContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/inventory/GeyserEnchantOption.java b/connector/src/main/java/org/geysermc/connector/inventory/GeyserEnchantOption.java index ae4a9cf4e..a643fc194 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/GeyserEnchantOption.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/GeyserEnchantOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java index 46cf8529a..a5cfb46ca 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java @@ -1,27 +1,26 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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: + * 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 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 + * 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.inventory; diff --git a/connector/src/main/java/org/geysermc/connector/inventory/LecternContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/LecternContainer.java index 0ce9217d7..1b686a8f3 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/LecternContainer.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/LecternContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/inventory/MerchantContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/MerchantContainer.java index a33f81477..f4f2d90eb 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/MerchantContainer.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/MerchantContainer.java @@ -1,27 +1,26 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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: + * 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 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 + * 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.inventory; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java index 65083ddef..03aaf3ba8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java @@ -1,27 +1,26 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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: + * 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 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 + * 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.translators.bedrock; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockLecternUpdateTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockLecternUpdateTranslator.java index 1ba08646c..832d13471 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockLecternUpdateTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockLecternUpdateTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BedrockContainerSlot.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BedrockContainerSlot.java index b3a09e167..47d1f0709 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BedrockContainerSlot.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BedrockContainerSlot.java @@ -1,27 +1,26 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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: + * 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 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 + * 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.translators.inventory; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/Click.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/Click.java index d27290bff..fe4ac8bf9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/Click.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/Click.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java index 5bfe197e5..e2d554e2f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java index d4684057c..b131544b2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java index 6407b9b39..5b31c83ba 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CartographyInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CartographyInventoryTranslator.java index 9c4eee1f2..047944336 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CartographyInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CartographyInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CraftingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CraftingInventoryTranslator.java index 77eeee17b..359a4559e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CraftingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CraftingInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java index 50e8ec6ac..4d105d423 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java index b54278bcf..55df41c1e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java index 0eabf951f..9ce0ee0d1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java index 7fbca6e92..bac9e7ae6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/MerchantInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/MerchantInventoryTranslator.java index c19a81be6..7422c7e48 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/MerchantInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/MerchantInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/ShulkerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/ShulkerInventoryTranslator.java index a0c4383ef..43584df41 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/ShulkerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/ShulkerInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java index 419e80603..fe21969d0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/BlastFurnaceInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/BlastFurnaceInventoryTranslator.java index b7834dde9..ed9a8a79c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/BlastFurnaceInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/BlastFurnaceInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/FurnaceInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/FurnaceInventoryTranslator.java index f3d759412..b41c9b03b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/FurnaceInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/FurnaceInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/SmokerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/SmokerInventoryTranslator.java index 75eb33d97..2b9a78c7d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/SmokerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/furnace/SmokerInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/AbstractHorseInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/AbstractHorseInventoryTranslator.java index b33542d39..6c6c9a0c2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/AbstractHorseInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/AbstractHorseInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/ChestedHorseInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/ChestedHorseInventoryTranslator.java index 3031e45a8..f74c2d361 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/ChestedHorseInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/ChestedHorseInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/DonkeyInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/DonkeyInventoryTranslator.java index 61a8d6926..bf13bd6da 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/DonkeyInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/DonkeyInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/HorseInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/HorseInventoryTranslator.java index 957933a02..09a8f5de3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/HorseInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/HorseInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/LlamaInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/LlamaInventoryTranslator.java index 523a1d3e7..cea605f83 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/LlamaInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/LlamaInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/HorseInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/HorseInventoryUpdater.java index 2f88c49cd..838e59d78 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/HorseInventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/HorseInventoryUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenHorseWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenHorseWindowTranslator.java index 3d205d2a9..e5748616d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenHorseWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenHorseWindowTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BeaconBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BeaconBlockEntityTranslator.java index f60b0daab..147651a18 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BeaconBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BeaconBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2021 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 From 528a9a4431bd994f83d880297c823dc330f4e7d4 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Fri, 1 Jan 2021 18:37:33 -0900 Subject: [PATCH 032/101] Crafting table slot mappings --- .../translators/CraftingInventoryTranslator.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CraftingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CraftingInventoryTranslator.java index 359a4559e..81769c00a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CraftingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CraftingInventoryTranslator.java @@ -67,4 +67,12 @@ public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslato } return super.bedrockSlotToJava(slotInfoData); } + + @Override + public int javaSlotToBedrock(int slot) { + if (slot < size) { + return slot == 0 ? 50 : slot + 31; + } + return super.javaSlotToBedrock(slot); + } } From 8928d554a1a8dde5e4d826afbb809b57358b409f Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sun, 3 Jan 2021 17:54:26 -0900 Subject: [PATCH 033/101] WIP autocrafting using java recipe book work in progress. many edge cases are currently unhandled. will not work at all pre 1.12. (support is planned) --- .../network/session/GeyserSession.java | 3 + .../inventory/InventoryTranslator.java | 86 ++++++++++++++----- .../translators/inventory/click/Click.java | 6 +- .../inventory/click/ClickPlan.java | 16 +++- .../java/JavaDeclareRecipesTranslator.java | 1 + .../java/JavaUnlockRecipesTranslator.java | 48 +++++++++++ 6 files changed, 130 insertions(+), 30 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/JavaUnlockRecipesTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 10a58360c..e2587ee08 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -61,6 +61,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2LongMap; import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectIterator; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import lombok.AccessLevel; import lombok.Getter; import lombok.NonNull; @@ -230,6 +231,7 @@ public class GeyserSession implements CommandSender { @Setter private Int2ObjectMap craftingRecipes; + private final Set unlockedRecipes; /** * Saves a list of all stonecutter recipes, for use in a stonecutter inventory. @@ -382,6 +384,7 @@ public class GeyserSession implements CommandSender { this.openInventory = null; this.inventoryFuture = CompletableFuture.completedFuture(null); this.craftingRecipes = new Int2ObjectOpenHashMap<>(); + this.unlockedRecipes = new ObjectOpenHashSet<>(); this.spawned = false; this.loggedIn = false; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index ffc8d02fa..bf2fb36cf 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -27,8 +27,12 @@ package org.geysermc.connector.network.translators.inventory; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; +import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; +import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientPrepareCraftingGridPacket; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; @@ -552,7 +556,8 @@ public abstract class InventoryTranslator { int recipeId = 0; int resultSize = 0; - boolean autoCraft; + int timesCrafted = 0; + boolean autoCraft = false; CraftState craftState = CraftState.START; int leftover = 0; @@ -566,28 +571,30 @@ public abstract class InventoryTranslator { } craftState = CraftState.RECIPE_ID; recipeId = craftAction.getRecipeNetworkId(); - //System.out.println(session.getCraftingRecipes().get(recipeId)); autoCraft = false; break; } -// case CRAFT_RECIPE_AUTO: { -// AutoCraftRecipeStackRequestActionData autoCraftAction = (AutoCraftRecipeStackRequestActionData) action; -// if (craftState != CraftState.START) { -// return rejectRequest(request); -// } -// craftState = CraftState.RECIPE_ID; -// recipeId = autoCraftAction.getRecipeNetworkId(); -// Recipe recipe = session.getCraftingRecipes().get(recipeId); -// System.out.println(recipe); -// if (recipe == null) { -// return rejectRequest(request); -// } -//// ClientPrepareCraftingGridPacket packet = new ClientPrepareCraftingGridPacket(session.getOpenInventory().getId(), recipe.getIdentifier(), true); -//// session.sendDownstreamPacket(packet); -// autoCraft = true; -// //TODO: reject transaction if crafting grid is not clear -// break; -// } + case CRAFT_RECIPE_AUTO: { + AutoCraftRecipeStackRequestActionData autoCraftAction = (AutoCraftRecipeStackRequestActionData) action; + if (craftState != CraftState.START) { + return rejectRequest(request); + } + craftState = CraftState.RECIPE_ID; + + recipeId = autoCraftAction.getRecipeNetworkId(); + if (!plan.getCursor().isEmpty()) { + return rejectRequest(request); + } + //reject if crafting grid is not clear + int gridSize = inventory.getId() == 0 ? 4 : 9; + for (int i = 1; i <= gridSize; i++) { + if (!inventory.getItem(i).isEmpty()) { + return rejectRequest(request); + } + } + autoCraft = true; + break; + } case CRAFT_RESULTS_DEPRECATED: { CraftResultsDeprecatedStackRequestActionData deprecatedCraftAction = (CraftResultsDeprecatedStackRequestActionData) action; if (craftState != CraftState.RECIPE_ID) { @@ -599,7 +606,8 @@ public abstract class InventoryTranslator { return rejectRequest(request); } resultSize = deprecatedCraftAction.getResultItems()[0].getCount(); - if (resultSize <= 0) { + timesCrafted = deprecatedCraftAction.getTimesCrafted(); + if (resultSize <= 0 || timesCrafted <= 0) { return rejectRequest(request); } break; @@ -628,11 +636,45 @@ public abstract class InventoryTranslator { } int sourceSlot = bedrockSlotToJava(transferAction.getSource()); + int destSlot = bedrockSlotToJava(transferAction.getDestination()); + + if (autoCraft) { + Recipe recipe = session.getCraftingRecipes().get(recipeId); + //cannot use java recipe book if recipe is locked + if (recipe == null || !session.getUnlockedRecipes().contains(recipe.getIdentifier())) { + return rejectRequest(request); + } + + boolean cursorDest = isCursor(transferAction.getDestination()); + boolean makeAll = timesCrafted > 1; + if (cursorDest) { + makeAll = false; + } + + ClientPrepareCraftingGridPacket prepareCraftingPacket = new ClientPrepareCraftingGridPacket(inventory.getId(), recipe.getIdentifier(), makeAll); + session.sendDownstreamPacket(prepareCraftingPacket); + + ItemStack output = null; + switch (recipe.getType()) { + case CRAFTING_SHAPED: + output = ((ShapedRecipeData)recipe.getData()).getResult(); + break; + case CRAFTING_SHAPELESS: + output = ((ShapelessRecipeData)recipe.getData()).getResult(); + break; + } + inventory.setItem(0, GeyserItemStack.from(output), session); + + plan.add(cursorDest ? Click.LEFT : Click.LEFT_SHIFT, 0); + plan.execute(true); + + return acceptRequest(request, makeContainerEntries(session, inventory, Collections.emptySet())); + } + if (isCursor(transferAction.getDestination())) { plan.add(Click.LEFT, sourceSlot); craftState = CraftState.DONE; } else { - int destSlot = bedrockSlotToJava(transferAction.getDestination()); if (leftover != 0) { if (transferAction.getCount() > leftover) { return rejectRequest(request); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/Click.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/Click.java index fe4ac8bf9..d3666a9e9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/Click.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/Click.java @@ -25,16 +25,14 @@ package org.geysermc.connector.network.translators.inventory.click; -import com.github.steveice10.mc.protocol.data.game.window.ClickItemParam; -import com.github.steveice10.mc.protocol.data.game.window.DropItemParam; -import com.github.steveice10.mc.protocol.data.game.window.WindowAction; -import com.github.steveice10.mc.protocol.data.game.window.WindowActionParam; +import com.github.steveice10.mc.protocol.data.game.window.*; import lombok.AllArgsConstructor; @AllArgsConstructor public enum Click { LEFT(WindowAction.CLICK_ITEM, ClickItemParam.LEFT_CLICK), RIGHT(WindowAction.CLICK_ITEM, ClickItemParam.RIGHT_CLICK), + LEFT_SHIFT(WindowAction.SHIFT_CLICK_ITEM, ShiftClickItemParam.LEFT_CLICK), DROP_ONE(WindowAction.DROP_ITEM, DropItemParam.DROP_FROM_SELECTED), DROP_ALL(WindowAction.DROP_ITEM, DropItemParam.DROP_SELECTED_STACK), LEFT_OUTSIDE(WindowAction.CLICK_ITEM, ClickItemParam.LEFT_CLICK), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java index 830a9ce0b..9268cbf12 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java @@ -166,10 +166,15 @@ public class ClickPlan { GeyserItemStack clicked = simulating ? getItem(action.slot) : inventory.getItem(action.slot); if (translator.getSlotType(action.slot) == SlotType.OUTPUT) { - if (cursor.isEmpty() && !clicked.isEmpty()) { - setCursor(clicked.copy()); - } else if (InventoryUtils.canStack(cursor, clicked)) { - cursor.add(clicked.getAmount()); + switch (action.click) { + case LEFT: + case RIGHT: + if (cursor.isEmpty() && !clicked.isEmpty()) { + setCursor(clicked.copy()); + } else if (InventoryUtils.canStack(cursor, clicked)) { + cursor.add(clicked.getAmount()); + } + break; } } else { switch (action.click) { @@ -195,6 +200,9 @@ public class ClickPlan { clicked.add(1); } break; + case LEFT_SHIFT: + //TODO + break; case DROP_ONE: if (!clicked.isEmpty()) { clicked.sub(1); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java index ed0abe108..31726cc5c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -183,6 +183,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator { + + @Override + public void translate(ServerUnlockRecipesPacket packet, GeyserSession session) { + if (packet.getAction() == UnlockRecipesAction.REMOVE) { + session.getUnlockedRecipes().removeAll(Arrays.asList(packet.getRecipes())); + } else { + session.getUnlockedRecipes().addAll(Arrays.asList(packet.getRecipes())); + } + } +} + From 50f295b4cd6a441a0ebd46cd0f83de72b390e9ba Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 4 Jan 2021 18:19:43 -0500 Subject: [PATCH 034/101] Remove unneeded GeyserItemStack constructor and add comments --- .../org/geysermc/connector/inventory/GeyserItemStack.java | 6 +----- .../network/translators/inventory/InventoryTranslator.java | 4 ++-- .../translators/StonecutterInventoryTranslator.java | 2 +- .../translators/java/JavaDeclareRecipesTranslator.java | 5 +++++ .../translators/java/JavaUnlockRecipesTranslator.java | 3 +++ 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java index 6c6cf9110..76f7674a9 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java @@ -91,11 +91,7 @@ public class GeyserItemStack { } public static GeyserItemStack from(ItemStack itemStack) { - return from(itemStack, 1); - } - - public static GeyserItemStack from(ItemStack itemStack, int netId) { - return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getNbt(), netId); + return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getNbt()); } public ItemStack getItemStack() { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index bf2fb36cf..f0f734fcf 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -757,7 +757,7 @@ public abstract class InventoryTranslator { ItemStack javaCreativeItem = ItemTranslator.translateToJava(creativeItem); if (isCursor(transferAction.getDestination())) { - session.getPlayerInventory().setCursor(GeyserItemStack.from(javaCreativeItem, session.getNextItemNetId()), session); + session.getPlayerInventory().setCursor(GeyserItemStack.from(javaCreativeItem), session); return acceptRequest(request, Collections.singletonList( new ItemStackResponsePacket.ContainerEntry(ContainerSlotType.CURSOR, Collections.singletonList(makeItemEntry(0, session.getPlayerInventory().getCursor()))))); @@ -769,7 +769,7 @@ public abstract class InventoryTranslator { existingItem.setAmount(existingItem.getAmount() + transferAction.getCount()); javaCreativeItem = existingItem.getItemStack(); } else { - inventory.setItem(javaSlot, GeyserItemStack.from(javaCreativeItem, session.getNextItemNetId()), session); + inventory.setItem(javaSlot, GeyserItemStack.from(javaCreativeItem), session); } ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( javaSlot, diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java index fe21969d0..0168d0ef9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java @@ -86,7 +86,7 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl container.setStonecutterButton(button); if (inventory.getItem(1).getJavaId() != javaOutput.getId()) { // We don't know there is an output here, so we tell ourselves that there is - inventory.setItem(1, GeyserItemStack.from(javaOutput, session.getNextItemNetId()), session); + inventory.setItem(1, GeyserItemStack.from(javaOutput), session); } } return translateRequest(session, inventory, request); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java index 31726cc5c..2565c6abb 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -47,6 +47,11 @@ import org.geysermc.connector.network.translators.item.*; import java.util.*; import java.util.stream.Collectors; +/** + * Used to send all valid recipes from Java to Bedrock. + * + * Bedrock REQUIRES a CraftingDataPacket to be sent in order to craft anything. + */ @Translator(packet = ServerDeclareRecipesPacket.class) public class JavaDeclareRecipesTranslator extends PacketTranslator { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaUnlockRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaUnlockRecipesTranslator.java index 6b6aefc33..0a0ba4d2d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaUnlockRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaUnlockRecipesTranslator.java @@ -33,6 +33,9 @@ import org.geysermc.connector.network.translators.Translator; import java.util.Arrays; +/** + * Used to list recipes that we can definitely use the recipe book for (and therefore save on packet usage) + */ @Translator(packet = ServerUnlockRecipesPacket.class) public class JavaUnlockRecipesTranslator extends PacketTranslator { From a160e3694b2574c8214fac796f80d84672fd600d Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 4 Jan 2021 14:47:48 -0900 Subject: [PATCH 035/101] Add stackSize to ItemEntry --- .../network/translators/item/ItemEntry.java | 3 ++- .../network/translators/item/ItemRegistry.java | 12 ++++++++---- .../network/translators/item/ToolItemEntry.java | 4 ++-- connector/src/main/resources/mappings | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemEntry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemEntry.java index f61c3d709..278d708f9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemEntry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemEntry.java @@ -34,7 +34,7 @@ import lombok.ToString; @ToString public class ItemEntry { - public static ItemEntry AIR = new ItemEntry("minecraft:air", "minecraft:air", 0, 0, 0, false); + public static ItemEntry AIR = new ItemEntry("minecraft:air", "minecraft:air", 0, 0, 0, false, 64); private final String javaIdentifier; private final String bedrockIdentifier; @@ -43,6 +43,7 @@ public class ItemEntry { private final int bedrockData; private final boolean block; + private final int stackSize; @Override public boolean equals(Object obj) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java index 02cd839aa..c2b60c8f4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java @@ -147,6 +147,7 @@ public class ItemRegistry { if (bedrockIdentifier == null) { throw new RuntimeException("Missing Bedrock ID in mappings!: " + bedrockId); } + int stackSize = entry.getValue().get("stack_size") == null ? 64 : entry.getValue().get("stack_size").intValue(); if (entry.getValue().has("tool_type")) { if (entry.getValue().has("tool_tier")) { ITEM_ENTRIES.put(itemIndex, new ToolItemEntry( @@ -154,19 +155,22 @@ public class ItemRegistry { entry.getValue().get("bedrock_data").intValue(), entry.getValue().get("tool_type").textValue(), entry.getValue().get("tool_tier").textValue(), - entry.getValue().get("is_block") != null && entry.getValue().get("is_block").booleanValue())); + entry.getValue().get("is_block") != null && entry.getValue().get("is_block").booleanValue(), + stackSize)); } else { ITEM_ENTRIES.put(itemIndex, new ToolItemEntry( entry.getKey(), bedrockIdentifier, itemIndex, bedrockId, entry.getValue().get("bedrock_data").intValue(), entry.getValue().get("tool_type").textValue(), - "", entry.getValue().get("is_block").booleanValue())); + "", entry.getValue().get("is_block").booleanValue(), + stackSize)); } } else { ITEM_ENTRIES.put(itemIndex, new ItemEntry( entry.getKey(), bedrockIdentifier, itemIndex, bedrockId, entry.getValue().get("bedrock_data").intValue(), - entry.getValue().get("is_block") != null && entry.getValue().get("is_block").booleanValue())); + entry.getValue().get("is_block") != null && entry.getValue().get("is_block").booleanValue(), + stackSize)); } switch (entry.getKey()) { case "minecraft:barrier": @@ -209,7 +213,7 @@ public class ItemRegistry { // Add the loadstone compass since it doesn't exist on java but we need it for item conversion ITEM_ENTRIES.put(itemIndex, new ItemEntry("minecraft:lodestone_compass", "minecraft:lodestone_compass", itemIndex, - lodestoneCompassId, 0, false)); + lodestoneCompassId, 0, false, 1)); /* Load creative items */ stream = FileUtils.getResource("bedrock/creative_items.json"); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ToolItemEntry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ToolItemEntry.java index 5352938c0..ba1753a35 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ToolItemEntry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ToolItemEntry.java @@ -32,8 +32,8 @@ public class ToolItemEntry extends ItemEntry { private final String toolType; private final String toolTier; - public ToolItemEntry(String javaIdentifier, String bedrockIdentifier, int javaId, int bedrockId, int bedrockData, String toolType, String toolTier, boolean isBlock) { - super(javaIdentifier, bedrockIdentifier, javaId, bedrockId, bedrockData, isBlock); + public ToolItemEntry(String javaIdentifier, String bedrockIdentifier, int javaId, int bedrockId, int bedrockData, String toolType, String toolTier, boolean isBlock, int stackSize) { + super(javaIdentifier, bedrockIdentifier, javaId, bedrockId, bedrockData, isBlock, stackSize); this.toolType = toolType; this.toolTier = toolTier; } diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index 143285afb..62e39acaf 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 143285afb4bdf4d5ef40ef7a7959477dabf4d34c +Subproject commit 62e39acaf3859da86189a76fff57b30c2403ef3d From 57e176efd6572f56fc8fe3921fd32aa8b255d9f0 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 4 Jan 2021 15:12:26 -0900 Subject: [PATCH 036/101] Optimize stackSize Co-Authored-By: Camotoy <20743703+Camotoy@users.noreply.github.com> --- .../connector/network/translators/item/ItemRegistry.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java index c2b60c8f4..adb91aa3e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java @@ -147,7 +147,8 @@ public class ItemRegistry { if (bedrockIdentifier == null) { throw new RuntimeException("Missing Bedrock ID in mappings!: " + bedrockId); } - int stackSize = entry.getValue().get("stack_size") == null ? 64 : entry.getValue().get("stack_size").intValue(); + JsonNode stackSizeNode = entry.getValue().get("stack_size"); + int stackSize = stackSizeNode == null ? 64 : stackSizeNode.intValue(); if (entry.getValue().has("tool_type")) { if (entry.getValue().has("tool_tier")) { ITEM_ENTRIES.put(itemIndex, new ToolItemEntry( From ff69752d2cd434985dd44c74d960852aae5363ad Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 4 Jan 2021 15:16:21 -0900 Subject: [PATCH 037/101] Remove unnecessary is_block null check --- .../connector/network/translators/item/ItemRegistry.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java index adb91aa3e..dea9b5c9a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java @@ -156,7 +156,7 @@ public class ItemRegistry { entry.getValue().get("bedrock_data").intValue(), entry.getValue().get("tool_type").textValue(), entry.getValue().get("tool_tier").textValue(), - entry.getValue().get("is_block") != null && entry.getValue().get("is_block").booleanValue(), + entry.getValue().get("is_block").booleanValue(), stackSize)); } else { ITEM_ENTRIES.put(itemIndex, new ToolItemEntry( @@ -170,7 +170,7 @@ public class ItemRegistry { ITEM_ENTRIES.put(itemIndex, new ItemEntry( entry.getKey(), bedrockIdentifier, itemIndex, bedrockId, entry.getValue().get("bedrock_data").intValue(), - entry.getValue().get("is_block") != null && entry.getValue().get("is_block").booleanValue(), + entry.getValue().get("is_block").booleanValue(), stackSize)); } switch (entry.getKey()) { From a88678a5c10ecdaadb75cec318306b48260fe1c1 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 4 Jan 2021 22:15:55 -0500 Subject: [PATCH 038/101] Add manual recipes as Recipe classes for future usage --- .../translators/item/ItemRegistry.java | 2 +- .../translators/item/RecipeRegistry.java | 92 ++++++++++++++++--- .../translators/TippedArrowTranslator.java | 1 + .../java/JavaDeclareRecipesTranslator.java | 2 +- connector/src/main/resources/mappings | 2 +- 5 files changed, 84 insertions(+), 15 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java index dea9b5c9a..4237f7d6a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java @@ -56,7 +56,7 @@ public class ItemRegistry { * A list of all identifiers that only exist on Java. Used to prevent creative items from becoming these unintentionally. */ private static final List JAVA_ONLY_ITEMS = Arrays.asList("minecraft:spectral_arrow", "minecraft:debug_stick", - "minecraft:knowledge_book"); + "minecraft:knowledge_book", "minecraft:tipped_arrow", "minecraft:furnace_minecart"); public static final ItemData[] CREATIVE_ITEMS; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java index 4c6a872f5..cb866e6b1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java @@ -26,13 +26,25 @@ package org.geysermc.connector.network.translators.item; import com.fasterxml.jackson.databind.JsonNode; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; +import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; +import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType; +import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; +import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; +import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtUtils; import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.utils.FileUtils; import org.geysermc.connector.utils.LanguageUtils; +import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; import java.util.*; @@ -47,7 +59,7 @@ public class RecipeRegistry { */ public static int LAST_RECIPE_NET_ID = 0; - //public static final Int2ObjectMap + public static final Int2ObjectMap ALL_CRAFTING_RECIPES = new Int2ObjectOpenHashMap<>(); /** * A list of all possible leather armor dyeing recipes. @@ -131,7 +143,7 @@ public class RecipeRegistry { throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e); } - for (JsonNode entry: items.get("leather_armor")) { + for (JsonNode entry : items.get("leather_armor")) { // This won't be perfect, as we can't possibly send every leather input for every kind of color // But it does display the correct output from a base leather armor, and besides visuals everything works fine LEATHER_DYEING_RECIPES.add(getCraftingDataFromJsonNode(entry)); @@ -151,6 +163,7 @@ public class RecipeRegistry { for (JsonNode entry : items.get("tipped_arrows")) { TIPPED_ARROW_RECIPES.add(getCraftingDataFromJsonNode(entry)); } + System.out.println(ALL_CRAFTING_RECIPES); } /** @@ -159,9 +172,13 @@ public class RecipeRegistry { * @return the {@link CraftingData} to send to the Bedrock client. */ private static CraftingData getCraftingDataFromJsonNode(JsonNode node) { - ItemData output = ItemRegistry.getBedrockItemFromJson(node.get("output").get(0)); + int netId = LAST_RECIPE_NET_ID++; + int type = node.get("bedrockRecipeType").asInt(); + JsonNode outputNode = node.get("output"); + ItemEntry outputEntry = ItemRegistry.getItemEntry(outputNode.get("identifier").asText()); + ItemData output = getBedrockItemFromIdentifierJson(outputEntry, outputNode); UUID uuid = UUID.randomUUID(); - if (node.get("type").asInt() == 1) { + if (type == 1) { // Shaped recipe List shape = new ArrayList<>(); // Get the shape of the recipe @@ -171,10 +188,12 @@ public class RecipeRegistry { // In recipes.json each recipe is mapped by a letter Map letterToRecipe = new HashMap<>(); - Iterator> iterator = node.get("input").fields(); + Iterator> iterator = node.get("inputs").fields(); while (iterator.hasNext()) { Map.Entry entry = iterator.next(); - letterToRecipe.put(entry.getKey(), ItemRegistry.getBedrockItemFromJson(entry.getValue())); + JsonNode inputNode = entry.getValue(); + ItemEntry inputEntry = ItemRegistry.getItemEntry(inputNode.get("identifier").asText()); + letterToRecipe.put(entry.getKey(), getBedrockItemFromIdentifierJson(inputEntry, inputNode)); } List inputs = new ArrayList<>(shape.size() * shape.get(0).length()); @@ -188,20 +207,69 @@ public class RecipeRegistry { } } + /* Convert into a Java recipe class for autocrafting */ + List ingredients = new ArrayList<>(); + for (ItemData input : inputs) { + ingredients.add(new Ingredient(new ItemStack[]{ItemTranslator.translateToJava(input)})); + } + ShapedRecipeData data = new ShapedRecipeData(shape.get(0).length(), shape.size(), "crafting_table", + ingredients.toArray(new Ingredient[0]), ItemTranslator.translateToJava(output)); + Recipe recipe = new Recipe(RecipeType.CRAFTING_SHAPED, "", data); + ALL_CRAFTING_RECIPES.put(netId, recipe); + /* Convert end */ + return CraftingData.fromShaped(uuid.toString(), shape.get(0).length(), shape.size(), - inputs, Collections.singletonList(output), uuid, "crafting_table", 0, LAST_RECIPE_NET_ID++); + inputs, Collections.singletonList(output), uuid, "crafting_table", 0, netId); } List inputs = new ObjectArrayList<>(); - for (JsonNode entry : node.get("input")) { - inputs.add(ItemRegistry.getBedrockItemFromJson(entry)); + for (JsonNode entry : node.get("inputs")) { + ItemEntry inputEntry = ItemRegistry.getItemEntry(entry.get("identifier").asText()); + inputs.add(getBedrockItemFromIdentifierJson(inputEntry, entry)); } - if (node.get("type").asInt() == 5) { + + /* Convert into a Java Recipe class for autocrafting */ + List ingredients = new ArrayList<>(); + for (ItemData input : inputs) { + ingredients.add(new Ingredient(new ItemStack[]{ItemTranslator.translateToJava(input)})); + } + ShapelessRecipeData data = new ShapelessRecipeData("crafting_table", + ingredients.toArray(new Ingredient[0]), ItemTranslator.translateToJava(output)); + Recipe recipe = new Recipe(RecipeType.CRAFTING_SHAPELESS, "", data); + ALL_CRAFTING_RECIPES.put(netId, recipe); + /* Convert end */ + + if (type == 5) { // Shulker box return CraftingData.fromShulkerBox(uuid.toString(), - inputs, Collections.singletonList(output), uuid, "crafting_table", 0, LAST_RECIPE_NET_ID++); + inputs, Collections.singletonList(output), uuid, "crafting_table", 0, netId); } return CraftingData.fromShapeless(uuid.toString(), - inputs, Collections.singletonList(output), uuid, "crafting_table", 0, LAST_RECIPE_NET_ID++); + inputs, Collections.singletonList(output), uuid, "crafting_table", 0, netId); + } + + private static ItemData getBedrockItemFromIdentifierJson(ItemEntry itemEntry, JsonNode itemNode) { + int count = 1; + short damage = 0; + NbtMap tag = null; + JsonNode damageNode = itemNode.get("bedrockDamage"); + if (damageNode != null) { + damage = damageNode.numberValue().shortValue(); + } + JsonNode countNode = itemNode.get("count"); + if (countNode != null) { + count = countNode.asInt(); + } + JsonNode nbtNode = itemNode.get("bedrockNbt"); + if (nbtNode != null) { + byte[] bytes = Base64.getDecoder().decode(nbtNode.asText()); + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + try { + tag = (NbtMap) NbtUtils.createReaderLE(bais).readTag(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return ItemData.of(itemEntry.getBedrockId(), damage, count, tag); } public static void init() { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java index dd151dcd8..c33b71ac5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java @@ -70,6 +70,7 @@ public class TippedArrowTranslator extends ItemTranslator { @Override public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { + GeyserConnector.getInstance().getLogger().warning(itemData.toString() + " " + itemEntry.getJavaIdentifier()); TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByBedrockId(itemData.getDamage()); ItemStack itemStack = super.translateToJava(itemData, itemEntry); if (tippedArrowPotion != null) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java index 2565c6abb..3b4f14d71 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -59,7 +59,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator recipeMap = new Int2ObjectOpenHashMap<>(); + Int2ObjectMap recipeMap = new Int2ObjectOpenHashMap<>(RecipeRegistry.ALL_CRAFTING_RECIPES); Int2ObjectMap> unsortedStonecutterData = new Int2ObjectOpenHashMap<>(); CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); craftingDataPacket.setCleanRecipes(true); diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index 62e39acaf..07f65c380 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 62e39acaf3859da86189a76fff57b30c2403ef3d +Subproject commit 07f65c3803dcd3f83358ee574e54bf129cad0840 From c8016647f21c67ee2f7452c30b5be9a40a65610c Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 5 Jan 2021 19:08:54 -0500 Subject: [PATCH 039/101] Clean up and add mobile button for horse opening --- .../entity/player/BedrockInteractTranslator.java | 12 +++++++++--- .../network/translators/item/RecipeRegistry.java | 5 ++++- .../item/translators/TippedArrowTranslator.java | 1 - 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java index c7c596d8d..ca71a1975 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java @@ -39,6 +39,7 @@ import com.nukkitx.protocol.bedrock.packet.InteractPacket; import lombok.Getter; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.living.animal.horse.AbstractHorseEntity; +import org.geysermc.connector.entity.living.animal.horse.HorseEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.network.session.GeyserSession; @@ -212,6 +213,11 @@ public class BedrockInteractTranslator extends PacketTranslator case SKELETON_HORSE: case TRADER_LLAMA: case ZOMBIE_HORSE: + boolean tamed = entityMetadata.getFlags().getFlag(EntityFlag.TAMED); + if (session.isSneaking() && tamed && (interactEntity instanceof HorseEntity || entityMetadata.getFlags().getFlag(EntityFlag.CHESTED))) { + interactiveTag = InteractiveTag.OPEN_CONTAINER; + break; + } // have another switch statement as, while these share mount attributes they don't share food switch (interactEntity.getEntityType()) { case LLAMA: @@ -230,9 +236,9 @@ public class BedrockInteractTranslator extends PacketTranslator } if (!entityMetadata.getFlags().getFlag(EntityFlag.BABY)) { // Can't ride a baby - if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED)) { + if (tamed) { interactiveTag = InteractiveTag.RIDE_HORSE; - } else if (!entityMetadata.getFlags().getFlag(EntityFlag.TAMED) && itemEntry.equals(ItemEntry.AIR)) { + } else if (itemEntry.equals(ItemEntry.AIR)) { // Can't hide an untamed entity without having your hand empty interactiveTag = InteractiveTag.MOUNT; } @@ -351,7 +357,7 @@ public class BedrockInteractTranslator extends PacketTranslator } else { if (!session.getPlayerEntity().getMetadata().getString(EntityData.INTERACTIVE_TAG).isEmpty()) { // No interactive tag should be sent - session.getPlayerEntity().getMetadata().remove(EntityData.INTERACTIVE_TAG); + session.getPlayerEntity().getMetadata().put(EntityData.INTERACTIVE_TAG, ""); session.getPlayerEntity().updateBedrockMetadata(session); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java index cb866e6b1..110014bf5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java @@ -59,6 +59,10 @@ public class RecipeRegistry { */ public static int LAST_RECIPE_NET_ID = 0; + /** + * A list of all the following crafting recipes, but in a format understood by Java servers. + * Used for console autocrafting. + */ public static final Int2ObjectMap ALL_CRAFTING_RECIPES = new Int2ObjectOpenHashMap<>(); /** @@ -163,7 +167,6 @@ public class RecipeRegistry { for (JsonNode entry : items.get("tipped_arrows")) { TIPPED_ARROW_RECIPES.add(getCraftingDataFromJsonNode(entry)); } - System.out.println(ALL_CRAFTING_RECIPES); } /** diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java index c33b71ac5..dd151dcd8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java @@ -70,7 +70,6 @@ public class TippedArrowTranslator extends ItemTranslator { @Override public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { - GeyserConnector.getInstance().getLogger().warning(itemData.toString() + " " + itemEntry.getJavaIdentifier()); TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByBedrockId(itemData.getDamage()); ItemStack itemStack = super.translateToJava(itemData, itemEntry); if (tippedArrowPotion != null) { From 9118ec68406e6ff8c0498c9253f43bc6d3adc9aa Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Fri, 8 Jan 2021 17:01:31 -0900 Subject: [PATCH 040/101] wip support old crafting --- .../network/session/GeyserSession.java | 2 + .../inventory/InventoryTranslator.java | 7 +-- .../java/JavaDeclareRecipesTranslator.java | 3 +- .../java/window/JavaSetSlotTranslator.java | 62 +++++++++++++++++++ 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index e2587ee08..4287c24f6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -232,6 +232,7 @@ public class GeyserSession implements CommandSender { @Setter private Int2ObjectMap craftingRecipes; private final Set unlockedRecipes; + private AtomicInteger lastRecipeNetId; /** * Saves a list of all stonecutter recipes, for use in a stonecutter inventory. @@ -385,6 +386,7 @@ public class GeyserSession implements CommandSender { this.inventoryFuture = CompletableFuture.completedFuture(null); this.craftingRecipes = new Int2ObjectOpenHashMap<>(); this.unlockedRecipes = new ObjectOpenHashSet<>(); + this.lastRecipeNetId = new AtomicInteger(1); this.spawned = false; this.loggedIn = false; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index f0f734fcf..4c1c55976 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -805,13 +805,12 @@ public abstract class InventoryTranslator { } public boolean checkNetId(GeyserSession session, Inventory inventory, StackRequestSlotInfoData slotInfoData) { - if (slotInfoData.getStackNetworkId() < 0) + int netId = slotInfoData.getStackNetworkId(); + if (netId < 0 || netId == 1) return true; -// if (slotInfoData.getContainer() == ContainerSlotType.CURSOR) //TODO: temporary -// return true; GeyserItemStack currentItem = isCursor(slotInfoData) ? session.getPlayerInventory().getCursor() : inventory.getItem(bedrockSlotToJava(slotInfoData)); - return currentItem.getNetId() == slotInfoData.getStackNetworkId(); + return currentItem.getNetId() == netId; } /** diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java index 3b4f14d71..7624bf868 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -186,10 +186,11 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator { @@ -55,6 +67,56 @@ public class JavaSetSlotTranslator extends PacketTranslator InventoryTranslator translator = session.getInventoryTranslator(); if (translator != null) { + if (packet.getSlot() == 0) { + int gridSize = -1; + if (translator instanceof PlayerInventoryTranslator) { + gridSize = 4; + } + if (translator instanceof CraftingInventoryTranslator) { + gridSize = 9; + } + if (gridSize != -1) { + int offset = gridSize == 4 ? 28 : 32; + int gridWidth = gridSize == 4 ? 2 : 3; + ItemData[] ingredients = new ItemData[gridSize]; + //construct ingredient list and clear slots on client + for (int i = 0; i < gridSize; i++) { + ingredients[i] = inventory.getItem(i + 1).getItemData(session); + + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(ContainerId.UI); + slotPacket.setSlot(i + offset); + slotPacket.setItem(ItemData.AIR); + session.sendUpstreamPacket(slotPacket); + } + + CraftingDataPacket craftPacket = new CraftingDataPacket(); + UUID uuid = UUID.fromString("e0a4971a-698c-40fb-95dd-afc8ed16e108"); + craftPacket.getCraftingData().add(CraftingData.fromShaped( + uuid.toString(), + gridWidth, + gridWidth, + Arrays.asList(ingredients), + Collections.singletonList(ItemTranslator.translateToBedrock(session, packet.getItem())), + uuid, + "crafting_table", + 0, + session.getLastRecipeNetId().incrementAndGet() + )); + craftPacket.setCleanRecipes(false); + session.sendUpstreamPacket(craftPacket); + + //restore cleared slots + for (int i = 0; i < gridSize; i++) { + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(ContainerId.UI); + slotPacket.setSlot(i + offset); + slotPacket.setItem(ingredients[i]); + session.sendUpstreamPacket(slotPacket); + } + } + } + GeyserItemStack newItem = GeyserItemStack.from(packet.getItem()); inventory.setItem(packet.getSlot(), newItem, session); translator.updateSlot(session, inventory, packet.getSlot()); From 9bfc5d320ca0a9e8e36300a78727e2ae47f29a8a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 9 Jan 2021 00:38:53 -0500 Subject: [PATCH 041/101] Work-in-progress checks for legacy slot checking --- .../java/JavaDeclareRecipesTranslator.java | 2 +- .../java/window/JavaSetSlotTranslator.java | 197 +++++++++++++----- 2 files changed, 149 insertions(+), 50 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java index 7624bf868..07b839f9c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -186,7 +186,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator InventoryTranslator translator = session.getInventoryTranslator(); if (translator != null) { - if (packet.getSlot() == 0) { - int gridSize = -1; - if (translator instanceof PlayerInventoryTranslator) { - gridSize = 4; - } - if (translator instanceof CraftingInventoryTranslator) { - gridSize = 9; - } - if (gridSize != -1) { - int offset = gridSize == 4 ? 28 : 32; - int gridWidth = gridSize == 4 ? 2 : 3; - ItemData[] ingredients = new ItemData[gridSize]; - //construct ingredient list and clear slots on client - for (int i = 0; i < gridSize; i++) { - ingredients[i] = inventory.getItem(i + 1).getItemData(session); - - InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(ContainerId.UI); - slotPacket.setSlot(i + offset); - slotPacket.setItem(ItemData.AIR); - session.sendUpstreamPacket(slotPacket); - } - - CraftingDataPacket craftPacket = new CraftingDataPacket(); - UUID uuid = UUID.fromString("e0a4971a-698c-40fb-95dd-afc8ed16e108"); - craftPacket.getCraftingData().add(CraftingData.fromShaped( - uuid.toString(), - gridWidth, - gridWidth, - Arrays.asList(ingredients), - Collections.singletonList(ItemTranslator.translateToBedrock(session, packet.getItem())), - uuid, - "crafting_table", - 0, - session.getLastRecipeNetId().incrementAndGet() - )); - craftPacket.setCleanRecipes(false); - session.sendUpstreamPacket(craftPacket); - - //restore cleared slots - for (int i = 0; i < gridSize; i++) { - InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(ContainerId.UI); - slotPacket.setSlot(i + offset); - slotPacket.setItem(ingredients[i]); - session.sendUpstreamPacket(slotPacket); - } - } - } + updateCraftingGrid(session, packet, inventory, translator); GeyserItemStack newItem = GeyserItemStack.from(packet.getItem()); inventory.setItem(packet.getSlot(), newItem, session); @@ -123,4 +81,145 @@ public class JavaSetSlotTranslator extends PacketTranslator } }); } + + private void updateCraftingGrid(GeyserSession session, ServerSetSlotPacket packet, Inventory inventory, InventoryTranslator translator) { + if (packet.getSlot() == 0) { + int gridSize; + if (translator instanceof PlayerInventoryTranslator) { + gridSize = 4; + } else if (translator instanceof CraftingInventoryTranslator) { + gridSize = 9; + } else { + return; + } + + if (packet.getItem() == null || packet.getItem().getId() == 0) { + return; + } + + int offset = gridSize == 4 ? 28 : 32; + int gridDimensions = gridSize == 4 ? 2 : 3; + int itemsStart = 0; + for (int i = 1; i < inventory.getSize(); i++) { // Slot 0 is, well, the output, so we ignore that + if (!inventory.getItem(i).isEmpty()) { + System.out.println(inventory.getItem(i).getItemStack().toString()); + itemsStart = i; + break; + } + } + + System.out.println("Items start: " + itemsStart); + + //TODO + recipes: + for (Recipe recipe : session.getCraftingRecipes().values()) { + if (recipe.getType() == RecipeType.CRAFTING_SHAPED) { + ShapedRecipeData data = (ShapedRecipeData) recipe.getData(); + if (!data.getResult().equals(packet.getItem())) { + continue; + } + int height = 1; + int width = 1; + for (int i = 0; i < data.getIngredients().length; i++) { + System.out.println(height); + System.out.println(width); + System.out.println(data.getHeight()); + System.out.println(data.getWidth()); + System.out.println(Arrays.toString(data.getIngredients())); + Ingredient ingredient = data.getIngredients()[i]; + GeyserItemStack geyserItemStack = inventory.getItem(itemsStart + (width - 1) + ((data.getWidth() - 1) * (gridDimensions - data.getWidth() + height))); + System.out.println(itemsStart + (width - 1) + ((data.getWidth() - 1) * (gridDimensions - data.getWidth() + height))); + boolean inventoryHasItem = false; + for (ItemStack itemStack : ingredient.getOptions()) { + if (geyserItemStack.isEmpty()) { + inventoryHasItem = itemStack == null || itemStack.getId() == 0; + if (inventoryHasItem) { + break; + } + } else if (itemStack.equals(geyserItemStack.getItemStack())) { + inventoryHasItem = true; + break; + } + } + if (!inventoryHasItem) { + break recipes; + } + width++; + if (width > data.getWidth()) { + width = 1; + height++; + } + } + // Recipe is had, don't sent packet + return; + } else if (recipe.getType() == RecipeType.CRAFTING_SHAPELESS) { + ShapelessRecipeData data = (ShapelessRecipeData) recipe.getData(); + if (!data.getResult().equals(packet.getItem())) { + continue; + } + for (int i = 0; i < data.getIngredients().length; i++) { + Ingredient ingredient = data.getIngredients()[i]; + for (ItemStack itemStack : ingredient.getOptions()) { + boolean inventoryHasItem = false; + for (int j = 0; j < inventory.getSize(); j++) { + GeyserItemStack geyserItemStack = inventory.getItem(j); + if (geyserItemStack.isEmpty()) { + inventoryHasItem = itemStack == null || itemStack.getId() == 0; + if (inventoryHasItem) { + break; + } + } else if (itemStack.equals(geyserItemStack.getItemStack())) { + inventoryHasItem = true; + break; + } + } + if (!inventoryHasItem) { + continue recipes; + } + } + } + // Recipe is had, don't sent packet + return; + } + } + System.out.println("Sending packet!"); + + ItemData[] ingredients = new ItemData[gridSize]; + //construct ingredient list and clear slots on client + for (int i = 0; i < gridSize; i++) { + ingredients[i] = inventory.getItem(i + 1).getItemData(session); + + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(ContainerId.UI); + slotPacket.setSlot(i + offset); + slotPacket.setItem(ItemData.AIR); + session.sendUpstreamPacket(slotPacket); + } + + CraftingDataPacket craftPacket = new CraftingDataPacket(); + UUID uuid = UUID.randomUUID(); + craftPacket.getCraftingData().add(CraftingData.fromShaped( + uuid.toString(), + gridDimensions, + gridDimensions, + Arrays.asList(ingredients), + Collections.singletonList(ItemTranslator.translateToBedrock(session, packet.getItem())), + uuid, + "crafting_table", + 0, + session.getLastRecipeNetId().incrementAndGet() + )); + craftPacket.setCleanRecipes(false); + session.sendUpstreamPacket(craftPacket); + + //restore cleared slots + for (int i = 0; i < gridSize; i++) { + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(ContainerId.UI); + slotPacket.setSlot(i + offset); + slotPacket.setItem(ingredients[i]); + session.sendUpstreamPacket(slotPacket); + } + } + } } From 554ec82ef59a3f7729914e8e926a48cf9822eb0d Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sat, 9 Jan 2021 04:10:27 -0900 Subject: [PATCH 042/101] Shaped recipe detection --- .../connector/inventory/GeyserItemStack.java | 6 +- .../java/window/JavaSetSlotTranslator.java | 110 ++++++++++++------ 2 files changed, 78 insertions(+), 38 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java index 76f7674a9..7cdaf1801 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java @@ -95,7 +95,11 @@ public class GeyserItemStack { } public ItemStack getItemStack() { - return isEmpty() ? null : new ItemStack(javaId, amount, nbt); + return getItemStack(amount); + } + + public ItemStack getItemStack(int newAmount) { + return isEmpty() ? null : new ItemStack(javaId, newAmount, nbt); } public ItemData getItemData(GeyserSession session) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java index d30060a13..39a7db11d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java @@ -50,6 +50,7 @@ import org.geysermc.connector.utils.InventoryUtils; import java.util.Arrays; import java.util.Collections; +import java.util.Objects; import java.util.UUID; @Translator(packet = ServerSetSlotPacket.class) @@ -82,7 +83,7 @@ public class JavaSetSlotTranslator extends PacketTranslator }); } - private void updateCraftingGrid(GeyserSession session, ServerSetSlotPacket packet, Inventory inventory, InventoryTranslator translator) { + private static void updateCraftingGrid(GeyserSession session, ServerSetSlotPacket packet, Inventory inventory, InventoryTranslator translator) { if (packet.getSlot() == 0) { int gridSize; if (translator instanceof PlayerInventoryTranslator) { @@ -99,16 +100,35 @@ public class JavaSetSlotTranslator extends PacketTranslator int offset = gridSize == 4 ? 28 : 32; int gridDimensions = gridSize == 4 ? 2 : 3; - int itemsStart = 0; - for (int i = 1; i < inventory.getSize(); i++) { // Slot 0 is, well, the output, so we ignore that - if (!inventory.getItem(i).isEmpty()) { - System.out.println(inventory.getItem(i).getItemStack().toString()); - itemsStart = i; - break; + int firstRow = -1, height = -1; + int firstCol = -1, width = -1; + for (int row = 0; row < gridDimensions; row++) { + for (int col = 0; col < gridDimensions; col++) { + if (!inventory.getItem(col + (row * gridDimensions) + 1).isEmpty()) { + if (firstRow == -1) { + firstRow = row; + firstCol = col; + } else { + firstCol = Math.min(firstCol, col); + } + height = Math.max(height, row); + width = Math.max(width, col); + } } } - System.out.println("Items start: " + itemsStart); + //empty grid + if (firstRow == -1) { + return; + } + + height += -firstRow + 1; + width += -firstCol + 1; + + System.out.println("Start Row: " + firstRow); + System.out.println("Start Column: " + firstCol); + System.out.println("Rows: " + height); + System.out.println("Columns: " + width); //TODO recipes: @@ -118,38 +138,27 @@ public class JavaSetSlotTranslator extends PacketTranslator if (!data.getResult().equals(packet.getItem())) { continue; } - int height = 1; - int width = 1; - for (int i = 0; i < data.getIngredients().length; i++) { - System.out.println(height); - System.out.println(width); - System.out.println(data.getHeight()); - System.out.println(data.getWidth()); - System.out.println(Arrays.toString(data.getIngredients())); - Ingredient ingredient = data.getIngredients()[i]; - GeyserItemStack geyserItemStack = inventory.getItem(itemsStart + (width - 1) + ((data.getWidth() - 1) * (gridDimensions - data.getWidth() + height))); - System.out.println(itemsStart + (width - 1) + ((data.getWidth() - 1) * (gridDimensions - data.getWidth() + height))); - boolean inventoryHasItem = false; - for (ItemStack itemStack : ingredient.getOptions()) { - if (geyserItemStack.isEmpty()) { - inventoryHasItem = itemStack == null || itemStack.getId() == 0; - if (inventoryHasItem) { - break; - } - } else if (itemStack.equals(geyserItemStack.getItemStack())) { - inventoryHasItem = true; - break; + if (data.getWidth() != width || data.getHeight() != height || width * height != data.getIngredients().length) { + continue; + } + + Ingredient[] ingredients = data.getIngredients(); + if (!testShapedRecipe(ingredients, inventory, gridDimensions, firstRow, height, firstCol, width)) { + Ingredient[] mirroredIngredients = new Ingredient[data.getIngredients().length]; + for (int row = 0; row < height; row++) { + for (int col = 0; col < width; col++) { + mirroredIngredients[col + (row * width)] = ingredients[(width - 1 - col) + (row * width)]; } } - if (!inventoryHasItem) { - break recipes; - } - width++; - if (width > data.getWidth()) { - width = 1; - height++; + + if (Arrays.equals(ingredients, mirroredIngredients)) { + continue; + } else if (!testShapedRecipe(mirroredIngredients, inventory, gridDimensions, firstRow, height, firstCol, width)) { + continue; } } + System.out.println("FOUND SHAPED RECIPE :)"); + System.out.println(recipe); // Recipe is had, don't sent packet return; } else if (recipe.getType() == RecipeType.CRAFTING_SHAPELESS) { @@ -168,7 +177,7 @@ public class JavaSetSlotTranslator extends PacketTranslator if (inventoryHasItem) { break; } - } else if (itemStack.equals(geyserItemStack.getItemStack())) { + } else if (itemStack.equals(geyserItemStack.getItemStack(1))) { inventoryHasItem = true; break; } @@ -222,4 +231,31 @@ public class JavaSetSlotTranslator extends PacketTranslator } } } + + private static boolean testShapedRecipe(Ingredient[] ingredients, Inventory inventory, int gridDimensions, int firstRow, int height, int firstCol, int width) { + int ingredientIndex = 0; + for (int row = firstRow; row < height + firstRow; row++) { + for (int col = firstCol; col < width + firstCol; col++) { + GeyserItemStack geyserItemStack = inventory.getItem(col + (row * gridDimensions) + 1); + Ingredient ingredient = ingredients[ingredientIndex++]; + if (ingredient.getOptions().length == 0) { + if (!geyserItemStack.isEmpty()) { + return false; + } + } else { + boolean inventoryHasItem = false; + for (ItemStack item : ingredient.getOptions()) { + if (Objects.equals(geyserItemStack.getItemStack(1), item)) { + inventoryHasItem = true; + break; + } + } + if (!inventoryHasItem) { + return false; + } + } + } + } + return true; + } } From 54fb56ea85d29f8ba7b1f03d2378d581fffb8e0b Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 9 Jan 2021 16:45:32 -0500 Subject: [PATCH 043/101] Add legacy crafting support for Spigot and finish up standalone --- .../platform/spigot/GeyserSpigotPlugin.java | 10 +- .../GeyserSpigot1_11CraftingListener.java | 197 ++++++++++++++++++ .../java/window/JavaSetSlotTranslator.java | 59 ++++-- 3 files changed, 244 insertions(+), 22 deletions(-) create mode 100644 bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigot1_11CraftingListener.java diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java index 74b9e03d4..86247300a 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java @@ -43,6 +43,7 @@ import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.platform.spigot.command.GeyserSpigotCommandExecutor; import org.geysermc.platform.spigot.command.GeyserSpigotCommandManager; import org.geysermc.platform.spigot.command.SpigotCommandSender; +import org.geysermc.platform.spigot.world.GeyserSpigot1_11CraftingListener; import org.geysermc.platform.spigot.world.GeyserSpigotBlockPlaceListener; import org.geysermc.platform.spigot.world.manager.*; import us.myles.ViaVersion.api.Pair; @@ -146,8 +147,9 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { geyserLogger.debug("Legacy version of Minecraft (1.15.2 or older) detected; not using 3D biomes."); } + boolean isPre1_12 = !isCompatible(Bukkit.getServer().getVersion(), "1.12.0"); // Set if we need to use a different method for getting a player's locale - SpigotCommandSender.setUseLegacyLocaleMethod(!isCompatible(Bukkit.getServer().getVersion(), "1.12.0")); + SpigotCommandSender.setUseLegacyLocaleMethod(isPre1_12); if (connector.getConfig().isUseAdapters()) { try { @@ -191,9 +193,13 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { geyserLogger.debug("Using default world manager: " + this.geyserWorldManager.getClass()); } GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(connector, this.geyserWorldManager); - Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this); + if (isPre1_12) { + // Register events needed to send all recipes to the client + Bukkit.getServer().getPluginManager().registerEvents(new GeyserSpigot1_11CraftingListener(this, connector), this); + } + this.getCommand("geyser").setExecutor(new GeyserSpigotCommandExecutor(connector)); } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigot1_11CraftingListener.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigot1_11CraftingListener.java new file mode 100644 index 000000000..d20b7637d --- /dev/null +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigot1_11CraftingListener.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2019-2021 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.platform.spigot.world; + +import com.github.steveice10.mc.protocol.MinecraftConstants; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; +import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType; +import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; +import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; +import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; +import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.inventory.Recipe; +import org.bukkit.inventory.ShapedRecipe; +import org.bukkit.inventory.ShapelessRecipe; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.item.ItemTranslator; +import org.geysermc.connector.network.translators.item.RecipeRegistry; +import org.geysermc.platform.spigot.GeyserSpigotPlugin; +import us.myles.ViaVersion.api.Pair; +import us.myles.ViaVersion.api.data.MappingData; +import us.myles.ViaVersion.api.protocol.Protocol; +import us.myles.ViaVersion.api.protocol.ProtocolRegistry; +import us.myles.ViaVersion.api.protocol.ProtocolVersion; +import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2; + +import java.util.*; + +/** + * Used to send all available recipes from the server to the client, as a valid recipe book packet won't be sent by the server. + * Requires ViaVersion. + */ +public class GeyserSpigot1_11CraftingListener implements Listener { + + private final GeyserConnector connector; + /** + * Specific mapping data for 1.12 to 1.13. Used to convert the 1.12 item into 1.13. + */ + private final MappingData mappingData1_12to1_13; + /** + * The list of all protocols from the client's version to 1.13. + */ + private final List> protocolList; + private final ProtocolVersion version; + + public GeyserSpigot1_11CraftingListener(GeyserSpigotPlugin plugin, GeyserConnector connector) { + this.connector = connector; + this.mappingData1_12to1_13 = ProtocolRegistry.getProtocol(Protocol1_13To1_12_2.class).getMappingData(); + this.protocolList = ProtocolRegistry.getProtocolPath(MinecraftConstants.PROTOCOL_VERSION, + ProtocolVersion.v1_13.getVersion()); + this.version = plugin.getServerProtocolVersion(); + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + GeyserSession session = null; + for (GeyserSession otherSession : connector.getPlayers()) { + if (otherSession.getName().equals(event.getPlayer().getName())) { + session = otherSession; + break; + } + } + if (session == null) { + return; + } + + System.out.println("Sending recipes!"); + sendServerRecipes(session); + } + + public void sendServerRecipes(GeyserSession session) { + int netId = RecipeRegistry.LAST_RECIPE_NET_ID; + + CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); + craftingDataPacket.setCleanRecipes(true); + Iterator recipeIterator = Bukkit.getServer().recipeIterator(); + while (recipeIterator.hasNext()) { + Recipe recipe = recipeIterator.next(); + Pair outputs = translateToBedrock(session, recipe.getResult()); + ItemStack javaOutput = outputs.getKey(); + ItemData output = outputs.getValue(); + if (output.getId() == 0) continue; // If items make air we don't want that + boolean isNotAllAir = false; // Check for all-air recipes + if (recipe instanceof ShapedRecipe) { + ShapedRecipe shapedRecipe = (ShapedRecipe) recipe; + int size = shapedRecipe.getShape().length * shapedRecipe.getShape()[0].length(); + Ingredient[] ingredients = new Ingredient[size]; + ItemData[] input = new ItemData[size]; + for (int i = 0; i < input.length; i++) { + // Index is converting char to integer, adding i then converting back to char based on ASCII code + Pair result = translateToBedrock(session, shapedRecipe.getIngredientMap().get((char) ('a' + i))); + ingredients[i] = new Ingredient(new ItemStack[]{result.getKey()}); + input[i] = result.getValue(); + isNotAllAir = isNotAllAir || input[i].getId() != 0; + } + if (!isNotAllAir) continue; + UUID uuid = UUID.randomUUID(); + // Add recipe to our internal cache + ShapedRecipeData data = new ShapedRecipeData(shapedRecipe.getShape()[0].length(), shapedRecipe.getShape().length, + "", ingredients, javaOutput); + session.getCraftingRecipes().put(netId, + new com.github.steveice10.mc.protocol.data.game.recipe.Recipe(RecipeType.CRAFTING_SHAPED, uuid.toString(), data)); + // Add recipe for Bedrock + craftingDataPacket.getCraftingData().add(CraftingData.fromShaped(uuid.toString(), + shapedRecipe.getShape()[0].length(), shapedRecipe.getShape().length, Arrays.asList(input), + Collections.singletonList(output), uuid, "crafting_table", 0, netId++)); + } else if (recipe instanceof ShapelessRecipe) { + ShapelessRecipe shapelessRecipe = (ShapelessRecipe) recipe; + Ingredient[] ingredients = new Ingredient[shapelessRecipe.getIngredientList().size()]; + ItemData[] input = new ItemData[shapelessRecipe.getIngredientList().size()]; + for (int i = 0; i < input.length; i++) { + Pair result = translateToBedrock(session, shapelessRecipe.getIngredientList().get(i)); + ingredients[i] = new Ingredient(new ItemStack[]{result.getKey()}); + input[i] = result.getValue(); + isNotAllAir = isNotAllAir || input[i].getId() != 0; + } + if (!isNotAllAir) continue; + UUID uuid = UUID.randomUUID(); + // Add recipe to our internal cache + ShapelessRecipeData data = new ShapelessRecipeData("", ingredients, javaOutput); + session.getCraftingRecipes().put(netId, + new com.github.steveice10.mc.protocol.data.game.recipe.Recipe(RecipeType.CRAFTING_SHAPELESS, uuid.toString(), data)); + // Add recipe for Bedrock + craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(), + Arrays.asList(input), Collections.singletonList(output), uuid, "crafting_table", 0, netId++)); + } + } + + session.sendUpstreamPacket(craftingDataPacket); + } + + @SuppressWarnings("deprecation") + private Pair translateToBedrock(GeyserSession session, org.bukkit.inventory.ItemStack itemStack) { + if (itemStack != null && itemStack.getData() != null) { + if (itemStack.getType().getId() == 0) { + return new Pair<>(null, ItemData.AIR); + } + int legacyId = (itemStack.getType().getId() << 4) | (itemStack.getData().getData() & 0xFFFF); + if (itemStack.getType().getId() == 355 && itemStack.getData().getData() == (byte) 0) { // Handle bed color since the server will always be pre-1.12 + legacyId = (itemStack.getType().getId() << 4) | ((byte) 14 & 0xFFFF); + } + // old version -> 1.13 -> 1.13.1 -> 1.14 -> 1.15 -> 1.16 and so on + int itemId; + if (mappingData1_12to1_13.getItemMappings().containsKey(legacyId)) { + itemId = mappingData1_12to1_13.getNewItemId(legacyId); + } else if (mappingData1_12to1_13.getItemMappings().containsKey((itemStack.getType().getId() << 4) | (0))) { + itemId = mappingData1_12to1_13.getNewItemId((itemStack.getType().getId() << 4) | (0)); + } else { + // No ID found, just send back air + return new Pair<>(null, ItemData.AIR); + } + + for (int i = protocolList.size() - 1; i >= 0; i--) { + MappingData mappingData = protocolList.get(i).getValue().getMappingData(); + if (mappingData != null) { + itemId = mappingData.getNewItemId(itemId); + } + } + + ItemStack mcItemStack = new ItemStack(itemId, itemStack.getAmount()); + ItemData finalData = ItemTranslator.translateToBedrock(session, mcItemStack); + return new Pair<>(mcItemStack, finalData); + } + // Empty slot, most likely + return new Pair<>(null, ItemData.AIR); + } + +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java index 39a7db11d..bc6768a72 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java @@ -193,41 +193,60 @@ public class JavaSetSlotTranslator extends PacketTranslator } System.out.println("Sending packet!"); - ItemData[] ingredients = new ItemData[gridSize]; - //construct ingredient list and clear slots on client - for (int i = 0; i < gridSize; i++) { - ingredients[i] = inventory.getItem(i + 1).getItemData(session); + UUID uuid = UUID.randomUUID(); + int newRecipeId = session.getLastRecipeNetId().incrementAndGet(); - InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(ContainerId.UI); - slotPacket.setSlot(i + offset); - slotPacket.setItem(ItemData.AIR); - session.sendUpstreamPacket(slotPacket); + ItemData[] ingredients = new ItemData[height * width]; + //construct ingredient list and clear slots on client + Ingredient[] javaIngredients = new Ingredient[height * width]; + int index = 0; + for (int row = firstRow; row < height + firstRow; row++) { + for (int col = firstCol; col < width + firstCol; col++) { + GeyserItemStack geyserItemStack = inventory.getItem(col + (row * gridDimensions) + 1); + ingredients[index] = geyserItemStack.getItemData(session); + ItemStack[] itemStacks = new ItemStack[] {geyserItemStack.isEmpty() ? null : geyserItemStack.getItemStack(1)}; + javaIngredients[index] = new Ingredient(itemStacks); + + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(ContainerId.UI); + slotPacket.setSlot(col + (row * gridDimensions) + offset); + slotPacket.setItem(ItemData.AIR); + session.sendUpstreamPacket(slotPacket); + index++; + } } + ShapedRecipeData data = new ShapedRecipeData(width, height, "", javaIngredients, packet.getItem()); + session.getConnector().getLogger().error(data.toString()); + // Cache this recipe so we know the client has received it + session.getCraftingRecipes().put(newRecipeId, new Recipe(RecipeType.CRAFTING_SHAPED, uuid.toString(), data)); + CraftingDataPacket craftPacket = new CraftingDataPacket(); - UUID uuid = UUID.randomUUID(); craftPacket.getCraftingData().add(CraftingData.fromShaped( uuid.toString(), - gridDimensions, - gridDimensions, + width, + height, Arrays.asList(ingredients), Collections.singletonList(ItemTranslator.translateToBedrock(session, packet.getItem())), uuid, "crafting_table", 0, - session.getLastRecipeNetId().incrementAndGet() + newRecipeId )); craftPacket.setCleanRecipes(false); + System.out.println(craftPacket); session.sendUpstreamPacket(craftPacket); - //restore cleared slots - for (int i = 0; i < gridSize; i++) { - InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(ContainerId.UI); - slotPacket.setSlot(i + offset); - slotPacket.setItem(ingredients[i]); - session.sendUpstreamPacket(slotPacket); + index = 0; + for (int row = firstRow; row < height + firstRow; row++) { + for (int col = firstCol; col < width + firstCol; col++) { + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(ContainerId.UI); + slotPacket.setSlot(col + (row * gridDimensions) + offset); + slotPacket.setItem(ingredients[index]); + session.sendUpstreamPacket(slotPacket); + index++; + } } } } From 6a9d4cd071211b18eb19040497292ad0f0094e67 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 11 Jan 2021 20:06:55 -0500 Subject: [PATCH 044/101] Implement 1.16.100 anvil renaming support --- .../translators/AnvilInventoryTranslator.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java index b131544b2..9d4fbfeec 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java @@ -26,20 +26,80 @@ package org.geysermc.connector.network.translators.inventory.translators; import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientRenameItemPacket; +import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.data.inventory.ItemData; 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.StackRequestActionData; +import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType; +import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; +import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import org.geysermc.connector.inventory.AnvilContainer; +import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.inventory.PlayerInventory; +import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; +import org.geysermc.connector.network.translators.item.ItemTranslator; public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { public AnvilInventoryTranslator() { super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL, UIInventoryUpdater.INSTANCE); } + /* 1.16.100 support start */ + @Override + @Deprecated + public boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { + return action.getType() == StackRequestActionType.CRAFT_NON_IMPLEMENTED_DEPRECATED; + } + + @Override + @Deprecated + public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + if (!(request.getActions()[1] instanceof CraftResultsDeprecatedStackRequestActionData)) { + // Just silently log an error + session.getConnector().getLogger().debug("Something isn't quite right with taking an item out of an anvil."); + return translateRequest(session, inventory, request); + } + CraftResultsDeprecatedStackRequestActionData actionData = (CraftResultsDeprecatedStackRequestActionData) request.getActions()[1]; + ItemData resultItem = actionData.getResultItems()[0]; + if (resultItem.getTag() != null) { + NbtMap displayTag = resultItem.getTag().getCompound("display"); + if (displayTag != null && displayTag.containsKey("Name")) { + ItemData sourceSlot = inventory.getItem(0).getItemData(session); + + if (sourceSlot.getTag() != null) { + NbtMap oldDisplayTag = sourceSlot.getTag().getCompound("display"); + if (oldDisplayTag != null && oldDisplayTag.containsKey("Name")) { + if (!displayTag.getString("Name").equals(oldDisplayTag.getString("Name"))) { + // Name has changed + sendRenamePacket(session, inventory, resultItem, displayTag.getString("Name")); + } + } else { + // No display tag on the old item + sendRenamePacket(session, inventory, resultItem, displayTag.getString("Name")); + } + } else { + // New NBT tag + sendRenamePacket(session, inventory, resultItem, displayTag.getString("Name")); + } + } + } + return translateRequest(session, inventory, request); + } + + private void sendRenamePacket(GeyserSession session, Inventory inventory, ItemData outputItem, String name) { + session.sendDownstreamPacket(new ClientRenameItemPacket(name)); + inventory.setItem(2, GeyserItemStack.from(ItemTranslator.translateToJava(outputItem)), session); + } + + /* 1.16.100 support end */ + @Override public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { if (slotInfoData.getContainer() == ContainerSlotType.ANVIL_INPUT) { From d3cb0695946c05eb45dd911dfff7abd5266e0265 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Tue, 12 Jan 2021 16:37:12 -0900 Subject: [PATCH 045/101] WIP. Autocrafting without java recipe book --- .../inventory/InventoryTranslator.java | 336 +++++++++++++----- .../inventory/click/ClickPlan.java | 63 +++- 2 files changed, 305 insertions(+), 94 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index f0f734fcf..cb000a2b5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -27,12 +27,12 @@ package org.geysermc.connector.network.translators.inventory; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientPrepareCraftingGridPacket; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; @@ -40,8 +40,7 @@ import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.*; import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; -import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.ints.*; import lombok.AllArgsConstructor; import org.geysermc.connector.inventory.CartographyContainer; import org.geysermc.connector.inventory.GeyserItemStack; @@ -159,8 +158,10 @@ public abstract class InventoryTranslator { if (shouldHandleRequestFirst(firstAction, inventory)) { // Some special request that shouldn't be processed normally responsePacket.getEntries().add(translateSpecialRequest(session, inventory, request)); - } else if (firstAction.getType() == StackRequestActionType.CRAFT_RECIPE || firstAction.getType() == StackRequestActionType.CRAFT_RECIPE_AUTO) { + } else if (firstAction.getType() == StackRequestActionType.CRAFT_RECIPE) { responsePacket.getEntries().add(translateCraftingRequest(session, inventory, request)); + } else if (firstAction.getType() == StackRequestActionType.CRAFT_RECIPE_AUTO) { + responsePacket.getEntries().add(translateAutoCraftingRequest(session, inventory, request)); } else if (firstAction.getType() == StackRequestActionType.CRAFT_CREATIVE) { // This is also used for pulling items out of creative responsePacket.getEntries().add(translateCreativeRequest(session, inventory, request)); @@ -329,40 +330,16 @@ public abstract class InventoryTranslator { } } else { //transfer from one slot to another int tempSlot = -1; - if (!cursor.isEmpty()) { + if (!plan.getCursor().isEmpty()) { tempSlot = findTempSlot(inventory, cursor, false, sourceSlot, destSlot); if (tempSlot == -1) { return rejectRequest(request); } plan.add(Click.LEFT, tempSlot); //place cursor into temp slot } - int sourceAmount = plan.getItem(sourceSlot).getAmount(); - if (transferAction.getCount() == sourceAmount) { //transfer all - plan.add(Click.LEFT, sourceSlot); //pickup source - plan.add(Click.LEFT, destSlot); //let go of all items and done - } else { //transfer some - //try to transfer items with least clicks possible - int halfSource = sourceAmount - (sourceAmount / 2); //larger half - int holding; - if (plan.getCursor().isEmpty() && transferAction.getCount() <= halfSource) { //faster to take only half. CURSOR MUST BE EMPTY - plan.add(Click.RIGHT, sourceSlot); - holding = halfSource; - } else { //need all - plan.add(Click.LEFT, sourceSlot); - holding = sourceAmount; - } - if (transferAction.getCount() > holding / 2) { //faster to release extra items onto source or dest slot? - for (int i = 0; i < holding - transferAction.getCount(); i++) { - plan.add(Click.RIGHT, sourceSlot); //prepare cursor - } - plan.add(Click.LEFT, destSlot); //release cursor onto dest slot - } else { - for (int i = 0; i < transferAction.getCount(); i++) { - plan.add(Click.RIGHT, destSlot); //right click until transfer goal is met - } - plan.add(Click.LEFT, sourceSlot); //return extra items to source slot - } - } + + transferSlot(plan, sourceSlot, destSlot, transferAction.getCount()); + if (tempSlot != -1) { plan.add(Click.LEFT, tempSlot); //retrieve original cursor } @@ -557,7 +534,6 @@ public abstract class InventoryTranslator { int recipeId = 0; int resultSize = 0; int timesCrafted = 0; - boolean autoCraft = false; CraftState craftState = CraftState.START; int leftover = 0; @@ -571,28 +547,6 @@ public abstract class InventoryTranslator { } craftState = CraftState.RECIPE_ID; recipeId = craftAction.getRecipeNetworkId(); - autoCraft = false; - break; - } - case CRAFT_RECIPE_AUTO: { - AutoCraftRecipeStackRequestActionData autoCraftAction = (AutoCraftRecipeStackRequestActionData) action; - if (craftState != CraftState.START) { - return rejectRequest(request); - } - craftState = CraftState.RECIPE_ID; - - recipeId = autoCraftAction.getRecipeNetworkId(); - if (!plan.getCursor().isEmpty()) { - return rejectRequest(request); - } - //reject if crafting grid is not clear - int gridSize = inventory.getId() == 0 ? 4 : 9; - for (int i = 1; i <= gridSize; i++) { - if (!inventory.getItem(i).isEmpty()) { - return rejectRequest(request); - } - } - autoCraft = true; break; } case CRAFT_RESULTS_DEPRECATED: { @@ -638,39 +592,6 @@ public abstract class InventoryTranslator { int sourceSlot = bedrockSlotToJava(transferAction.getSource()); int destSlot = bedrockSlotToJava(transferAction.getDestination()); - if (autoCraft) { - Recipe recipe = session.getCraftingRecipes().get(recipeId); - //cannot use java recipe book if recipe is locked - if (recipe == null || !session.getUnlockedRecipes().contains(recipe.getIdentifier())) { - return rejectRequest(request); - } - - boolean cursorDest = isCursor(transferAction.getDestination()); - boolean makeAll = timesCrafted > 1; - if (cursorDest) { - makeAll = false; - } - - ClientPrepareCraftingGridPacket prepareCraftingPacket = new ClientPrepareCraftingGridPacket(inventory.getId(), recipe.getIdentifier(), makeAll); - session.sendDownstreamPacket(prepareCraftingPacket); - - ItemStack output = null; - switch (recipe.getType()) { - case CRAFTING_SHAPED: - output = ((ShapedRecipeData)recipe.getData()).getResult(); - break; - case CRAFTING_SHAPELESS: - output = ((ShapelessRecipeData)recipe.getData()).getResult(); - break; - } - inventory.setItem(0, GeyserItemStack.from(output), session); - - plan.add(cursorDest ? Click.LEFT : Click.LEFT_SHIFT, 0); - plan.execute(true); - - return acceptRequest(request, makeContainerEntries(session, inventory, Collections.emptySet())); - } - if (isCursor(transferAction.getDestination())) { plan.add(Click.LEFT, sourceSlot); craftState = CraftState.DONE; @@ -711,9 +632,211 @@ public abstract class InventoryTranslator { } } plan.execute(false); - Set affectedSlots = plan.getAffectedSlots(); - affectedSlots.addAll(Arrays.asList(1, 2, 3, 4)); //TODO: crafting grid - return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); + return acceptRequest(request, makeContainerEntries(session, inventory, plan.getAffectedSlots())); + } + + public ItemStackResponsePacket.Response translateAutoCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + int gridSize; + int gridDimensions; + if (this instanceof PlayerInventoryTranslator) { + gridSize = 4; + gridDimensions = 2; + } else if (this instanceof CraftingInventoryTranslator) { + gridSize = 9; + gridDimensions = 3; + } else { + return rejectRequest(request); + } + + Recipe recipe; + Ingredient[] ingredients = new Ingredient[0]; + ItemStack output = null; + int recipeWidth = 0; + int ingRemaining = 0; + int ingredientIndex = -1; + + Int2IntMap consumedSlots = new Int2IntOpenHashMap(); + int prioritySlot = -1; + int secondarySlot = -1; + int tempSlot = -1; + boolean intoCursor = false; + + int resultSize; + int timesCrafted = 0; + Int2ObjectMap ingredientMap = new Int2ObjectOpenHashMap<>(); + CraftState craftState = CraftState.START; + + ClickPlan plan = new ClickPlan(session, this, inventory); + requestLoop: + for (StackRequestActionData action : request.getActions()) { + switch (action.getType()) { + case CRAFT_RECIPE_AUTO: { + AutoCraftRecipeStackRequestActionData autoCraftAction = (AutoCraftRecipeStackRequestActionData) action; + if (craftState != CraftState.START) { + return rejectRequest(request); + } + craftState = CraftState.RECIPE_ID; + + int recipeId = autoCraftAction.getRecipeNetworkId(); + recipe = session.getCraftingRecipes().get(recipeId); + if (recipe == null) { + return rejectRequest(request); + } + if (!plan.getCursor().isEmpty()) { + return rejectRequest(request); + } + //reject if crafting grid is not clear + for (int i = 1; i <= gridSize; i++) { + if (!inventory.getItem(i).isEmpty()) { + return rejectRequest(request); + } + } + + switch (recipe.getType()) { + case CRAFTING_SHAPED: + ShapedRecipeData shapedData = (ShapedRecipeData) recipe.getData(); + ingredients = shapedData.getIngredients(); + recipeWidth = shapedData.getWidth(); + output = shapedData.getResult(); + if (shapedData.getWidth() > gridDimensions || shapedData.getHeight() > gridDimensions) { + return rejectRequest(request); + } + break; + case CRAFTING_SHAPELESS: + ShapelessRecipeData shapelessData = (ShapelessRecipeData) recipe.getData(); + ingredients = shapelessData.getIngredients(); + recipeWidth = gridDimensions; + output = shapelessData.getResult(); + if (ingredients.length > gridSize) { + return rejectRequest(request); + } + break; + } + break; + } + case CRAFT_RESULTS_DEPRECATED: { + CraftResultsDeprecatedStackRequestActionData deprecatedCraftAction = (CraftResultsDeprecatedStackRequestActionData) action; + if (craftState != CraftState.RECIPE_ID) { + return rejectRequest(request); + } + craftState = CraftState.DEPRECATED; + + if (deprecatedCraftAction.getResultItems().length != 1) { + return rejectRequest(request); + } + resultSize = deprecatedCraftAction.getResultItems()[0].getCount(); + timesCrafted = deprecatedCraftAction.getTimesCrafted(); + if (resultSize <= 0 || timesCrafted <= 0) { + return rejectRequest(request); + } + break; + } + case CONSUME: { + ConsumeStackRequestActionData consumeAction = (ConsumeStackRequestActionData) action; + if (craftState != CraftState.DEPRECATED && craftState != CraftState.INGREDIENTS) { + return rejectRequest(request); + } + craftState = CraftState.INGREDIENTS; + + if (ingRemaining == 0) { + while (++ingredientIndex < ingredients.length) { + if (ingredients[ingredientIndex].getOptions().length != 0) { + ingRemaining = timesCrafted; + break; + } + } + } + + ingRemaining -= consumeAction.getCount(); + if (ingRemaining < 0) + return rejectRequest(request); + + int javaSlot = bedrockSlotToJava(consumeAction.getSource()); + consumedSlots.merge(javaSlot, consumeAction.getCount(), Integer::sum); + + int gridSlot = 1 + ingredientIndex + ((ingredientIndex / recipeWidth) * (gridDimensions - recipeWidth)); + Int2IntMap sources = ingredientMap.computeIfAbsent(gridSlot, k -> new Int2IntOpenHashMap()); + sources.put(javaSlot, consumeAction.getCount()); + break; + } + case TAKE: + case PLACE: { + TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action; + if (craftState != CraftState.INGREDIENTS && craftState != CraftState.TRANSFER) { + return rejectRequest(request); + } + craftState = CraftState.TRANSFER; + + if (transferAction.getSource().getContainer() != ContainerSlotType.CREATIVE_OUTPUT) { + return rejectRequest(request); + } + if (transferAction.getCount() <= 0) { + return rejectRequest(request); + } + + int javaSlot = bedrockSlotToJava(transferAction.getDestination()); + if (isCursor(transferAction.getDestination())) { //TODO + intoCursor = true; + if (timesCrafted > 1) { + tempSlot = findTempSlot(inventory, GeyserItemStack.from(output), true); + if (tempSlot == -1) { + return rejectRequest(request); + } + } + break requestLoop; + } else if (inventory.getItem(javaSlot).getAmount() == consumedSlots.get(javaSlot)) { + prioritySlot = bedrockSlotToJava(transferAction.getDestination()); + break requestLoop; + } + break; + } + default: + return rejectRequest(request); + } + } + + final int maxLoops = Math.min(64, timesCrafted); + for (int loops = 0; loops < maxLoops; loops++) { + boolean done = true; + for (Int2ObjectMap.Entry entry : ingredientMap.int2ObjectEntrySet()) { + Int2IntMap sources = entry.getValue(); + System.out.println("Grid slot: " + entry.getIntKey()); + System.out.println(sources); + if (sources.isEmpty()) + continue; + + done = false; + int gridSlot = entry.getIntKey(); + if (!plan.getItem(gridSlot).isEmpty()) + continue; + + int sourceSlot; + if (loops == 0 && sources.containsKey(prioritySlot)) { + sourceSlot = prioritySlot; + } else { + sourceSlot = sources.keySet().iterator().nextInt(); + } + int transferAmount = sources.remove(sourceSlot); + transferSlot(plan, sourceSlot, gridSlot, transferAmount); + } + + for (int x = 0; x < 3; x++) { + int offset = x * 3; + System.out.println(plan.getItem(1 + offset).getAmount() + " " + plan.getItem(2 + offset).getAmount() + " " + plan.getItem(3 + offset).getAmount()); + } + + if (!done) { + //TODO: sometimes the server does not agree on this slot? + plan.add(Click.LEFT_SHIFT, 0, true); + } else { + System.out.println("Times looped: " + loops); + break; + } + } + + inventory.setItem(0, GeyserItemStack.from(output), session); + plan.execute(true); + return acceptRequest(request, makeContainerEntries(session, inventory, plan.getAffectedSlots())); } public ItemStackResponsePacket.Response translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { @@ -788,6 +911,37 @@ public abstract class InventoryTranslator { return rejectRequest(request); } + private void transferSlot(ClickPlan plan, int sourceSlot, int destSlot, int transferAmount) { + boolean tempSwap = !plan.getCursor().isEmpty(); + int sourceAmount = plan.getItem(sourceSlot).getAmount(); + if (transferAmount == sourceAmount) { //transfer all + plan.add(Click.LEFT, sourceSlot); //pickup source + plan.add(Click.LEFT, destSlot); //let go of all items and done + } else { //transfer some + //try to transfer items with least clicks possible + int halfSource = sourceAmount - (sourceAmount / 2); //larger half + int holding; + if (!tempSwap && transferAmount <= halfSource) { //faster to take only half. CURSOR MUST BE EMPTY + plan.add(Click.RIGHT, sourceSlot); + holding = halfSource; + } else { //need all + plan.add(Click.LEFT, sourceSlot); + holding = sourceAmount; + } + if (!tempSwap && transferAmount > holding / 2) { //faster to release extra items onto source or dest slot? + for (int i = 0; i < holding - transferAmount; i++) { + plan.add(Click.RIGHT, sourceSlot); //prepare cursor + } + plan.add(Click.LEFT, destSlot); //release cursor onto dest slot + } else { + for (int i = 0; i < transferAmount; i++) { + plan.add(Click.RIGHT, destSlot); //right click until transfer goal is met + } + plan.add(Click.LEFT, sourceSlot); //return extra items to source slot + } + } + } + public static ItemStackResponsePacket.Response acceptRequest(ItemStackRequestPacket.Request request, List containerEntries) { return new ItemStackResponsePacket.Response(ItemStackResponsePacket.ResponseStatus.OK, request.getRequestId(), containerEntries); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java index 9268cbf12..018f1bc78 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java @@ -39,6 +39,8 @@ import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.inventory.SlotType; +import org.geysermc.connector.network.translators.inventory.translators.CraftingInventoryTranslator; +import org.geysermc.connector.network.translators.inventory.translators.PlayerInventoryTranslator; import org.geysermc.connector.utils.InventoryUtils; import java.util.*; @@ -52,6 +54,7 @@ public class ClickPlan { private final GeyserSession session; private final InventoryTranslator translator; private final Inventory inventory; + private final int gridSize; public ClickPlan(GeyserSession session, InventoryTranslator translator, Inventory inventory) { this.session = session; @@ -61,6 +64,14 @@ public class ClickPlan { this.simulatedItems = new Int2ObjectOpenHashMap<>(inventory.getSize()); this.simulatedCursor = session.getPlayerInventory().getCursor().copy(); this.simulating = true; + + if (translator instanceof PlayerInventoryTranslator) { + gridSize = 4; + } else if (translator instanceof CraftingInventoryTranslator) { + gridSize = 9; + } else { + gridSize = -1; + } } private void resetSimulation() { @@ -69,6 +80,10 @@ public class ClickPlan { } public void add(Click click, int slot) { + add(click, slot, false); + } + + public void add(Click click, int slot, boolean force) { if (!simulating) throw new UnsupportedOperationException("ClickPlan already executed"); @@ -76,7 +91,7 @@ public class ClickPlan { slot = Click.OUTSIDE_SLOT; } - ClickAction action = new ClickAction(click, slot); + ClickAction action = new ClickAction(click, slot, force); plan.add(action); simulateAction(action); } @@ -114,7 +129,7 @@ public class ClickPlan { simulateAction(action); session.sendDownstreamPacket(clickPacket); - if (clickedItemStack == InventoryUtils.REFRESH_ITEM) { + if (clickedItemStack == InventoryUtils.REFRESH_ITEM || action.force) { session.sendDownstreamPacket(new ClientConfirmTransactionPacket(inventory.getId(), actionId, true)); } System.out.println(clickPacket); @@ -128,7 +143,15 @@ public class ClickPlan { } public GeyserItemStack getItem(int slot) { - return simulatedItems.computeIfAbsent(slot, k -> inventory.getItem(slot).copy()); + return getItem(slot, true); + } + + public GeyserItemStack getItem(int slot, boolean generate) { + if (generate) { + return simulatedItems.computeIfAbsent(slot, k -> inventory.getItem(slot).copy()); + } else { + return simulatedItems.getOrDefault(slot, inventory.getItem(slot)); + } } public GeyserItemStack getCursor() { @@ -174,6 +197,10 @@ public class ClickPlan { } else if (InventoryUtils.canStack(cursor, clicked)) { cursor.add(clicked.getAmount()); } + reduceCraftingGrid(false); + break; + case LEFT_SHIFT: + reduceCraftingGrid(true); break; } } else { @@ -215,6 +242,35 @@ public class ClickPlan { } } + //TODO + private void reduceCraftingGrid(boolean makeAll) { + if (gridSize == -1) + return; + + int crafted; + if (!makeAll) { + crafted = 1; + } else { + crafted = 0; + for (int i = 0; i < gridSize; i++) { + GeyserItemStack item = getItem(i + 1); + if (!item.isEmpty()) { + if (crafted == 0) { + crafted = item.getAmount(); + } + crafted = Math.min(crafted, item.getAmount()); + } + } + } + + for (int i = 0; i < gridSize; i++) { + GeyserItemStack item = getItem(i + 1); + if (!item.isEmpty()) + item.sub(crafted); + } + System.out.println("REDUCED GRID BY " + crafted); + } + /** * @return a new set of all affected slots. This isn't a constant variable; it's newly generated each time it is run. */ @@ -235,5 +291,6 @@ public class ClickPlan { * Java slot */ int slot; + boolean force; } } From 454fd102d6aa8334ce76768ba35a63d8cccf47d4 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 13 Jan 2021 13:37:20 -0500 Subject: [PATCH 046/101] Add better destroy support --- .../inventory/InventoryTranslator.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index cb000a2b5..f029a6051 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -465,7 +465,6 @@ public abstract class InventoryTranslator { } case DESTROY: { // Only called when a creative client wants to destroy an item... I think - Camotoy - //TODO there is a Count here we don't use DestroyStackRequestActionData destroyAction = (DestroyStackRequestActionData) action; if (!session.getGameMode().equals(GameMode.CREATIVE)) { // If this happens, let's throw an error and figure out why. @@ -474,13 +473,23 @@ public abstract class InventoryTranslator { if (!isCursor(destroyAction.getSource())) { // Item exists; let's remove it from the inventory int javaSlot = bedrockSlotToJava(destroyAction.getSource()); - ClientCreativeInventoryActionPacket destroyItemPacket = new ClientCreativeInventoryActionPacket( - javaSlot, - new ItemStack(0) - ); + GeyserItemStack existingItem = inventory.getItem(javaSlot); + existingItem.setAmount(existingItem.getAmount() - destroyAction.getCount()); + ClientCreativeInventoryActionPacket destroyItemPacket; + if (existingItem.isEmpty()) { + destroyItemPacket = new ClientCreativeInventoryActionPacket( + javaSlot, + new ItemStack(0) + ); + inventory.setItem(javaSlot, GeyserItemStack.EMPTY, session); + } else { + destroyItemPacket = new ClientCreativeInventoryActionPacket( + javaSlot, + existingItem.getItemStack() + ); + } session.sendDownstreamPacket(destroyItemPacket); System.out.println(destroyItemPacket); - inventory.setItem(javaSlot, GeyserItemStack.EMPTY, session); affectedSlots.add(javaSlot); } else { // Just sync up the item on our end, since the server doesn't care what's in our cursor From 196c9f5c17a2d78af5e5fcc57f905217d5480991 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Wed, 13 Jan 2021 19:19:01 -0900 Subject: [PATCH 047/101] Remove debug lines --- .../GeyserSpigot1_11CraftingListener.java | 1 - .../network/session/GeyserSession.java | 2 -- .../BedrockContainerCloseTranslator.java | 1 - .../bedrock/BedrockFilterTextTranslator.java | 1 - ...BedrockInventoryTransactionTranslator.java | 1 - .../BedrockItemStackRequestTranslator.java | 1 - .../BedrockLecternUpdateTranslator.java | 4 --- .../inventory/InventoryTranslator.java | 25 ------------------- .../inventory/click/ClickPlan.java | 2 -- .../BeaconInventoryTranslator.java | 2 -- .../BrewingInventoryTranslator.java | 1 - .../EnchantingInventoryTranslator.java | 2 -- .../translators/LoomInventoryTranslator.java | 1 - .../StonecutterInventoryTranslator.java | 3 --- .../ChestedHorseInventoryTranslator.java | 1 - .../updater/HorseInventoryUpdater.java | 1 - .../JavaConfirmTransactionTranslator.java | 1 - .../window/JavaOpenHorseWindowTranslator.java | 2 -- .../java/window/JavaSetSlotTranslator.java | 10 -------- .../window/JavaWindowPropertyTranslator.java | 1 - 20 files changed, 63 deletions(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigot1_11CraftingListener.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigot1_11CraftingListener.java index d20b7637d..66fbb0163 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigot1_11CraftingListener.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigot1_11CraftingListener.java @@ -93,7 +93,6 @@ public class GeyserSpigot1_11CraftingListener implements Listener { return; } - System.out.println("Sending recipes!"); sendServerRecipes(session); } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 4542abf77..50ab17e23 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -887,7 +887,6 @@ public class GeyserSession implements CommandSender { */ public void addInventoryTask(Runnable task) { synchronized (inventoryLock) { - System.out.println("new task " + task.toString()); inventoryFuture = inventoryFuture.thenRun(task).exceptionally(throwable -> { GeyserConnector.getInstance().getLogger().error("Error processing inventory task", throwable.getCause()); return null; @@ -905,7 +904,6 @@ public class GeyserSession implements CommandSender { */ public void addInventoryTask(Runnable task, long delayMillis) { synchronized (inventoryLock) { - System.out.println("new delayed task " + task.toString()); Executor delayedExecutor = command -> GeyserConnector.getInstance().getGeneralThreadPool().schedule(command, delayMillis, TimeUnit.MILLISECONDS); inventoryFuture = inventoryFuture.thenRunAsync(task, delayedExecutor).exceptionally(throwable -> { GeyserConnector.getInstance().getLogger().error("Error processing inventory task", throwable.getCause()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java index 7ac3dba51..6f0f877c8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java @@ -48,7 +48,6 @@ public class BedrockContainerCloseTranslator extends PacketTranslator currentJavaPage) { for (int i = currentJavaPage; i < newJavaPage; i++) { ClientClickWindowButtonPacket clickButtonPacket = new ClientClickWindowButtonPacket(session.getOpenInventory().getId(), 2); - System.out.println(clickButtonPacket); session.sendDownstreamPacket(clickButtonPacket); } } else { for (int i = currentJavaPage; i > newJavaPage; i--) { ClientClickWindowButtonPacket clickButtonPacket = new ClientClickWindowButtonPacket(session.getOpenInventory().getId(), 1); - System.out.println(clickButtonPacket); session.sendDownstreamPacket(clickButtonPacket); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index 654a7b422..fab81933a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -173,11 +173,9 @@ public abstract class InventoryTranslator { } } session.sendUpstreamPacket(responsePacket); - System.out.println(responsePacket); } public ItemStackResponsePacket.Response translateRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { - System.out.println(request); ClickPlan plan = new ClickPlan(session, this, inventory); IntSet affectedSlots = new IntOpenHashSet(); for (StackRequestActionData action : request.getActions()) { @@ -273,7 +271,6 @@ public abstract class InventoryTranslator { itemToUpdate.isEmpty() ? new ItemStack(0) : itemToUpdate.getItemStack() ); session.sendDownstreamPacket(creativeActionPacket); - System.out.println(creativeActionPacket); if (!sourceIsCursor) { // Cursor is always added for us as an affected slot affectedSlots.add(sourceSlot); @@ -365,7 +362,6 @@ public abstract class InventoryTranslator { sourceSlot, oldDestinationItem.isEmpty() ? new ItemStack(0) : oldDestinationItem.getItemStack() // isEmpty check... just in case ); - System.out.println(creativeActionPacket); session.sendDownstreamPacket(creativeActionPacket); inventory.setItem(sourceSlot, oldDestinationItem, session); } @@ -376,7 +372,6 @@ public abstract class InventoryTranslator { destSlot, oldSourceItem.isEmpty() ? new ItemStack(0) : oldSourceItem.getItemStack() ); - System.out.println(creativeActionPacket); session.sendDownstreamPacket(creativeActionPacket); inventory.setItem(destSlot, oldSourceItem, session); } @@ -433,7 +428,6 @@ public abstract class InventoryTranslator { Click.OUTSIDE_SLOT, droppingItem.getItemStack() ); - System.out.println(packet.toString()); session.sendDownstreamPacket(packet); } else { int sourceAmount = plan.getCursor().getAmount(); @@ -458,11 +452,6 @@ public abstract class InventoryTranslator { } break; } - case CRAFT_CREATIVE: { - CraftCreativeStackRequestActionData creativeAction = (CraftCreativeStackRequestActionData) action; - System.out.println(creativeAction.getCreativeItemNetworkId()); - break; - } case DESTROY: { // Only called when a creative client wants to destroy an item... I think - Camotoy DestroyStackRequestActionData destroyAction = (DestroyStackRequestActionData) action; @@ -489,7 +478,6 @@ public abstract class InventoryTranslator { ); } session.sendDownstreamPacket(destroyItemPacket); - System.out.println(destroyItemPacket); affectedSlots.add(javaSlot); } else { // Just sync up the item on our end, since the server doesn't care what's in our cursor @@ -538,8 +526,6 @@ public abstract class InventoryTranslator { } public ItemStackResponsePacket.Response translateCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { - System.out.println(request); - int recipeId = 0; int resultSize = 0; int timesCrafted = 0; @@ -809,8 +795,6 @@ public abstract class InventoryTranslator { boolean done = true; for (Int2ObjectMap.Entry entry : ingredientMap.int2ObjectEntrySet()) { Int2IntMap sources = entry.getValue(); - System.out.println("Grid slot: " + entry.getIntKey()); - System.out.println(sources); if (sources.isEmpty()) continue; @@ -829,16 +813,10 @@ public abstract class InventoryTranslator { transferSlot(plan, sourceSlot, gridSlot, transferAmount); } - for (int x = 0; x < 3; x++) { - int offset = x * 3; - System.out.println(plan.getItem(1 + offset).getAmount() + " " + plan.getItem(2 + offset).getAmount() + " " + plan.getItem(3 + offset).getAmount()); - } - if (!done) { //TODO: sometimes the server does not agree on this slot? plan.add(Click.LEFT_SHIFT, 0, true); } else { - System.out.println("Times looped: " + loops); break; } } @@ -908,7 +886,6 @@ public abstract class InventoryTranslator { javaCreativeItem ); session.sendDownstreamPacket(creativeActionPacket); - System.out.println(creativeActionPacket); Set affectedSlots = Collections.singleton(javaSlot); return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); } @@ -1017,8 +994,6 @@ public abstract class InventoryTranslator { if (!viable) { continue; } - - System.out.println("TEMP SLOT CHOSEN: " + i + " => " + inventory.getItem(i)); return i; } //could not find a viable temp slot diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java index 018f1bc78..c750baf51 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java @@ -132,7 +132,6 @@ public class ClickPlan { if (clickedItemStack == InventoryUtils.REFRESH_ITEM || action.force) { session.sendDownstreamPacket(new ClientConfirmTransactionPacket(inventory.getId(), actionId, true)); } - System.out.println(clickPacket); } session.getPlayerInventory().setCursor(simulatedCursor, session); @@ -268,7 +267,6 @@ public class ClickPlan { if (!item.isEmpty()) item.sub(crafted); } - System.out.println("REDUCED GRID BY " + crafted); } /** diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java index 5b31c83ba..d0db8f3d6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java @@ -84,7 +84,6 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator BlockEntityDataPacket packet = new BlockEntityDataPacket(); packet.setBlockPosition(position); packet.setData(builder.build()); - System.out.println(packet.toString()); session.sendUpstreamPacket(packet); } @@ -98,7 +97,6 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator // Input a beacon payment BeaconPaymentStackRequestActionData beaconPayment = (BeaconPaymentStackRequestActionData) request.getActions()[0]; ClientSetBeaconEffectPacket packet = new ClientSetBeaconEffectPacket(beaconPayment.getPrimaryEffect(), beaconPayment.getSecondaryEffect()); - System.out.println(packet.toString()); session.sendDownstreamPacket(packet); return acceptRequest(request, makeContainerEntries(session, inventory, Collections.emptySet())); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BrewingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BrewingInventoryTranslator.java index 9dbbbf964..b44350615 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BrewingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BrewingInventoryTranslator.java @@ -69,7 +69,6 @@ public class BrewingInventoryTranslator extends AbstractBlockInventoryTranslator @Override public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { - System.out.println("Brewing stand: " + slotInfoData); if (slotInfoData.getContainer() == ContainerSlotType.BREWING_INPUT) { // Ingredient // TODO: This hasn't worked and then suddenly, it did. diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java index 4d105d423..8d2f20145 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java @@ -99,7 +99,6 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla enchantingInventory.getEnchantOptions()[slotToUpdate] = enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].build(session); PlayerEnchantOptionsPacket packet = new PlayerEnchantOptionsPacket(); packet.getOptions().addAll(Arrays.asList(enchantingInventory.getEnchantOptions())); - System.out.println(packet); session.sendUpstreamPacket(packet); } } @@ -130,7 +129,6 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla return rejectRequest(request); } ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), javaSlot); - System.out.println(packet); session.sendDownstreamPacket(packet); return acceptRequest(request, makeContainerEntries(session, inventory, Collections.emptySet())); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java index bac9e7ae6..409cc4f15 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java @@ -140,7 +140,6 @@ 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. :) ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), index); - System.out.println(packet); session.sendDownstreamPacket(packet); GeyserItemStack inputCopy = inventory.getItem(0).copy(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java index 0168d0ef9..af742c136 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java @@ -73,15 +73,12 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl if (results == null) { return rejectRequest(request); } - System.out.println(id + " " + results); ItemStack javaOutput = ItemTranslator.translateToJava(craftData.getResultItems()[0]); - System.out.println(javaOutput); int button = results.indexOf(javaOutput.getId()); // If we've already pressed the button with this item, no need to press it again! if (container.getStonecutterButton() != button) { // Getting the index of the item in the Java stonecutter list ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), button); - System.out.println(packet.toString()); session.sendDownstreamPacket(packet); container.setStonecutterButton(button); if (inventory.getItem(1).getJavaId() != javaOutput.getId()) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/ChestedHorseInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/ChestedHorseInventoryTranslator.java index f74c2d361..77a1976be 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/ChestedHorseInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/horse/ChestedHorseInventoryTranslator.java @@ -107,7 +107,6 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven InventoryContentPacket horseContentsPacket = new InventoryContentPacket(); horseContentsPacket.setContainerId(inventory.getId()); horseContentsPacket.setContents(Arrays.asList(horseItems)); - System.out.println(horseContentsPacket); session.sendUpstreamPacket(horseContentsPacket); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/HorseInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/HorseInventoryUpdater.java index 838e59d78..d238b4148 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/HorseInventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/HorseInventoryUpdater.java @@ -62,7 +62,6 @@ public class HorseInventoryUpdater extends InventoryUpdater { slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); session.sendUpstreamPacket(slotPacket); - System.out.println(slotPacket); return true; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java index 05347fd06..3b55733bf 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java @@ -41,7 +41,6 @@ public class JavaConfirmTransactionTranslator extends PacketTranslator @Override public void translate(ServerSetSlotPacket packet, GeyserSession session) { - System.out.println(packet.toString()); session.addInventoryTask(() -> { if (packet.getWindowId() == 255) { //cursor GeyserItemStack newItem = GeyserItemStack.from(packet.getItem()); @@ -125,11 +124,6 @@ public class JavaSetSlotTranslator extends PacketTranslator height += -firstRow + 1; width += -firstCol + 1; - System.out.println("Start Row: " + firstRow); - System.out.println("Start Column: " + firstCol); - System.out.println("Rows: " + height); - System.out.println("Columns: " + width); - //TODO recipes: for (Recipe recipe : session.getCraftingRecipes().values()) { @@ -157,8 +151,6 @@ public class JavaSetSlotTranslator extends PacketTranslator continue; } } - System.out.println("FOUND SHAPED RECIPE :)"); - System.out.println(recipe); // Recipe is had, don't sent packet return; } else if (recipe.getType() == RecipeType.CRAFTING_SHAPELESS) { @@ -191,7 +183,6 @@ public class JavaSetSlotTranslator extends PacketTranslator return; } } - System.out.println("Sending packet!"); UUID uuid = UUID.randomUUID(); int newRecipeId = session.getLastRecipeNetId().incrementAndGet(); @@ -234,7 +225,6 @@ public class JavaSetSlotTranslator extends PacketTranslator newRecipeId )); craftPacket.setCleanRecipes(false); - System.out.println(craftPacket); session.sendUpstreamPacket(craftPacket); index = 0; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java index 94ec8784d..c31a39029 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java @@ -38,7 +38,6 @@ public class JavaWindowPropertyTranslator extends PacketTranslator { Inventory inventory = InventoryUtils.getInventory(session, packet.getWindowId()); if (inventory == null) From 5ddb189b4881c246d229ddc37fbeec9e1cac70f5 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Wed, 13 Jan 2021 19:19:37 -0900 Subject: [PATCH 048/101] Use server-inventory mappings --- connector/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index dd0347bd5..07f65c380 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit dd0347bd51e00e42ea58faaf68b562526c4d2817 +Subproject commit 07f65c3803dcd3f83358ee574e54bf129cad0840 From 4ee3143fe931c54ea248ffbf2554602cf753371a Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Wed, 13 Jan 2021 19:40:01 -0900 Subject: [PATCH 049/101] Add delay to legacy recipe detection Workaround for an issue which will be properly fixed later. --- .../geysermc/connector/network/session/GeyserSession.java | 3 +++ .../translators/java/window/JavaSetSlotTranslator.java | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 50ab17e23..17c6bd66c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -151,6 +151,9 @@ public class GeyserSession implements CommandSender { @Getter(AccessLevel.NONE) private CompletableFuture inventoryFuture; + @Setter + private ScheduledFuture craftingGridFuture; + /** * Stores session collision */ diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java index ea2c9d555..c5bf6dd25 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java @@ -52,6 +52,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Objects; import java.util.UUID; +import java.util.concurrent.TimeUnit; @Translator(packet = ServerSetSlotPacket.class) public class JavaSetSlotTranslator extends PacketTranslator { @@ -73,7 +74,10 @@ public class JavaSetSlotTranslator extends PacketTranslator InventoryTranslator translator = session.getInventoryTranslator(); if (translator != null) { - updateCraftingGrid(session, packet, inventory, translator); + if (session.getCraftingGridFuture() != null) { + session.getCraftingGridFuture().cancel(false); + } + session.setCraftingGridFuture(session.getConnector().getGeneralThreadPool().schedule(() -> session.addInventoryTask(() -> updateCraftingGrid(session, packet, inventory, translator)), 150, TimeUnit.MILLISECONDS)); GeyserItemStack newItem = GeyserItemStack.from(packet.getItem()); inventory.setItem(packet.getSlot(), newItem, session); @@ -208,7 +212,6 @@ public class JavaSetSlotTranslator extends PacketTranslator } ShapedRecipeData data = new ShapedRecipeData(width, height, "", javaIngredients, packet.getItem()); - session.getConnector().getLogger().error(data.toString()); // Cache this recipe so we know the client has received it session.getCraftingRecipes().put(newRecipeId, new Recipe(RecipeType.CRAFTING_SHAPED, uuid.toString(), data)); From 95703d2ea7794da4e747af5cebaaa650de5d3438 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Wed, 13 Jan 2021 19:59:11 -0900 Subject: [PATCH 050/101] Update inventory if request was rejected --- .../inventory/InventoryTranslator.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index fab81933a..64f73ac54 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -151,28 +151,39 @@ public abstract class InventoryTranslator { } public void translateRequests(GeyserSession session, Inventory inventory, List requests) { + boolean refresh = false; ItemStackResponsePacket responsePacket = new ItemStackResponsePacket(); for (ItemStackRequestPacket.Request request : requests) { + ItemStackResponsePacket.Response response; if (request.getActions().length > 0) { StackRequestActionData firstAction = request.getActions()[0]; if (shouldHandleRequestFirst(firstAction, inventory)) { // Some special request that shouldn't be processed normally - responsePacket.getEntries().add(translateSpecialRequest(session, inventory, request)); + response = translateSpecialRequest(session, inventory, request); } else if (firstAction.getType() == StackRequestActionType.CRAFT_RECIPE) { - responsePacket.getEntries().add(translateCraftingRequest(session, inventory, request)); + response = translateCraftingRequest(session, inventory, request); } else if (firstAction.getType() == StackRequestActionType.CRAFT_RECIPE_AUTO) { - responsePacket.getEntries().add(translateAutoCraftingRequest(session, inventory, request)); + response = translateAutoCraftingRequest(session, inventory, request); } else if (firstAction.getType() == StackRequestActionType.CRAFT_CREATIVE) { // This is also used for pulling items out of creative - responsePacket.getEntries().add(translateCreativeRequest(session, inventory, request)); + response = translateCreativeRequest(session, inventory, request); } else { - responsePacket.getEntries().add(translateRequest(session, inventory, request)); + response = translateRequest(session, inventory, request); } } else { - responsePacket.getEntries().add(rejectRequest(request)); + response = rejectRequest(request); } + if (response.getResult() == ItemStackResponsePacket.ResponseStatus.ERROR) { + refresh = true; + } + responsePacket.getEntries().add(response); } session.sendUpstreamPacket(responsePacket); + + if (refresh) { + InventoryUtils.updateCursor(session); + updateInventory(session, inventory); + } } public ItemStackResponsePacket.Response translateRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { From 234c6542bbabf5a1314e883208af1e595c9e2e42 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Thu, 14 Jan 2021 19:45:59 -0900 Subject: [PATCH 051/101] Refactor creative request translator and fix bugs --- .../inventory/InventoryTranslator.java | 237 +--------------- .../PlayerInventoryTranslator.java | 255 ++++++++++++++++++ 2 files changed, 265 insertions(+), 227 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index 64f73ac54..b6f22dc61 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -217,79 +217,6 @@ public abstract class InventoryTranslator { if (isCursor(transferAction.getSource()) && isCursor(transferAction.getDestination())) { //??? return rejectRequest(request); - } else if (session.getGameMode().equals(GameMode.CREATIVE) && inventory instanceof PlayerInventory) { // TODO: does the Java server use this stuff all the time in creative? - // Creative acts a little differently because it just edits slots - boolean sourceIsCursor = isCursor(transferAction.getSource()); - boolean destIsCursor = isCursor(transferAction.getDestination()); - - GeyserItemStack sourceItem = sourceIsCursor ? session.getPlayerInventory().getCursor() : - inventory.getItem(sourceSlot); - GeyserItemStack newItem = sourceItem.copy(); - if (sourceIsCursor) { - GeyserItemStack destItem = inventory.getItem(destSlot); - if (destItem.getJavaId() == sourceItem.getJavaId()) { - // Combining items - int itemsLeftOver = destItem.getAmount() + transferAction.getCount(); - if (itemsLeftOver > MAX_ITEM_STACK_SIZE) { - // Items will remain in cursor because destination slot gets set to 64 - destItem.setAmount(MAX_ITEM_STACK_SIZE); - sourceItem.setAmount(itemsLeftOver - MAX_ITEM_STACK_SIZE); - } else { - // Cursor will be emptied - destItem.setAmount(itemsLeftOver); - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); - } - ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( - destSlot, - destItem.getItemStack() - ); - session.sendDownstreamPacket(creativeActionPacket); - affectedSlots.add(destSlot); - break; - } - } else { - // Delete the source since we're moving it - inventory.setItem(sourceSlot, GeyserItemStack.EMPTY, session); - ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( - sourceSlot, - new ItemStack(0) - ); - session.sendDownstreamPacket(creativeActionPacket); - affectedSlots.add(sourceSlot); - } - // Update the item count with however much the client took - newItem.setAmount(transferAction.getCount()); - // Remove that amount from the existing item - sourceItem.setAmount(sourceItem.getAmount() - transferAction.getCount()); - if (sourceItem.isEmpty()) { - // Item is basically deleted - if (sourceIsCursor) { - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); - } else { - inventory.setItem(sourceSlot, GeyserItemStack.EMPTY, session); - } - } - if (destIsCursor) { - session.getPlayerInventory().setCursor(newItem, session); - } else { - inventory.setItem(destSlot, newItem, session); - } - GeyserItemStack itemToUpdate = destIsCursor ? sourceItem : newItem; - // The Java server doesn't care about what's in the mouse in creative mode, so we just need to track - // which inventory slot the client modified - ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( - destIsCursor ? sourceSlot : destSlot, - itemToUpdate.isEmpty() ? new ItemStack(0) : itemToUpdate.getItemStack() - ); - session.sendDownstreamPacket(creativeActionPacket); - - if (!sourceIsCursor) { // Cursor is always added for us as an affected slot - affectedSlots.add(sourceSlot); - } - if (!destIsCursor) { - affectedSlots.add(destSlot); - } - } else if (isCursor(transferAction.getSource())) { //releasing cursor int sourceAmount = cursor.getAmount(); if (transferAction.getCount() == sourceAmount) { //release all @@ -359,35 +286,7 @@ public abstract class InventoryTranslator { if (!(checkNetId(session, inventory, swapAction.getSource()) && checkNetId(session, inventory, swapAction.getDestination()))) return rejectRequest(request); - if (session.getGameMode().equals(GameMode.CREATIVE) && inventory instanceof PlayerInventory) { - int destSlot = bedrockSlotToJava(swapAction.getDestination()); - GeyserItemStack oldSourceItem; - GeyserItemStack oldDestinationItem = inventory.getItem(destSlot); - if (isCursor(swapAction.getSource())) { - oldSourceItem = session.getPlayerInventory().getCursor(); - session.getPlayerInventory().setCursor(oldDestinationItem, session); - } else { - int sourceSlot = bedrockSlotToJava(swapAction.getSource()); - oldSourceItem = inventory.getItem(sourceSlot); - ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( - sourceSlot, - oldDestinationItem.isEmpty() ? new ItemStack(0) : oldDestinationItem.getItemStack() // isEmpty check... just in case - ); - session.sendDownstreamPacket(creativeActionPacket); - inventory.setItem(sourceSlot, oldDestinationItem, session); - } - if (isCursor(swapAction.getDestination())) { - session.getPlayerInventory().setCursor(oldSourceItem, session); - } else { - ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( - destSlot, - oldSourceItem.isEmpty() ? new ItemStack(0) : oldSourceItem.getItemStack() - ); - session.sendDownstreamPacket(creativeActionPacket); - inventory.setItem(destSlot, oldSourceItem, session); - } - - } else if (isCursor(swapAction.getSource()) && isCursor(swapAction.getDestination())) { //??? + if (isCursor(swapAction.getSource()) && isCursor(swapAction.getDestination())) { //??? return rejectRequest(request); } else if (isCursor(swapAction.getSource())) { //swap cursor int destSlot = bedrockSlotToJava(swapAction.getDestination()); @@ -425,29 +324,12 @@ public abstract class InventoryTranslator { return rejectRequest(request); if (isCursor(dropAction.getSource())) { //clicking outside of window - if (session.getGameMode() == GameMode.CREATIVE && inventory instanceof PlayerInventory) { - GeyserItemStack cursorItem = session.getPlayerInventory().getCursor(); - GeyserItemStack droppingItem = cursorItem.copy(); - // Subtract the cursor item by however much is being dropped - cursorItem.setAmount(cursorItem.getAmount() - dropAction.getCount()); - if (cursorItem.isEmpty()) { - // Cursor item no longer exists - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); - } - droppingItem.setAmount(dropAction.getCount()); - ClientCreativeInventoryActionPacket packet = new ClientCreativeInventoryActionPacket( - Click.OUTSIDE_SLOT, - droppingItem.getItemStack() - ); - session.sendDownstreamPacket(packet); - } else { - int sourceAmount = plan.getCursor().getAmount(); - if (dropAction.getCount() == sourceAmount) { //drop all - plan.add(Click.LEFT_OUTSIDE, Click.OUTSIDE_SLOT); - } else { //drop some - for (int i = 0; i < dropAction.getCount(); i++) { - plan.add(Click.RIGHT_OUTSIDE, Click.OUTSIDE_SLOT); //drop one until goal is met - } + int sourceAmount = plan.getCursor().getAmount(); + if (dropAction.getCount() == sourceAmount) { //drop all + plan.add(Click.LEFT_OUTSIDE, Click.OUTSIDE_SLOT); + } else { //drop some + for (int i = 0; i < dropAction.getCount(); i++) { + plan.add(Click.RIGHT_OUTSIDE, Click.OUTSIDE_SLOT); //drop one until goal is met } } } else { //dropping from inventory @@ -463,39 +345,6 @@ public abstract class InventoryTranslator { } break; } - case DESTROY: { - // Only called when a creative client wants to destroy an item... I think - Camotoy - DestroyStackRequestActionData destroyAction = (DestroyStackRequestActionData) action; - if (!session.getGameMode().equals(GameMode.CREATIVE)) { - // If this happens, let's throw an error and figure out why. - return rejectRequest(request); - } - if (!isCursor(destroyAction.getSource())) { - // Item exists; let's remove it from the inventory - int javaSlot = bedrockSlotToJava(destroyAction.getSource()); - GeyserItemStack existingItem = inventory.getItem(javaSlot); - existingItem.setAmount(existingItem.getAmount() - destroyAction.getCount()); - ClientCreativeInventoryActionPacket destroyItemPacket; - if (existingItem.isEmpty()) { - destroyItemPacket = new ClientCreativeInventoryActionPacket( - javaSlot, - new ItemStack(0) - ); - inventory.setItem(javaSlot, GeyserItemStack.EMPTY, session); - } else { - destroyItemPacket = new ClientCreativeInventoryActionPacket( - javaSlot, - existingItem.getItemStack() - ); - } - session.sendDownstreamPacket(destroyItemPacket); - affectedSlots.add(javaSlot); - } else { - // Just sync up the item on our end, since the server doesn't care what's in our cursor - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); - } - break; - } // The following three tend to be called for UI inventories case CONSUME: { if (inventory instanceof CartographyContainer) { @@ -838,73 +687,7 @@ public abstract class InventoryTranslator { } public ItemStackResponsePacket.Response translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { - int creativeId = 0; - CraftState craftState = CraftState.START; - for (StackRequestActionData action : request.getActions()) { - switch (action.getType()) { - case CRAFT_CREATIVE: { - CraftCreativeStackRequestActionData creativeAction = (CraftCreativeStackRequestActionData) action; - if (craftState != CraftState.START) { - return rejectRequest(request); - } - craftState = CraftState.RECIPE_ID; - - creativeId = creativeAction.getCreativeItemNetworkId(); - break; - } - case CRAFT_RESULTS_DEPRECATED: { - CraftResultsDeprecatedStackRequestActionData deprecatedCraftAction = (CraftResultsDeprecatedStackRequestActionData) action; - if (craftState != CraftState.RECIPE_ID) { - return rejectRequest(request); - } - craftState = CraftState.DEPRECATED; - break; - } - case TAKE: - case PLACE: { - TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action; - if (craftState != CraftState.DEPRECATED) { - return rejectRequest(request); - } - craftState = CraftState.TRANSFER; - - if (transferAction.getSource().getContainer() != ContainerSlotType.CREATIVE_OUTPUT) { - return rejectRequest(request); - } - // Reference the creative items list we send to the client to know what it's asking of us - ItemData creativeItem = ItemRegistry.CREATIVE_ITEMS[creativeId - 1]; - // Get the correct count - creativeItem = ItemData.of(creativeItem.getId(), creativeItem.getDamage(), transferAction.getCount(), creativeItem.getTag()); - ItemStack javaCreativeItem = ItemTranslator.translateToJava(creativeItem); - - if (isCursor(transferAction.getDestination())) { - session.getPlayerInventory().setCursor(GeyserItemStack.from(javaCreativeItem), session); - return acceptRequest(request, Collections.singletonList( - new ItemStackResponsePacket.ContainerEntry(ContainerSlotType.CURSOR, - Collections.singletonList(makeItemEntry(0, session.getPlayerInventory().getCursor()))))); - } else { - int javaSlot = bedrockSlotToJava(transferAction.getDestination()); - GeyserItemStack existingItem = inventory.getItem(javaSlot); - if (existingItem.getJavaId() == javaCreativeItem.getId()) { - // Adding more to an existing item - existingItem.setAmount(existingItem.getAmount() + transferAction.getCount()); - javaCreativeItem = existingItem.getItemStack(); - } else { - inventory.setItem(javaSlot, GeyserItemStack.from(javaCreativeItem), session); - } - ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( - javaSlot, - javaCreativeItem - ); - session.sendDownstreamPacket(creativeActionPacket); - Set affectedSlots = Collections.singleton(javaSlot); - return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); - } - } - default: - return rejectRequest(request); - } - } + // Handled in PlayerInventoryTranslator return rejectRequest(request); } @@ -1040,11 +823,11 @@ public abstract class InventoryTranslator { return itemEntry; } - private static boolean isCursor(StackRequestSlotInfoData slotInfoData) { + protected static boolean isCursor(StackRequestSlotInfoData slotInfoData) { return slotInfoData.getContainer() == ContainerSlotType.CURSOR; } - private enum CraftState { + protected enum CraftState { START, RECIPE_ID, DEPRECATED, diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java index 51ff0f5d2..c5a2db1c8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java @@ -25,18 +25,26 @@ package org.geysermc.connector.network.translators.inventory.translators; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket; import com.nukkitx.protocol.bedrock.data.inventory.*; +import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.*; import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; +import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.inventory.SlotType; +import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.utils.InventoryUtils; import org.geysermc.connector.utils.LanguageUtils; @@ -207,6 +215,253 @@ public class PlayerInventoryTranslator extends InventoryTranslator { super.translateRequests(session, inventory, requests); } + @Override + public ItemStackResponsePacket.Response translateRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + if (session.getGameMode() != GameMode.CREATIVE) { + return super.translateRequest(session, inventory, request); + } + + PlayerInventory playerInv = session.getPlayerInventory(); + IntSet affectedSlots = new IntOpenHashSet(); + for (StackRequestActionData action : request.getActions()) { + switch (action.getType()) { + case TAKE: + case PLACE: { + TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action; + if (!(checkNetId(session, inventory, transferAction.getSource()) && checkNetId(session, inventory, transferAction.getDestination()))) { + return rejectRequest(request); + } + if (isCraftingGrid(transferAction.getSource()) || isCraftingGrid(transferAction.getDestination())) { + return rejectRequest(request, false); + } + + int transferAmount = transferAction.getCount(); + if (isCursor(transferAction.getDestination())) { + int sourceSlot = bedrockSlotToJava(transferAction.getSource()); + GeyserItemStack sourceItem = inventory.getItem(sourceSlot); + if (playerInv.getCursor().isEmpty()) { + playerInv.setCursor(sourceItem.copy(0), session); + } + + playerInv.getCursor().add(transferAmount); + sourceItem.sub(transferAmount); + + affectedSlots.add(sourceSlot); + } else if (isCursor(transferAction.getSource())) { + int destSlot = bedrockSlotToJava(transferAction.getDestination()); + GeyserItemStack sourceItem = playerInv.getCursor(); + if (inventory.getItem(destSlot).isEmpty()) { + inventory.setItem(destSlot, sourceItem.copy(0), session); + } + + inventory.getItem(destSlot).add(transferAmount); + sourceItem.sub(transferAmount); + + affectedSlots.add(destSlot); + } else { + int sourceSlot = bedrockSlotToJava(transferAction.getSource()); + int destSlot = bedrockSlotToJava(transferAction.getDestination()); + GeyserItemStack sourceItem = inventory.getItem(sourceSlot); + if (inventory.getItem(destSlot).isEmpty()) { + inventory.setItem(destSlot, sourceItem.copy(0), session); + } + + inventory.getItem(destSlot).add(transferAmount); + sourceItem.sub(transferAmount); + + affectedSlots.add(sourceSlot); + affectedSlots.add(destSlot); + } + break; + } + case SWAP: { + SwapStackRequestActionData swapAction = (SwapStackRequestActionData) action; + if (!(checkNetId(session, inventory, swapAction.getSource()) && checkNetId(session, inventory, swapAction.getDestination()))) { + return rejectRequest(request); + } + if (isCraftingGrid(swapAction.getSource()) || isCraftingGrid(swapAction.getDestination())) { + return rejectRequest(request, false); + } + + if (isCursor(swapAction.getDestination())) { + int sourceSlot = bedrockSlotToJava(swapAction.getSource()); + GeyserItemStack sourceItem = inventory.getItem(sourceSlot); + GeyserItemStack destItem = playerInv.getCursor(); + + playerInv.setCursor(sourceItem, session); + inventory.setItem(sourceSlot, destItem, session); + + affectedSlots.add(sourceSlot); + } else if (isCursor(swapAction.getSource())) { + int destSlot = bedrockSlotToJava(swapAction.getDestination()); + GeyserItemStack sourceItem = playerInv.getCursor(); + GeyserItemStack destItem = inventory.getItem(destSlot); + + inventory.setItem(destSlot, sourceItem, session); + playerInv.setCursor(destItem, session); + + affectedSlots.add(destSlot); + } else { + int sourceSlot = bedrockSlotToJava(swapAction.getSource()); + int destSlot = bedrockSlotToJava(swapAction.getDestination()); + GeyserItemStack sourceItem = inventory.getItem(sourceSlot); + GeyserItemStack destItem = inventory.getItem(destSlot); + + inventory.setItem(destSlot, sourceItem, session); + inventory.setItem(sourceSlot, destItem, session); + + affectedSlots.add(sourceSlot); + affectedSlots.add(destSlot); + } + break; + } + case DROP: { + DropStackRequestActionData dropAction = (DropStackRequestActionData) action; + if (!checkNetId(session, inventory, dropAction.getSource())) { + return rejectRequest(request); + } + if (isCraftingGrid(dropAction.getSource())) { + return rejectRequest(request, false); + } + + GeyserItemStack sourceItem; + if (isCursor(dropAction.getSource())) { + sourceItem = playerInv.getCursor(); + } else { + int sourceSlot = bedrockSlotToJava(dropAction.getSource()); + sourceItem = inventory.getItem(sourceSlot); + affectedSlots.add(sourceSlot); + } + + if (sourceItem.isEmpty()) { + return rejectRequest(request); + } + + ClientCreativeInventoryActionPacket creativeDropPacket = new ClientCreativeInventoryActionPacket(-1, sourceItem.getItemStack(dropAction.getCount())); + session.sendDownstreamPacket(creativeDropPacket); + + sourceItem.sub(dropAction.getCount()); + break; + } + case DESTROY: { + // Only called when a creative client wants to destroy an item... I think - Camotoy + DestroyStackRequestActionData destroyAction = (DestroyStackRequestActionData) action; + if (!checkNetId(session, inventory, destroyAction.getSource())) { + return rejectRequest(request); + } + if (isCraftingGrid(destroyAction.getSource())) { + return rejectRequest(request, false); + } + + if (!isCursor(destroyAction.getSource())) { + // Item exists; let's remove it from the inventory + int javaSlot = bedrockSlotToJava(destroyAction.getSource()); + GeyserItemStack existingItem = inventory.getItem(javaSlot); + existingItem.sub(destroyAction.getCount()); + affectedSlots.add(javaSlot); + } else { + // Just sync up the item on our end, since the server doesn't care what's in our cursor + playerInv.getCursor().sub(destroyAction.getCount()); + } + break; + } + default: + return rejectRequest(request); + } + } + for (int slot : affectedSlots) { + sendCreativeAction(session, inventory, slot); + } + return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); + } + + @Override + public ItemStackResponsePacket.Response translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + ItemStack javaCreativeItem = null; + IntSet affectedSlots = new IntOpenHashSet(); + CraftState craftState = CraftState.START; + for (StackRequestActionData action : request.getActions()) { + switch (action.getType()) { + case CRAFT_CREATIVE: { + CraftCreativeStackRequestActionData creativeAction = (CraftCreativeStackRequestActionData) action; + if (craftState != CraftState.START) { + return rejectRequest(request); + } + craftState = CraftState.RECIPE_ID; + + int creativeId = creativeAction.getCreativeItemNetworkId() - 1; + if (creativeId < 0 || creativeId >= ItemRegistry.CREATIVE_ITEMS.length) { + return rejectRequest(request); + } + // Reference the creative items list we send to the client to know what it's asking of us + ItemData creativeItem = ItemRegistry.CREATIVE_ITEMS[creativeId]; + javaCreativeItem = ItemTranslator.translateToJava(creativeItem); + break; + } + case CRAFT_RESULTS_DEPRECATED: { + CraftResultsDeprecatedStackRequestActionData deprecatedCraftAction = (CraftResultsDeprecatedStackRequestActionData) action; + if (craftState != CraftState.RECIPE_ID) { + return rejectRequest(request); + } + craftState = CraftState.DEPRECATED; + break; + } + case TAKE: + case PLACE: { + TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action; + if (!(craftState == CraftState.DEPRECATED || craftState == CraftState.TRANSFER)) { + return rejectRequest(request); + } + craftState = CraftState.TRANSFER; + + if (transferAction.getSource().getContainer() != ContainerSlotType.CREATIVE_OUTPUT) { + return rejectRequest(request); + } + + if (isCursor(transferAction.getDestination())) { + if (session.getPlayerInventory().getCursor().isEmpty()) { + GeyserItemStack newItemStack = GeyserItemStack.from(javaCreativeItem); + newItemStack.setAmount(transferAction.getCount()); + session.getPlayerInventory().setCursor(newItemStack, session); + } else { + session.getPlayerInventory().getCursor().add(transferAction.getCount()); + } + //cursor is always included in response + } else { + int destSlot = bedrockSlotToJava(transferAction.getDestination()); + if (inventory.getItem(destSlot).isEmpty()) { + GeyserItemStack newItemStack = GeyserItemStack.from(javaCreativeItem); + newItemStack.setAmount(transferAction.getCount()); + inventory.setItem(destSlot, newItemStack, session); + } else { + inventory.getItem(destSlot).add(transferAction.getCount()); + } + affectedSlots.add(destSlot); + } + break; + } + default: + return rejectRequest(request); + } + } + for (int slot : affectedSlots) { + sendCreativeAction(session, inventory, slot); + } + return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); + } + + private static void sendCreativeAction(GeyserSession session, Inventory inventory, int slot) { + GeyserItemStack item = inventory.getItem(slot); + ItemStack itemStack = item.isEmpty() ? new ItemStack(-1, 0, null) : item.getItemStack(); + + ClientCreativeInventoryActionPacket creativePacket = new ClientCreativeInventoryActionPacket(slot, itemStack); + session.sendDownstreamPacket(creativePacket); + } + + private static boolean isCraftingGrid(StackRequestSlotInfoData slotInfoData) { + return slotInfoData.getContainer() == ContainerSlotType.CRAFTING_INPUT; + } + @Override public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { throw new UnsupportedOperationException(); From 2304c1375e39b9027e1f7de051973bcb69d627e9 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 19 Jan 2021 18:22:07 -0500 Subject: [PATCH 052/101] [ci skip] Clarify strip NBT comment --- .../translators/java/JavaDeclareRecipesTranslator.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java index 07b839f9c..45b300ceb 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -68,7 +68,8 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator Date: Tue, 19 Jan 2021 19:01:51 -0500 Subject: [PATCH 053/101] Add some comments and fix book editing in creative --- .../bedrock/BedrockBookEditTranslator.java | 74 +++++++++---------- .../BedrockItemStackRequestTranslator.java | 3 + .../java/JavaDeclareRecipesTranslator.java | 6 ++ 3 files changed, 44 insertions(+), 39 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBookEditTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBookEditTranslator.java index 67778e822..8e2d77df7 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBookEditTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBookEditTranslator.java @@ -26,7 +26,6 @@ package org.geysermc.connector.network.translators.bedrock; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientEditBookPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; @@ -54,51 +53,48 @@ public class BedrockBookEditTranslator extends PacketTranslator List pages = tag.contains("pages") ? new LinkedList<>(((ListTag) tag.get("pages")).getValue()) : new LinkedList<>(); int page = packet.getPageNumber(); - // Creative edits the NBT for us - if (session.getGameMode() != GameMode.CREATIVE) { - switch (packet.getAction()) { - case ADD_PAGE: { + switch (packet.getAction()) { + case ADD_PAGE: { + // Add empty pages in between + for (int i = pages.size(); i < page; i++) { + pages.add(i, new StringTag("", "")); + } + pages.add(page, new StringTag("", packet.getText())); + break; + } + // Called whenever a page is modified + case REPLACE_PAGE: { + if (page < pages.size()) { + pages.set(page, new StringTag("", packet.getText())); + } else { // Add empty pages in between for (int i = pages.size(); i < page; i++) { pages.add(i, new StringTag("", "")); } pages.add(page, new StringTag("", packet.getText())); - break; } - // Called whenever a page is modified - case REPLACE_PAGE: { - if (page < pages.size()) { - pages.set(page, new StringTag("", packet.getText())); - } else { - // Add empty pages in between - for (int i = pages.size(); i < page; i++) { - pages.add(i, new StringTag("", "")); - } - pages.add(page, new StringTag("", packet.getText())); - } - break; - } - case DELETE_PAGE: { - if (page < pages.size()) { - pages.remove(page); - } - break; - } - case SWAP_PAGES: { - int page2 = packet.getSecondaryPageNumber(); - if (page < pages.size() && page2 < pages.size()) { - Collections.swap(pages, page, page2); - } - break; - } - case SIGN_BOOK: { - tag.put(new StringTag("author", packet.getAuthor())); - tag.put(new StringTag("title", packet.getTitle())); - break; - } - default: - return; + break; } + case DELETE_PAGE: { + if (page < pages.size()) { + pages.remove(page); + } + break; + } + case SWAP_PAGES: { + int page2 = packet.getSecondaryPageNumber(); + if (page < pages.size() && page2 < pages.size()) { + Collections.swap(pages, page, page2); + } + break; + } + case SIGN_BOOK: { + tag.put(new StringTag("author", packet.getAuthor())); + tag.put(new StringTag("title", packet.getTitle())); + break; + } + default: + return; } // Remove empty pages at the end while (pages.size() > 0) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java index a08d87496..bdbb88eee 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemStackRequestTranslator.java @@ -32,6 +32,9 @@ import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +/** + * The packet sent for server-authoritative-style inventory transactions. + */ @Translator(packet = ItemStackRequestPacket.class) public class BedrockItemStackRequestTranslator extends PacketTranslator { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java index 45b300ceb..ee8f03306 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -196,6 +196,12 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator, IntSet> squashedOptions = new HashMap<>(); for (int i = 0; i < ingredients.length; i++) { From 5d4b368e51bdda8e7d0843310e5ff9ff9070358d Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Wed, 20 Jan 2021 11:09:28 -0900 Subject: [PATCH 054/101] Fix inventory bug when respawning --- .../network/translators/java/JavaRespawnTranslator.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java index b986c7ef5..55fdcacd1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java @@ -35,6 +35,7 @@ import org.geysermc.connector.entity.attribute.AttributeType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.utils.DimensionUtils; @Translator(packet = ServerRespawnPacket.class) @@ -48,7 +49,10 @@ public class JavaRespawnTranslator extends PacketTranslator // Max health must be divisible by two in bedrock entity.getAttributes().put(AttributeType.HEALTH, AttributeType.HEALTH.getAttribute(maxHealth, (maxHealth % 2 == 1 ? maxHealth + 1 : maxHealth))); - session.setOpenInventory(null); + session.addInventoryTask(() -> { + session.setInventoryTranslator(InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR); + session.setOpenInventory(null); + }); SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket(); playerGameTypePacket.setGamemode(packet.getGamemode().ordinal()); From 787e6fe5f7fb10d26d372510fd39c7fdd6a4bc59 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 20 Jan 2021 18:46:04 -0500 Subject: [PATCH 055/101] Fix enchantments when there are less than three options --- .../geysermc/connector/inventory/EnchantingContainer.java | 3 +++ .../geysermc/connector/inventory/GeyserEnchantOption.java | 8 ++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/inventory/EnchantingContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/EnchantingContainer.java index 8638e6eab..d11ca6788 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/EnchantingContainer.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/EnchantingContainer.java @@ -47,6 +47,9 @@ public class EnchantingContainer extends Container { geyserEnchantOptions = new GeyserEnchantOption[3]; for (int i = 0; i < geyserEnchantOptions.length; i++) { geyserEnchantOptions[i] = new GeyserEnchantOption(i); + // Options cannot be null, so we build initial options + // GeyserSession can be safely null here because it's only needed for net IDs + enchantOptions[i] = geyserEnchantOptions[i].build(null); } } } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/GeyserEnchantOption.java b/connector/src/main/java/org/geysermc/connector/inventory/GeyserEnchantOption.java index a643fc194..e9ad81a6a 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/GeyserEnchantOption.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/GeyserEnchantOption.java @@ -67,12 +67,8 @@ public class GeyserEnchantOption { } public EnchantOptionData build(GeyserSession session) { - if (enchantLevel == -1) { - // Should not be sent to the client, as it is supposed to be empty - return null; - } return new EnchantOptionData(xpCost, javaIndex + 16, EMPTY, - Collections.singletonList(new EnchantData(bedrockEnchantIndex, enchantLevel)), EMPTY, - javaEnchantIndex == -1 ? "unknown" : ENCHANT_NAMES.get(javaEnchantIndex), session.getNextItemNetId()); + enchantLevel == -1 ? EMPTY : Collections.singletonList(new EnchantData(bedrockEnchantIndex, enchantLevel)), EMPTY, + javaEnchantIndex == -1 ? "unknown" : ENCHANT_NAMES.get(javaEnchantIndex), enchantLevel == -1 ? 0 : session.getNextItemNetId()); } } From 1676242c4f4b099e2a1586bc5270726fbd6ffccf Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 22 Jan 2021 13:36:27 -0500 Subject: [PATCH 056/101] Add precaution if lectern container is not open --- .../translators/bedrock/BedrockLecternUpdateTranslator.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockLecternUpdateTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockLecternUpdateTranslator.java index b7c8aa05c..cfcf762f8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockLecternUpdateTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockLecternUpdateTranslator.java @@ -31,7 +31,6 @@ import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPlaceBlockPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientClickWindowButtonPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCloseWindowPacket; -import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.packet.LecternUpdatePacket; import org.geysermc.connector.inventory.LecternContainer; import org.geysermc.connector.network.session.GeyserSession; @@ -60,6 +59,10 @@ public class BedrockLecternUpdateTranslator extends PacketTranslator Date: Fri, 29 Jan 2021 00:36:43 -0500 Subject: [PATCH 057/101] Add more debug logging --- .../translators/inventory/InventoryTranslator.java | 8 ++------ .../inventory/translators/PlayerInventoryTranslator.java | 1 + 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index b6f22dc61..e5a9705bc 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -32,10 +32,8 @@ import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; import com.github.steveice10.mc.protocol.data.game.window.WindowType; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.*; import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; @@ -55,8 +53,6 @@ import org.geysermc.connector.network.translators.inventory.translators.chest.Si import org.geysermc.connector.network.translators.inventory.translators.furnace.BlastFurnaceInventoryTranslator; import org.geysermc.connector.network.translators.inventory.translators.furnace.FurnaceInventoryTranslator; import org.geysermc.connector.network.translators.inventory.translators.furnace.SmokerInventoryTranslator; -import org.geysermc.connector.network.translators.item.ItemRegistry; -import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.utils.InventoryUtils; import java.util.*; @@ -200,7 +196,7 @@ public abstract class InventoryTranslator { transferAction.getSource().getSlot() >= 28 && transferAction.getSource().getSlot() <= 31) { return rejectRequest(request, false); } - session.getConnector().getLogger().error("DEBUG: About to reject request."); + session.getConnector().getLogger().error("DEBUG: About to reject request made by " + session.getName()); session.getConnector().getLogger().error("Source: " + transferAction.getSource().toString() + " Result: " + checkNetId(session, inventory, transferAction.getSource())); session.getConnector().getLogger().error("Destination: " + transferAction.getDestination().toString() + " Result: " + checkNetId(session, inventory, transferAction.getDestination())); return rejectRequest(request); @@ -733,7 +729,7 @@ public abstract class InventoryTranslator { public static ItemStackResponsePacket.Response rejectRequest(ItemStackRequestPacket.Request request, boolean throwError) { if (throwError) { // Currently for debugging, but might be worth it to keep in the future if something goes terribly wrong. - new Throwable("DEBUGGING: ItemStackRequest rejected").printStackTrace(); + new Throwable("DEBUGGING: ItemStackRequest rejected " + request.toString()).printStackTrace(); } return new ItemStackResponsePacket.Response(ItemStackResponsePacket.ResponseStatus.ERROR, request.getRequestId(), Collections.emptyList()); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java index c5a2db1c8..ffb97addd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java @@ -366,6 +366,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { break; } default: + session.getConnector().getLogger().error("Unknown crafting state induced by " + session.getName()); return rejectRequest(request); } } From 4a8d93752b1bef601cd9458b7c82faf9bad2631b Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Fri, 29 Jan 2021 03:34:56 -0900 Subject: [PATCH 058/101] Handle DESTROY creative action --- .../translators/PlayerInventoryTranslator.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java index ffb97addd..288f5926e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java @@ -407,6 +407,17 @@ public class PlayerInventoryTranslator extends InventoryTranslator { craftState = CraftState.DEPRECATED; break; } + case DESTROY: { + DestroyStackRequestActionData destroyAction = (DestroyStackRequestActionData) action; + if (craftState != CraftState.DEPRECATED) { + return rejectRequest(request); + } + + int sourceSlot = bedrockSlotToJava(destroyAction.getSource()); + inventory.setItem(sourceSlot, GeyserItemStack.EMPTY, session); //assume all creative destroy requests will empty the slot + affectedSlots.add(sourceSlot); + break; + } case TAKE: case PLACE: { TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action; From 454896a7adadafb2728a72669608f032d46811b2 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 30 Jan 2021 16:05:27 -0500 Subject: [PATCH 059/101] Start work on using the world block for inventories --- .../connector/inventory/Container.java | 7 +++ .../inventory/Generic3X3Container.java | 41 ++++++++++++++ .../network/session/GeyserSession.java | 17 ++++-- ...BedrockInventoryTransactionTranslator.java | 5 +- .../BedrockLecternUpdateTranslator.java | 4 +- .../inventory/InventoryTranslator.java | 5 +- .../holder/BlockInventoryHolder.java | 55 +++++++++++++++---- .../AbstractBlockInventoryTranslator.java | 8 +-- .../translators/AnvilInventoryTranslator.java | 3 +- .../Generic3X3InventoryTranslator.java | 48 ++++++++++++++++ ...or.java => HopperInventoryTranslator.java} | 8 +-- .../LecternInventoryTranslator.java | 3 +- .../chest/DoubleChestInventoryTranslator.java | 26 +++++++-- .../chest/SingleChestInventoryTranslator.java | 5 +- .../java/world/JavaBlockChangeTranslator.java | 2 +- 15 files changed, 195 insertions(+), 42 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/inventory/Generic3X3Container.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/{GenericBlockInventoryTranslator.java => HopperInventoryTranslator.java} (85%) diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Container.java b/connector/src/main/java/org/geysermc/connector/inventory/Container.java index 520a76ef3..5284868a0 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Container.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Container.java @@ -27,6 +27,7 @@ package org.geysermc.connector.inventory; import lombok.Getter; import lombok.NonNull; +import lombok.Setter; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; @@ -38,6 +39,12 @@ public class Container extends Inventory { private final PlayerInventory playerInventory; private final int containerSize; + /** + * Whether we are using a real block when opening this inventory. + */ + @Setter + private boolean isUsingRealBlock = false; + public Container(String title, int id, int size, PlayerInventory playerInventory) { super(title, id, size); this.playerInventory = playerInventory; diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Generic3X3Container.java b/connector/src/main/java/org/geysermc/connector/inventory/Generic3X3Container.java new file mode 100644 index 000000000..8cc820ccc --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/inventory/Generic3X3Container.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019-2021 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.inventory; + +import lombok.Getter; +import lombok.Setter; + +public class Generic3X3Container extends Container { + /** + * Whether we need to set the container type as {@link com.nukkitx.protocol.bedrock.data.inventory.ContainerType#DROPPER} + */ + @Getter @Setter + private boolean isDropper = false; + + public Generic3X3Container(String title, int id, int size, PlayerInventory playerInventory) { + super(title, id, size, playerInventory); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 17c6bd66c..5c3e921a6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -38,7 +38,6 @@ import com.github.steveice10.mc.protocol.data.SubProtocol; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; import com.github.steveice10.mc.protocol.data.game.statistic.Statistic; -import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket; @@ -73,10 +72,10 @@ import lombok.Setter; import org.geysermc.common.window.CustomFormWindow; import org.geysermc.common.window.FormWindow; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.entity.Tickable; import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.common.AuthType; import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.entity.Tickable; import org.geysermc.connector.entity.player.SessionPlayerEntity; import org.geysermc.connector.entity.player.SkullPlayerEntity; import org.geysermc.connector.inventory.Inventory; @@ -231,7 +230,15 @@ public class GeyserSession implements CommandSender { * Initialized as (0, 0, 0) so it is always not-null. */ @Setter - private Vector3i lastInteractionPosition = Vector3i.ZERO; + private Vector3i lastInteractionBlockPosition = Vector3i.ZERO; + + /** + * Stores the position of the player the last time they interacted. + * Used to verify that the player did not move since their last interaction.
+ * Initialized as (0, 0, 0) so it is always not-null. + */ + @Setter + private Vector3f lastInteractionPlayerPosition = Vector3f.ZERO; @Setter private Entity ridingVehicleEntity; @@ -239,15 +246,13 @@ public class GeyserSession implements CommandSender { @Setter private long lastWindowCloseTime = 0; - @Setter - private VillagerTrade[] villagerTrades; @Setter private long lastInteractedVillagerEid; @Setter private Int2ObjectMap craftingRecipes; private final Set unlockedRecipes; - private AtomicInteger lastRecipeNetId; + private final AtomicInteger lastRecipeNetId; /** * Saves a list of all stonecutter recipes, for use in a stonecutter inventory. diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index d6c9badb9..79f658188 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -117,8 +117,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { @Override public void translate(LecternUpdatePacket packet, GeyserSession session) { - session.getConnector().getLogger().error(packet.toString()); if (packet.isDroppingBook()) { // Bedrock drops the book outside of the GUI. Java drops it in the GUI // So, we enter the GUI and then drop it! :) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index e5a9705bc..7fd24080e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -33,7 +33,6 @@ import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.*; import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; @@ -94,8 +93,8 @@ public abstract class InventoryTranslator { put(WindowType.STONECUTTER, new StonecutterInventoryTranslator()); /* Generics */ - put(WindowType.GENERIC_3X3, new GenericBlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER)); - put(WindowType.HOPPER, new GenericBlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER)); + put(WindowType.GENERIC_3X3, new Generic3X3InventoryTranslator()); + put(WindowType.HOPPER, new HopperInventoryTranslator()); /* Lectern */ put(WindowType.LECTERN, new LecternInventoryTranslator()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java index 5c49c723e..35b46fe63 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java @@ -26,39 +26,70 @@ package org.geysermc.connector.network.translators.inventory.holder; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.google.common.collect.Sets; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; -import lombok.AllArgsConstructor; +import org.geysermc.connector.inventory.Container; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import java.util.Collections; +import java.util.Set; + /** - * Manages the fake block we implement for each inventory. + * Manages the fake block we implement for each inventory, should we need to. + * This class will attempt to use a real block first, if possible. */ -@AllArgsConstructor public class BlockInventoryHolder extends InventoryHolder { - private final int blockId; + /** + * The default Bedrock block ID to use as a fake block + */ + private final int defaultBedrockBlockId; private final ContainerType containerType; + private final Set validBlocks; + + public BlockInventoryHolder(String javaBlockIdentifier, ContainerType containerType, String... validBlocks) { + int javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); + this.defaultBedrockBlockId = BlockTranslator.getBedrockBlockId(javaBlockState); + this.containerType = containerType; + if (validBlocks != null) { + this.validBlocks = Sets.newHashSet(validBlocks); + this.validBlocks.add(javaBlockIdentifier.split("\\[")[0]); + } else { + this.validBlocks = Collections.singleton(javaBlockIdentifier.split("\\[")[0]); + } + } @Override public void prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { - //TODO: Improve on this (for example, multiple block states). We need this for the beacon. - if (BlockTranslator.getBedrockBlockId(session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionPosition())) == blockId) { - inventory.setHolderPosition(session.getLastInteractionPosition()); - return; + // Check to see if there is an existing block we can use that the player just selected. + // First, verify that the player's position has not changed, so we don't try to select a block wildly out of range. + // (This could be a virtual inventory that the player is opening) + if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) { + // Then, check to see if the interacted block is valid for this inventory by ensuring the block state identifier is valid + int javaBlockId = session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition()); + String javaBlockString = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(javaBlockId, "minecraft:air").split("\\[")[0]; + if (this.validBlocks.contains(javaBlockString)) { + // We can safely use this block + inventory.setHolderPosition(session.getLastInteractionBlockPosition()); + ((Container) inventory).setUsingRealBlock(true); + return; + } } + + // Otherwise, time to conjure up a fake block! Vector3i position = session.getPlayerEntity().getPosition().toInt(); position = position.add(Vector3i.UP); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(blockId); + blockPacket.setRuntimeId(defaultBedrockBlockId); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); inventory.setHolderPosition(position); @@ -86,10 +117,12 @@ public class BlockInventoryHolder extends InventoryHolder { @Override public void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { - Vector3i holderPos = inventory.getHolderPosition(); - if (holderPos.equals(session.getLastInteractionPosition())) { + if (((Container) inventory).isUsingRealBlock()) { + // No need to reset a block since we didn't change any blocks return; } + + Vector3i holderPos = inventory.getHolderPosition(); Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); int realBlock = session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java index 92710656d..8664dc192 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java @@ -31,7 +31,6 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder; import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; /** * Provided as a base for any inventory that requires a block for opening it @@ -45,11 +44,12 @@ public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTran * @param javaBlockIdentifier a Java block identifier that is used as a temporary block * @param containerType the container type of this inventory * @param updater updater + * @param additionalValidBlocks any other block identifiers that can safely use this inventory without a fake block */ - public AbstractBlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater) { + public AbstractBlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater, + String... additionalValidBlocks) { super(size); - int javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); - this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), containerType); + this.holder = new BlockInventoryHolder(javaBlockIdentifier, containerType, additionalValidBlocks); this.updater = updater; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java index 9d4fbfeec..0d2b62153 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java @@ -48,7 +48,8 @@ import org.geysermc.connector.network.translators.item.ItemTranslator; public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { public AnvilInventoryTranslator() { - super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL, UIInventoryUpdater.INSTANCE); + super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL, UIInventoryUpdater.INSTANCE, + "minecraft:chipped_anvil", "minecraft:damaged_anvil"); } /* 1.16.100 support start */ diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java new file mode 100644 index 000000000..daa47b61c --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019-2021 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.translators.inventory.translators; + +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import org.geysermc.connector.inventory.Generic3X3Container; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.PlayerInventory; +import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; + +/** + * Droppers and dispensers + */ +public class Generic3X3InventoryTranslator extends AbstractBlockInventoryTranslator { + //TODO allow droppers to use their own block - this requires changing the ContainerType to DROPPER + public Generic3X3InventoryTranslator() { + super(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, UIInventoryUpdater.INSTANCE); + } + + @Override + public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { + return new Generic3X3Container(name, windowId, this.size, playerInventory); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/HopperInventoryTranslator.java similarity index 85% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/HopperInventoryTranslator.java index 55df41c1e..f7525d958 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/HopperInventoryTranslator.java @@ -28,14 +28,14 @@ package org.geysermc.connector.network.translators.inventory.translators; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; -import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; +import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; /** * Implemented on top of any block that does not have special properties implemented */ -public class GenericBlockInventoryTranslator extends AbstractBlockInventoryTranslator { - public GenericBlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType) { - super(size, javaBlockIdentifier, containerType, ContainerInventoryUpdater.INSTANCE); +public class HopperInventoryTranslator extends AbstractBlockInventoryTranslator { + public HopperInventoryTranslator() { + super(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, UIInventoryUpdater.INSTANCE); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java index 9ce0ee0d1..157f63164 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java @@ -98,7 +98,7 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { CompoundTag tag = geyserItemStack.getNbt(); if (tag != null) { // Position has to be the last interacted position... right? - Vector3i position = session.getLastInteractionPosition(); + Vector3i position = session.getLastInteractionBlockPosition(); // shouldRefresh means that we should boot out the client on our side because their lectern GUI isn't updated yet boolean shouldRefresh = !session.getConnector().getWorldManager().shouldExpectLecternHandled() && !session.getLecternCache().contains(position); int pagesSize = ((ListTag) tag.get("pages")).size(); @@ -124,7 +124,6 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(lecternContainer.getId()); session.sendDownstreamPacket(closeWindowPacket); InventoryUtils.closeInventory(session, inventory.getId()); - session.getConnector().getLogger().warning("Closing inventory"); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java index c27eacff5..81efc1540 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java @@ -32,28 +32,41 @@ import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; +import org.geysermc.connector.inventory.Container; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockTranslator; public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { - private final int blockId; + private final int defaultBedrockBlockId; public DoubleChestInventoryTranslator(int size) { super(size, 54); int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); - this.blockId = BlockTranslator.getBedrockBlockId(javaBlockState); + this.defaultBedrockBlockId = BlockTranslator.getBedrockBlockId(javaBlockState); } @Override public void prepareInventory(GeyserSession session, Inventory inventory) { + // See BlockInventoryHolder - same concept there except we're also dealing with a specific block state + if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) { + int javaBlockId = session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition()); + String[] javaBlockString = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(javaBlockId, "minecraft:air").split("\\["); + if (javaBlockString.length > 1 && (javaBlockString[0].equals("minecraft:chest") || javaBlockString[0].equals("minecraft:trapped_chest")) + && !javaBlockString[1].contains("type=single")) { + inventory.setHolderPosition(session.getLastInteractionBlockPosition()); + ((Container) inventory).setUsingRealBlock(true); + return; + } + } + Vector3i position = session.getPlayerEntity().getPosition().toInt().add(Vector3i.UP); Vector3i pairPosition = position.add(Vector3i.UNIT_X); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(blockId); + blockPacket.setRuntimeId(defaultBedrockBlockId); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); @@ -73,7 +86,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(pairPosition); - blockPacket.setRuntimeId(blockId); + blockPacket.setRuntimeId(defaultBedrockBlockId); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); @@ -105,6 +118,11 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { @Override public void closeInventory(GeyserSession session, Inventory inventory) { + if (((Container) inventory).isUsingRealBlock()) { + // No need to reset a block since we didn't change any blocks + return; + } + Vector3i holderPos = inventory.getHolderPosition(); Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); int realBlock = session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java index 9fc3c0165..0861f62fd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java @@ -30,15 +30,14 @@ import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; public class SingleChestInventoryTranslator extends ChestInventoryTranslator { private final InventoryHolder holder; public SingleChestInventoryTranslator(int size) { super(size, 27); - int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); - this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), ContainerType.CONTAINER); + this.holder = new BlockInventoryHolder("minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER, + "minecraft:chest", "minecraft:ender_chest", "minecraft:trapped_chest"); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java index d74165b14..9bff2652e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java @@ -93,7 +93,7 @@ public class JavaBlockChangeTranslator extends PacketTranslator Date: Fri, 5 Feb 2021 11:48:12 -0500 Subject: [PATCH 060/101] Revert "Start work on using the world block for inventories" Oops! Not finished yet!! This reverts commit 454896a7adadafb2728a72669608f032d46811b2. --- .../connector/inventory/Container.java | 7 --- .../inventory/Generic3X3Container.java | 41 -------------- .../network/session/GeyserSession.java | 17 ++---- ...BedrockInventoryTransactionTranslator.java | 5 +- .../BedrockLecternUpdateTranslator.java | 4 +- .../inventory/InventoryTranslator.java | 5 +- .../holder/BlockInventoryHolder.java | 55 ++++--------------- .../AbstractBlockInventoryTranslator.java | 8 +-- .../translators/AnvilInventoryTranslator.java | 3 +- .../Generic3X3InventoryTranslator.java | 48 ---------------- ...a => GenericBlockInventoryTranslator.java} | 8 +-- .../LecternInventoryTranslator.java | 3 +- .../chest/DoubleChestInventoryTranslator.java | 26 ++------- .../chest/SingleChestInventoryTranslator.java | 5 +- .../java/world/JavaBlockChangeTranslator.java | 2 +- 15 files changed, 42 insertions(+), 195 deletions(-) delete mode 100644 connector/src/main/java/org/geysermc/connector/inventory/Generic3X3Container.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/{HopperInventoryTranslator.java => GenericBlockInventoryTranslator.java} (85%) diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Container.java b/connector/src/main/java/org/geysermc/connector/inventory/Container.java index 5284868a0..520a76ef3 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Container.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Container.java @@ -27,7 +27,6 @@ package org.geysermc.connector.inventory; import lombok.Getter; import lombok.NonNull; -import lombok.Setter; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; @@ -39,12 +38,6 @@ public class Container extends Inventory { private final PlayerInventory playerInventory; private final int containerSize; - /** - * Whether we are using a real block when opening this inventory. - */ - @Setter - private boolean isUsingRealBlock = false; - public Container(String title, int id, int size, PlayerInventory playerInventory) { super(title, id, size); this.playerInventory = playerInventory; diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Generic3X3Container.java b/connector/src/main/java/org/geysermc/connector/inventory/Generic3X3Container.java deleted file mode 100644 index 8cc820ccc..000000000 --- a/connector/src/main/java/org/geysermc/connector/inventory/Generic3X3Container.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2019-2021 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.inventory; - -import lombok.Getter; -import lombok.Setter; - -public class Generic3X3Container extends Container { - /** - * Whether we need to set the container type as {@link com.nukkitx.protocol.bedrock.data.inventory.ContainerType#DROPPER} - */ - @Getter @Setter - private boolean isDropper = false; - - public Generic3X3Container(String title, int id, int size, PlayerInventory playerInventory) { - super(title, id, size, playerInventory); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 5c3e921a6..17c6bd66c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -38,6 +38,7 @@ import com.github.steveice10.mc.protocol.data.SubProtocol; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; import com.github.steveice10.mc.protocol.data.game.statistic.Statistic; +import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket; @@ -72,10 +73,10 @@ import lombok.Setter; import org.geysermc.common.window.CustomFormWindow; import org.geysermc.common.window.FormWindow; import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.entity.Tickable; import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.common.AuthType; import org.geysermc.connector.entity.Entity; -import org.geysermc.connector.entity.Tickable; import org.geysermc.connector.entity.player.SessionPlayerEntity; import org.geysermc.connector.entity.player.SkullPlayerEntity; import org.geysermc.connector.inventory.Inventory; @@ -230,15 +231,7 @@ public class GeyserSession implements CommandSender { * Initialized as (0, 0, 0) so it is always not-null. */ @Setter - private Vector3i lastInteractionBlockPosition = Vector3i.ZERO; - - /** - * Stores the position of the player the last time they interacted. - * Used to verify that the player did not move since their last interaction.
- * Initialized as (0, 0, 0) so it is always not-null. - */ - @Setter - private Vector3f lastInteractionPlayerPosition = Vector3f.ZERO; + private Vector3i lastInteractionPosition = Vector3i.ZERO; @Setter private Entity ridingVehicleEntity; @@ -246,13 +239,15 @@ public class GeyserSession implements CommandSender { @Setter private long lastWindowCloseTime = 0; + @Setter + private VillagerTrade[] villagerTrades; @Setter private long lastInteractedVillagerEid; @Setter private Int2ObjectMap craftingRecipes; private final Set unlockedRecipes; - private final AtomicInteger lastRecipeNetId; + private AtomicInteger lastRecipeNetId; /** * Saves a list of all stonecutter recipes, for use in a stonecutter inventory. diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index 79f658188..d6c9badb9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -117,9 +117,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { @Override public void translate(LecternUpdatePacket packet, GeyserSession session) { + session.getConnector().getLogger().error(packet.toString()); if (packet.isDroppingBook()) { // Bedrock drops the book outside of the GUI. Java drops it in the GUI // So, we enter the GUI and then drop it! :) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index 7fd24080e..e5a9705bc 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -33,6 +33,7 @@ import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.*; import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; @@ -93,8 +94,8 @@ public abstract class InventoryTranslator { put(WindowType.STONECUTTER, new StonecutterInventoryTranslator()); /* Generics */ - put(WindowType.GENERIC_3X3, new Generic3X3InventoryTranslator()); - put(WindowType.HOPPER, new HopperInventoryTranslator()); + put(WindowType.GENERIC_3X3, new GenericBlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER)); + put(WindowType.HOPPER, new GenericBlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER)); /* Lectern */ put(WindowType.LECTERN, new LecternInventoryTranslator()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java index 35b46fe63..5c49c723e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java @@ -26,70 +26,39 @@ package org.geysermc.connector.network.translators.inventory.holder; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; -import com.google.common.collect.Sets; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; -import org.geysermc.connector.inventory.Container; +import lombok.AllArgsConstructor; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import java.util.Collections; -import java.util.Set; - /** - * Manages the fake block we implement for each inventory, should we need to. - * This class will attempt to use a real block first, if possible. + * Manages the fake block we implement for each inventory. */ +@AllArgsConstructor public class BlockInventoryHolder extends InventoryHolder { - /** - * The default Bedrock block ID to use as a fake block - */ - private final int defaultBedrockBlockId; + private final int blockId; private final ContainerType containerType; - private final Set validBlocks; - - public BlockInventoryHolder(String javaBlockIdentifier, ContainerType containerType, String... validBlocks) { - int javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); - this.defaultBedrockBlockId = BlockTranslator.getBedrockBlockId(javaBlockState); - this.containerType = containerType; - if (validBlocks != null) { - this.validBlocks = Sets.newHashSet(validBlocks); - this.validBlocks.add(javaBlockIdentifier.split("\\[")[0]); - } else { - this.validBlocks = Collections.singleton(javaBlockIdentifier.split("\\[")[0]); - } - } @Override public void prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { - // Check to see if there is an existing block we can use that the player just selected. - // First, verify that the player's position has not changed, so we don't try to select a block wildly out of range. - // (This could be a virtual inventory that the player is opening) - if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) { - // Then, check to see if the interacted block is valid for this inventory by ensuring the block state identifier is valid - int javaBlockId = session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition()); - String javaBlockString = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(javaBlockId, "minecraft:air").split("\\[")[0]; - if (this.validBlocks.contains(javaBlockString)) { - // We can safely use this block - inventory.setHolderPosition(session.getLastInteractionBlockPosition()); - ((Container) inventory).setUsingRealBlock(true); - return; - } + //TODO: Improve on this (for example, multiple block states). We need this for the beacon. + if (BlockTranslator.getBedrockBlockId(session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionPosition())) == blockId) { + inventory.setHolderPosition(session.getLastInteractionPosition()); + return; } - - // Otherwise, time to conjure up a fake block! Vector3i position = session.getPlayerEntity().getPosition().toInt(); position = position.add(Vector3i.UP); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(defaultBedrockBlockId); + blockPacket.setRuntimeId(blockId); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); inventory.setHolderPosition(position); @@ -117,12 +86,10 @@ public class BlockInventoryHolder extends InventoryHolder { @Override public void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { - if (((Container) inventory).isUsingRealBlock()) { - // No need to reset a block since we didn't change any blocks + Vector3i holderPos = inventory.getHolderPosition(); + if (holderPos.equals(session.getLastInteractionPosition())) { return; } - - Vector3i holderPos = inventory.getHolderPosition(); Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); int realBlock = session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java index 8664dc192..92710656d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java @@ -31,6 +31,7 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder; import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; /** * Provided as a base for any inventory that requires a block for opening it @@ -44,12 +45,11 @@ public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTran * @param javaBlockIdentifier a Java block identifier that is used as a temporary block * @param containerType the container type of this inventory * @param updater updater - * @param additionalValidBlocks any other block identifiers that can safely use this inventory without a fake block */ - public AbstractBlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater, - String... additionalValidBlocks) { + public AbstractBlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater) { super(size); - this.holder = new BlockInventoryHolder(javaBlockIdentifier, containerType, additionalValidBlocks); + int javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); + this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), containerType); this.updater = updater; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java index 0d2b62153..9d4fbfeec 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java @@ -48,8 +48,7 @@ import org.geysermc.connector.network.translators.item.ItemTranslator; public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { public AnvilInventoryTranslator() { - super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL, UIInventoryUpdater.INSTANCE, - "minecraft:chipped_anvil", "minecraft:damaged_anvil"); + super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL, UIInventoryUpdater.INSTANCE); } /* 1.16.100 support start */ diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java deleted file mode 100644 index daa47b61c..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021 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.translators.inventory.translators; - -import com.github.steveice10.mc.protocol.data.game.window.WindowType; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import org.geysermc.connector.inventory.Generic3X3Container; -import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.inventory.PlayerInventory; -import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; - -/** - * Droppers and dispensers - */ -public class Generic3X3InventoryTranslator extends AbstractBlockInventoryTranslator { - //TODO allow droppers to use their own block - this requires changing the ContainerType to DROPPER - public Generic3X3InventoryTranslator() { - super(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, UIInventoryUpdater.INSTANCE); - } - - @Override - public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { - return new Generic3X3Container(name, windowId, this.size, playerInventory); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/HopperInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java similarity index 85% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/HopperInventoryTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java index f7525d958..55df41c1e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/HopperInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java @@ -28,14 +28,14 @@ package org.geysermc.connector.network.translators.inventory.translators; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; -import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater; +import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; /** * Implemented on top of any block that does not have special properties implemented */ -public class HopperInventoryTranslator extends AbstractBlockInventoryTranslator { - public HopperInventoryTranslator() { - super(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, UIInventoryUpdater.INSTANCE); +public class GenericBlockInventoryTranslator extends AbstractBlockInventoryTranslator { + public GenericBlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType) { + super(size, javaBlockIdentifier, containerType, ContainerInventoryUpdater.INSTANCE); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java index 157f63164..9ce0ee0d1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java @@ -98,7 +98,7 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { CompoundTag tag = geyserItemStack.getNbt(); if (tag != null) { // Position has to be the last interacted position... right? - Vector3i position = session.getLastInteractionBlockPosition(); + Vector3i position = session.getLastInteractionPosition(); // shouldRefresh means that we should boot out the client on our side because their lectern GUI isn't updated yet boolean shouldRefresh = !session.getConnector().getWorldManager().shouldExpectLecternHandled() && !session.getLecternCache().contains(position); int pagesSize = ((ListTag) tag.get("pages")).size(); @@ -124,6 +124,7 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(lecternContainer.getId()); session.sendDownstreamPacket(closeWindowPacket); InventoryUtils.closeInventory(session, inventory.getId()); + session.getConnector().getLogger().warning("Closing inventory"); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java index 81efc1540..c27eacff5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java @@ -32,41 +32,28 @@ import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; -import org.geysermc.connector.inventory.Container; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockTranslator; public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { - private final int defaultBedrockBlockId; + private final int blockId; public DoubleChestInventoryTranslator(int size) { super(size, 54); int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); - this.defaultBedrockBlockId = BlockTranslator.getBedrockBlockId(javaBlockState); + this.blockId = BlockTranslator.getBedrockBlockId(javaBlockState); } @Override public void prepareInventory(GeyserSession session, Inventory inventory) { - // See BlockInventoryHolder - same concept there except we're also dealing with a specific block state - if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) { - int javaBlockId = session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition()); - String[] javaBlockString = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(javaBlockId, "minecraft:air").split("\\["); - if (javaBlockString.length > 1 && (javaBlockString[0].equals("minecraft:chest") || javaBlockString[0].equals("minecraft:trapped_chest")) - && !javaBlockString[1].contains("type=single")) { - inventory.setHolderPosition(session.getLastInteractionBlockPosition()); - ((Container) inventory).setUsingRealBlock(true); - return; - } - } - Vector3i position = session.getPlayerEntity().getPosition().toInt().add(Vector3i.UP); Vector3i pairPosition = position.add(Vector3i.UNIT_X); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(defaultBedrockBlockId); + blockPacket.setRuntimeId(blockId); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); @@ -86,7 +73,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(pairPosition); - blockPacket.setRuntimeId(defaultBedrockBlockId); + blockPacket.setRuntimeId(blockId); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); @@ -118,11 +105,6 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { @Override public void closeInventory(GeyserSession session, Inventory inventory) { - if (((Container) inventory).isUsingRealBlock()) { - // No need to reset a block since we didn't change any blocks - return; - } - Vector3i holderPos = inventory.getHolderPosition(); Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); int realBlock = session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java index 0861f62fd..9fc3c0165 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java @@ -30,14 +30,15 @@ import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; public class SingleChestInventoryTranslator extends ChestInventoryTranslator { private final InventoryHolder holder; public SingleChestInventoryTranslator(int size) { super(size, 27); - this.holder = new BlockInventoryHolder("minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER, - "minecraft:chest", "minecraft:ender_chest", "minecraft:trapped_chest"); + int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); + this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), ContainerType.CONTAINER); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java index 9bff2652e..d74165b14 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java @@ -93,7 +93,7 @@ public class JavaBlockChangeTranslator extends PacketTranslator Date: Sat, 6 Feb 2021 20:06:45 -0500 Subject: [PATCH 061/101] Use static commit of Protocol --- connector/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/connector/pom.xml b/connector/pom.xml index 5be089afd..37218bda2 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -30,9 +30,9 @@ compile - com.nukkitx.protocol + com.github.CloudburstMC.Protocol bedrock-v422 - 2.6.1-SNAPSHOT + 89617b7689 compile From 78337830c6929b759dc6c71dd872d1e945b949fd Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 12 Feb 2021 14:39:41 -0500 Subject: [PATCH 062/101] Use the real block for opening inventory when possible --- .../connector/inventory/Container.java | 15 ++++ .../inventory/Generic3X3Container.java | 48 +++++++++++++ .../network/session/GeyserSession.java | 17 +++-- ...BedrockInventoryTransactionTranslator.java | 5 +- .../BedrockLecternUpdateTranslator.java | 4 +- .../inventory/InventoryTranslator.java | 5 +- .../holder/BlockInventoryHolder.java | 60 +++++++++++++--- .../AbstractBlockInventoryTranslator.java | 8 +-- .../translators/AnvilInventoryTranslator.java | 3 +- .../Generic3X3InventoryTranslator.java | 71 +++++++++++++++++++ ...or.java => HopperInventoryTranslator.java} | 6 +- .../LecternInventoryTranslator.java | 3 +- .../chest/DoubleChestInventoryTranslator.java | 47 ++++++++++-- .../chest/SingleChestInventoryTranslator.java | 5 +- .../java/world/JavaBlockChangeTranslator.java | 2 +- .../DoubleChestBlockEntityTranslator.java | 52 ++++++++------ 16 files changed, 290 insertions(+), 61 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/inventory/Generic3X3Container.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/{GenericBlockInventoryTranslator.java => HopperInventoryTranslator.java} (87%) diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Container.java b/connector/src/main/java/org/geysermc/connector/inventory/Container.java index 520a76ef3..6302a7daa 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Container.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Container.java @@ -38,6 +38,11 @@ public class Container extends Inventory { private final PlayerInventory playerInventory; private final int containerSize; + /** + * Whether we are using a real block when opening this inventory. + */ + private boolean isUsingRealBlock = false; + public Container(String title, int id, int size, PlayerInventory playerInventory) { super(title, id, size); this.playerInventory = playerInventory; @@ -66,4 +71,14 @@ public class Container extends Inventory { public int getSize() { return this.containerSize; } + + /** + * Will be overwritten for droppers. + * + * @param usingRealBlock whether this container is using a real container or not + * @param javaBlockId the Java block string of the block, if real + */ + public void setUsingRealBlock(boolean usingRealBlock, String javaBlockId) { + isUsingRealBlock = usingRealBlock; + } } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Generic3X3Container.java b/connector/src/main/java/org/geysermc/connector/inventory/Generic3X3Container.java new file mode 100644 index 000000000..be8d13a74 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/inventory/Generic3X3Container.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019-2021 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.inventory; + +import lombok.Getter; + +public class Generic3X3Container extends Container { + /** + * Whether we need to set the container type as {@link com.nukkitx.protocol.bedrock.data.inventory.ContainerType#DROPPER} + */ + @Getter + private boolean isDropper = false; + + public Generic3X3Container(String title, int id, int size, PlayerInventory playerInventory) { + super(title, id, size, playerInventory); + } + + @Override + public void setUsingRealBlock(boolean usingRealBlock, String javaBlockId) { + super.setUsingRealBlock(usingRealBlock, javaBlockId); + if (usingRealBlock) { + isDropper = javaBlockId.startsWith("minecraft:dropper"); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 15357ada3..00d654764 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -38,7 +38,6 @@ import com.github.steveice10.mc.protocol.data.SubProtocol; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; import com.github.steveice10.mc.protocol.data.game.statistic.Statistic; -import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket; @@ -73,10 +72,10 @@ import lombok.Setter; import org.geysermc.common.window.CustomFormWindow; import org.geysermc.common.window.FormWindow; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.entity.Tickable; import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.common.AuthType; import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.entity.Tickable; import org.geysermc.connector.entity.player.SessionPlayerEntity; import org.geysermc.connector.entity.player.SkullPlayerEntity; import org.geysermc.connector.inventory.Inventory; @@ -234,7 +233,15 @@ public class GeyserSession implements CommandSender { * Initialized as (0, 0, 0) so it is always not-null. */ @Setter - private Vector3i lastInteractionPosition = Vector3i.ZERO; + private Vector3i lastInteractionBlockPosition = Vector3i.ZERO; + + /** + * Stores the position of the player the last time they interacted. + * Used to verify that the player did not move since their last interaction.
+ * Initialized as (0, 0, 0) so it is always not-null. + */ + @Setter + private Vector3f lastInteractionPlayerPosition = Vector3f.ZERO; @Setter private Entity ridingVehicleEntity; @@ -242,15 +249,13 @@ public class GeyserSession implements CommandSender { @Setter private long lastWindowCloseTime = 0; - @Setter - private VillagerTrade[] villagerTrades; @Setter private long lastInteractedVillagerEid; @Setter private Int2ObjectMap craftingRecipes; private final Set unlockedRecipes; - private AtomicInteger lastRecipeNetId; + private final AtomicInteger lastRecipeNetId; /** * Saves a list of all stonecutter recipes, for use in a stonecutter inventory. diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index d6c9badb9..79f658188 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -117,8 +117,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { @Override public void translate(LecternUpdatePacket packet, GeyserSession session) { - session.getConnector().getLogger().error(packet.toString()); if (packet.isDroppingBook()) { // Bedrock drops the book outside of the GUI. Java drops it in the GUI // So, we enter the GUI and then drop it! :) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index e5a9705bc..7fd24080e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -33,7 +33,6 @@ import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.*; import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; @@ -94,8 +93,8 @@ public abstract class InventoryTranslator { put(WindowType.STONECUTTER, new StonecutterInventoryTranslator()); /* Generics */ - put(WindowType.GENERIC_3X3, new GenericBlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER)); - put(WindowType.HOPPER, new GenericBlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER)); + put(WindowType.GENERIC_3X3, new Generic3X3InventoryTranslator()); + put(WindowType.HOPPER, new HopperInventoryTranslator()); /* Lectern */ put(WindowType.LECTERN, new LecternInventoryTranslator()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java index 5c49c723e..c6da2aeb2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java @@ -26,43 +26,79 @@ package org.geysermc.connector.network.translators.inventory.holder; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.google.common.collect.Sets; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; -import lombok.AllArgsConstructor; +import org.geysermc.connector.inventory.Container; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import java.util.Collections; +import java.util.Set; + /** - * Manages the fake block we implement for each inventory. + * Manages the fake block we implement for each inventory, should we need to. + * This class will attempt to use a real block first, if possible. */ -@AllArgsConstructor public class BlockInventoryHolder extends InventoryHolder { - private final int blockId; + /** + * The default Bedrock block ID to use as a fake block + */ + private final int defaultBedrockBlockId; private final ContainerType containerType; + private final Set validBlocks; + + public BlockInventoryHolder(String javaBlockIdentifier, ContainerType containerType, String... validBlocks) { + int javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); + this.defaultBedrockBlockId = BlockTranslator.getBedrockBlockId(javaBlockState); + this.containerType = containerType; + if (validBlocks != null) { + this.validBlocks = Sets.newHashSet(validBlocks); + this.validBlocks.add(javaBlockIdentifier.split("\\[")[0]); + } else { + this.validBlocks = Collections.singleton(javaBlockIdentifier.split("\\[")[0]); + } + } @Override public void prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { - //TODO: Improve on this (for example, multiple block states). We need this for the beacon. - if (BlockTranslator.getBedrockBlockId(session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionPosition())) == blockId) { - inventory.setHolderPosition(session.getLastInteractionPosition()); - return; + // Check to see if there is an existing block we can use that the player just selected. + // First, verify that the player's position has not changed, so we don't try to select a block wildly out of range. + // (This could be a virtual inventory that the player is opening) + if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) { + // Then, check to see if the interacted block is valid for this inventory by ensuring the block state identifier is valid + int javaBlockId = session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition()); + String javaBlockString = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(javaBlockId, "minecraft:air").split("\\[")[0]; + if (this.validBlocks.contains(javaBlockString)) { + // We can safely use this block + inventory.setHolderPosition(session.getLastInteractionBlockPosition()); + ((Container) inventory).setUsingRealBlock(true, javaBlockString); + setCustomName(session, session.getLastInteractionBlockPosition(), inventory); + return; + } } + + // Otherwise, time to conjure up a fake block! Vector3i position = session.getPlayerEntity().getPosition().toInt(); position = position.add(Vector3i.UP); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(blockId); + blockPacket.setRuntimeId(defaultBedrockBlockId); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); inventory.setHolderPosition(position); + setCustomName(session, position, inventory); + } + + protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory) { NbtMap tag = NbtMap.builder() .putInt("x", position.getX()) .putInt("y", position.getY()) @@ -86,10 +122,12 @@ public class BlockInventoryHolder extends InventoryHolder { @Override public void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { - Vector3i holderPos = inventory.getHolderPosition(); - if (holderPos.equals(session.getLastInteractionPosition())) { + if (((Container) inventory).isUsingRealBlock()) { + // No need to reset a block since we didn't change any blocks return; } + + Vector3i holderPos = inventory.getHolderPosition(); Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); int realBlock = session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java index 92710656d..8664dc192 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java @@ -31,7 +31,6 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder; import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; /** * Provided as a base for any inventory that requires a block for opening it @@ -45,11 +44,12 @@ public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTran * @param javaBlockIdentifier a Java block identifier that is used as a temporary block * @param containerType the container type of this inventory * @param updater updater + * @param additionalValidBlocks any other block identifiers that can safely use this inventory without a fake block */ - public AbstractBlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater) { + public AbstractBlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater, + String... additionalValidBlocks) { super(size); - int javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); - this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), containerType); + this.holder = new BlockInventoryHolder(javaBlockIdentifier, containerType, additionalValidBlocks); this.updater = updater; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java index 9d4fbfeec..0d2b62153 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java @@ -48,7 +48,8 @@ import org.geysermc.connector.network.translators.item.ItemTranslator; public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { public AnvilInventoryTranslator() { - super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL, UIInventoryUpdater.INSTANCE); + super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL, UIInventoryUpdater.INSTANCE, + "minecraft:chipped_anvil", "minecraft:damaged_anvil"); } /* 1.16.100 support start */ diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java new file mode 100644 index 000000000..eb417c51e --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2019-2021 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.translators.inventory.translators; + +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; +import org.geysermc.connector.inventory.Generic3X3Container; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.PlayerInventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; + +/** + * Droppers and dispensers + */ +public class Generic3X3InventoryTranslator extends AbstractBlockInventoryTranslator { + + public Generic3X3InventoryTranslator() { + super(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, ContainerInventoryUpdater.INSTANCE, + "minecraft:dropper"); + } + + @Override + public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { + return new Generic3X3Container(name, windowId, this.size, playerInventory); + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); + containerOpenPacket.setId((byte) inventory.getId()); + containerOpenPacket.setType(((Generic3X3Container) inventory).isDropper() ? ContainerType.DROPPER : ContainerType.DISPENSER); + containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); + containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); + session.sendUpstreamPacket(containerOpenPacket); + } + + @Override + public BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot) { + if (javaSlot < this.size) { + return new BedrockContainerSlot(ContainerSlotType.CONTAINER, javaSlot); + } + return super.javaSlotToBedrockContainer(javaSlot); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/HopperInventoryTranslator.java similarity index 87% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/HopperInventoryTranslator.java index 55df41c1e..7f067d1c0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GenericBlockInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/HopperInventoryTranslator.java @@ -33,9 +33,9 @@ import org.geysermc.connector.network.translators.inventory.updater.ContainerInv /** * Implemented on top of any block that does not have special properties implemented */ -public class GenericBlockInventoryTranslator extends AbstractBlockInventoryTranslator { - public GenericBlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType) { - super(size, javaBlockIdentifier, containerType, ContainerInventoryUpdater.INSTANCE); +public class HopperInventoryTranslator extends AbstractBlockInventoryTranslator { + public HopperInventoryTranslator() { + super(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, ContainerInventoryUpdater.INSTANCE); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java index 9ce0ee0d1..157f63164 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java @@ -98,7 +98,7 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { CompoundTag tag = geyserItemStack.getNbt(); if (tag != null) { // Position has to be the last interacted position... right? - Vector3i position = session.getLastInteractionPosition(); + Vector3i position = session.getLastInteractionBlockPosition(); // shouldRefresh means that we should boot out the client on our side because their lectern GUI isn't updated yet boolean shouldRefresh = !session.getConnector().getWorldManager().shouldExpectLecternHandled() && !session.getLecternCache().contains(position); int pagesSize = ((ListTag) tag.get("pages")).size(); @@ -124,7 +124,6 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(lecternContainer.getId()); session.sendDownstreamPacket(closeWindowPacket); InventoryUtils.closeInventory(session, inventory.getId()); - session.getConnector().getLogger().warning("Closing inventory"); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java index c27eacff5..d1e628fce 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java @@ -28,32 +28,66 @@ package org.geysermc.connector.network.translators.inventory.translators.chest; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; +import org.geysermc.connector.inventory.Container; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.world.block.DoubleChestValue; +import org.geysermc.connector.network.translators.world.block.entity.DoubleChestBlockEntityTranslator; public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { - private final int blockId; + private final int defaultBedrockBlockId; public DoubleChestInventoryTranslator(int size) { super(size, 54); int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); - this.blockId = BlockTranslator.getBedrockBlockId(javaBlockState); + this.defaultBedrockBlockId = BlockTranslator.getBedrockBlockId(javaBlockState); } @Override public void prepareInventory(GeyserSession session, Inventory inventory) { + // See BlockInventoryHolder - same concept there except we're also dealing with a specific block state + if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) { + int javaBlockId = session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition()); + String[] javaBlockString = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(javaBlockId, "minecraft:air").split("\\["); + if (javaBlockString.length > 1 && (javaBlockString[0].equals("minecraft:chest") || javaBlockString[0].equals("minecraft:trapped_chest")) + && !javaBlockString[1].contains("type=single")) { + inventory.setHolderPosition(session.getLastInteractionBlockPosition()); + ((Container) inventory).setUsingRealBlock(true, javaBlockString[0]); + + NbtMapBuilder tag = NbtMap.builder() + .putString("id", "Chest") + .putInt("x", session.getLastInteractionBlockPosition().getX()) + .putInt("y", session.getLastInteractionBlockPosition().getY()) + .putInt("z", session.getLastInteractionBlockPosition().getZ()) + .putString("CustomName", inventory.getTitle()) + .putString("id", "Chest"); + + DoubleChestValue chestValue = BlockStateValues.getDoubleChestValues().get(javaBlockId); + DoubleChestBlockEntityTranslator.translateChestValue(tag, chestValue, + session.getLastInteractionBlockPosition().getX(), session.getLastInteractionBlockPosition().getZ()); + + BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); + dataPacket.setData(tag.build()); + dataPacket.setBlockPosition(session.getLastInteractionBlockPosition()); + session.sendUpstreamPacket(dataPacket); + return; + } + } + Vector3i position = session.getPlayerEntity().getPosition().toInt().add(Vector3i.UP); Vector3i pairPosition = position.add(Vector3i.UNIT_X); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(blockId); + blockPacket.setRuntimeId(defaultBedrockBlockId); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); @@ -73,7 +107,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(pairPosition); - blockPacket.setRuntimeId(blockId); + blockPacket.setRuntimeId(defaultBedrockBlockId); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); @@ -105,6 +139,11 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { @Override public void closeInventory(GeyserSession session, Inventory inventory) { + if (((Container) inventory).isUsingRealBlock()) { + // No need to reset a block since we didn't change any blocks + return; + } + Vector3i holderPos = inventory.getHolderPosition(); Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); int realBlock = session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java index 9fc3c0165..7b9b12c4f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java @@ -30,15 +30,14 @@ import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; public class SingleChestInventoryTranslator extends ChestInventoryTranslator { private final InventoryHolder holder; public SingleChestInventoryTranslator(int size) { super(size, 27); - int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); - this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), ContainerType.CONTAINER); + this.holder = new BlockInventoryHolder("minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER, + "minecraft:ender_chest", "minecraft:trapped_chest"); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java index d74165b14..9bff2652e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java @@ -93,7 +93,7 @@ public class JavaBlockChangeTranslator extends PacketTranslator Date: Fri, 12 Feb 2021 14:43:29 -0500 Subject: [PATCH 063/101] [ci skip] Formatting fixes --- .../inventory/translators/Generic3X3InventoryTranslator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java index eb417c51e..133ec635d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/Generic3X3InventoryTranslator.java @@ -40,7 +40,6 @@ import org.geysermc.connector.network.translators.inventory.updater.ContainerInv * Droppers and dispensers */ public class Generic3X3InventoryTranslator extends AbstractBlockInventoryTranslator { - public Generic3X3InventoryTranslator() { super(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, ContainerInventoryUpdater.INSTANCE, "minecraft:dropper"); @@ -55,6 +54,7 @@ public class Generic3X3InventoryTranslator extends AbstractBlockInventoryTransla public void openInventory(GeyserSession session, Inventory inventory) { ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); containerOpenPacket.setId((byte) inventory.getId()); + // Required for opening the real block - otherwise, if the container type is incorrect, it refuses to open containerOpenPacket.setType(((Generic3X3Container) inventory).isDropper() ? ContainerType.DROPPER : ContainerType.DISPENSER); containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); From ec23e409b628273b95abcf62578b2b8d56f4fbdb Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 13 Feb 2021 15:29:54 -0500 Subject: [PATCH 064/101] Use switch statements, and change default block usage This is to support future changes of using multiple block translators --- .../holder/BlockInventoryHolder.java | 9 ++++---- .../translators/AnvilInventoryTranslator.java | 16 +++++++------- .../BrewingInventoryTranslator.java | 18 ++++++++-------- .../GrindstoneInventoryTranslator.java | 16 +++++++------- .../translators/LoomInventoryTranslator.java | 21 +++++++++---------- .../SmithingInventoryTranslator.java | 16 +++++++------- .../StonecutterInventoryTranslator.java | 11 +++++----- .../chest/DoubleChestInventoryTranslator.java | 11 +++++----- 8 files changed, 59 insertions(+), 59 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java index c6da2aeb2..2db4e86a4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java @@ -48,15 +48,14 @@ import java.util.Set; */ public class BlockInventoryHolder extends InventoryHolder { /** - * The default Bedrock block ID to use as a fake block + * The default Java block ID to translate as a fake block */ - private final int defaultBedrockBlockId; + private final int defaultJavaBlockState; private final ContainerType containerType; private final Set validBlocks; public BlockInventoryHolder(String javaBlockIdentifier, ContainerType containerType, String... validBlocks) { - int javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); - this.defaultBedrockBlockId = BlockTranslator.getBedrockBlockId(javaBlockState); + this.defaultJavaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); this.containerType = containerType; if (validBlocks != null) { this.validBlocks = Sets.newHashSet(validBlocks); @@ -90,7 +89,7 @@ public class BlockInventoryHolder extends InventoryHolder { UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(defaultBedrockBlockId); + blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(defaultJavaBlockState)); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); inventory.setHolderPosition(position); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java index 0d2b62153..854ccb772 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java @@ -103,14 +103,14 @@ public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { @Override public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { - if (slotInfoData.getContainer() == ContainerSlotType.ANVIL_INPUT) { - return 0; - } - if (slotInfoData.getContainer() == ContainerSlotType.ANVIL_MATERIAL) { - return 1; - } - if (slotInfoData.getContainer() == ContainerSlotType.ANVIL_RESULT || slotInfoData.getContainer() == ContainerSlotType.CREATIVE_OUTPUT) { - return 2; + switch (slotInfoData.getContainer()) { + case ANVIL_INPUT: + return 0; + case ANVIL_MATERIAL: + return 1; + case ANVIL_RESULT: + case CREATIVE_OUTPUT: + return 2; } return super.bedrockSlotToJava(slotInfoData); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BrewingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BrewingInventoryTranslator.java index b44350615..992a74511 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BrewingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BrewingInventoryTranslator.java @@ -71,7 +71,6 @@ public class BrewingInventoryTranslator extends AbstractBlockInventoryTranslator public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { if (slotInfoData.getContainer() == ContainerSlotType.BREWING_INPUT) { // Ingredient - // TODO: This hasn't worked and then suddenly, it did. return 3; } if (slotInfoData.getContainer() == ContainerSlotType.BREWING_RESULT) { @@ -98,14 +97,15 @@ public class BrewingInventoryTranslator extends AbstractBlockInventoryTranslator @Override public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { - if (slot == 0 || slot == 1 || slot == 2) { - return new BedrockContainerSlot(ContainerSlotType.BREWING_RESULT, javaSlotToBedrock(slot)); - } - if (slot == 3) { - return new BedrockContainerSlot(ContainerSlotType.BREWING_INPUT, 0); - } - if (slot == 4) { - return new BedrockContainerSlot(ContainerSlotType.BREWING_FUEL, 4); + switch (slot) { + case 0: + case 1: + case 2: + return new BedrockContainerSlot(ContainerSlotType.BREWING_RESULT, javaSlotToBedrock(slot)); + case 3: + return new BedrockContainerSlot(ContainerSlotType.BREWING_INPUT, 0); + case 4: + return new BedrockContainerSlot(ContainerSlotType.BREWING_INPUT, 0); } return super.javaSlotToBedrockContainer(slot); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GrindstoneInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GrindstoneInventoryTranslator.java index 81f2df8b3..65364e147 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GrindstoneInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/GrindstoneInventoryTranslator.java @@ -38,14 +38,14 @@ public class GrindstoneInventoryTranslator extends AbstractBlockInventoryTransla @Override public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { - if (slotInfoData.getContainer() == ContainerSlotType.GRINDSTONE_INPUT) { - return 0; - } - if (slotInfoData.getContainer() == ContainerSlotType.GRINDSTONE_ADDITIONAL) { - return 1; - } - if (slotInfoData.getContainer() == ContainerSlotType.GRINDSTONE_RESULT || slotInfoData.getContainer() == ContainerSlotType.CREATIVE_OUTPUT) { - return 2; + switch (slotInfoData.getContainer()) { + case GRINDSTONE_INPUT: + return 0; + case GRINDSTONE_ADDITIONAL: + return 1; + case GRINDSTONE_RESULT: + case CREATIVE_OUTPUT: + return 2; } return super.bedrockSlotToJava(slotInfoData); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java index 409cc4f15..27e7e0f94 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java @@ -172,17 +172,16 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { @Override public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { - if (slotInfoData.getContainer() == ContainerSlotType.LOOM_INPUT) { - return 0; - } - if (slotInfoData.getContainer() == ContainerSlotType.LOOM_DYE) { - return 1; - } - if (slotInfoData.getContainer() == ContainerSlotType.LOOM_MATERIAL) { - return 2; - } - if (slotInfoData.getContainer() == ContainerSlotType.LOOM_RESULT || slotInfoData.getContainer() == ContainerSlotType.CREATIVE_OUTPUT) { - return 3; + switch (slotInfoData.getContainer()) { + case LOOM_INPUT: + return 0; + case LOOM_DYE: + return 1; + case LOOM_MATERIAL: + return 2; + case LOOM_RESULT: + case CREATIVE_OUTPUT: + return 3; } return super.bedrockSlotToJava(slotInfoData); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/SmithingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/SmithingInventoryTranslator.java index dabe5c511..dbe04f68b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/SmithingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/SmithingInventoryTranslator.java @@ -38,14 +38,14 @@ public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslato @Override public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { - if (slotInfoData.getContainer() == ContainerSlotType.SMITHING_TABLE_INPUT) { - return 0; - } - if (slotInfoData.getContainer() == ContainerSlotType.SMITHING_TABLE_MATERIAL) { - return 1; - } - if (slotInfoData.getContainer() == ContainerSlotType.SMITHING_TABLE_RESULT || slotInfoData.getContainer() == ContainerSlotType.CREATIVE_OUTPUT) { - return 2; + switch (slotInfoData.getContainer()) { + case SMITHING_TABLE_INPUT: + return 0; + case SMITHING_TABLE_MATERIAL: + return 1; + case SMITHING_TABLE_RESULT: + case CREATIVE_OUTPUT: + return 2; } return super.bedrockSlotToJava(slotInfoData); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java index af742c136..78ef48849 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java @@ -91,11 +91,12 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl @Override public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { - if (slotInfoData.getContainer() == ContainerSlotType.STONECUTTER_INPUT) { - return 0; - } - if (slotInfoData.getContainer() == ContainerSlotType.STONECUTTER_RESULT || slotInfoData.getContainer() == ContainerSlotType.CREATIVE_OUTPUT) { - return 1; + switch (slotInfoData.getContainer()) { + case STONECUTTER_INPUT: + return 0; + case STONECUTTER_RESULT: + case CREATIVE_OUTPUT: + return 1; } return super.bedrockSlotToJava(slotInfoData); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java index d1e628fce..5a5c8209d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java @@ -42,12 +42,11 @@ import org.geysermc.connector.network.translators.world.block.DoubleChestValue; import org.geysermc.connector.network.translators.world.block.entity.DoubleChestBlockEntityTranslator; public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { - private final int defaultBedrockBlockId; + private final int defaultJavaBlockState; public DoubleChestInventoryTranslator(int size) { super(size, 54); - int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); - this.defaultBedrockBlockId = BlockTranslator.getBedrockBlockId(javaBlockState); + this.defaultJavaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); } @Override @@ -84,10 +83,12 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { Vector3i position = session.getPlayerEntity().getPosition().toInt().add(Vector3i.UP); Vector3i pairPosition = position.add(Vector3i.UNIT_X); + int bedrockBlockId = BlockTranslator.getBedrockBlockId(defaultJavaBlockState); + UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(defaultBedrockBlockId); + blockPacket.setRuntimeId(bedrockBlockId); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); @@ -107,7 +108,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(pairPosition); - blockPacket.setRuntimeId(defaultBedrockBlockId); + blockPacket.setRuntimeId(bedrockBlockId); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); From 22c39d285e77c4a5e28c7066fc7068f2c5c18033 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 16 Feb 2021 19:09:57 -0500 Subject: [PATCH 065/101] Make BlockInventoryHolder block strings immutable; clean up lectern unloading --- .../inventory/holder/BlockInventoryHolder.java | 9 ++++++--- .../java/world/JavaUnloadChunkTranslator.java | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java index 2db4e86a4..24be49144 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java @@ -26,7 +26,7 @@ package org.geysermc.connector.network.translators.inventory.holder; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; -import com.google.common.collect.Sets; +import com.google.common.collect.ImmutableSet; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; @@ -40,6 +40,7 @@ import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.world.block.BlockTranslator; import java.util.Collections; +import java.util.HashSet; import java.util.Set; /** @@ -58,8 +59,10 @@ public class BlockInventoryHolder extends InventoryHolder { this.defaultJavaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); this.containerType = containerType; if (validBlocks != null) { - this.validBlocks = Sets.newHashSet(validBlocks); - this.validBlocks.add(javaBlockIdentifier.split("\\[")[0]); + Set validBlocksTemp = new HashSet<>(validBlocks.length + 1); + Collections.addAll(validBlocksTemp, validBlocks); + validBlocksTemp.add(javaBlockIdentifier.split("\\[")[0]); + this.validBlocks = ImmutableSet.copyOf(validBlocksTemp); } else { this.validBlocks = Collections.singleton(javaBlockIdentifier.split("\\[")[0]); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUnloadChunkTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUnloadChunkTranslator.java index 7e2ae9859..6d3efc1cb 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUnloadChunkTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUnloadChunkTranslator.java @@ -54,7 +54,7 @@ public class JavaUnloadChunkTranslator extends PacketTranslator> 4) == packet.getX() && (position.getZ() >> 4) == packet.getZ()) { iterator.remove(); } } From 605201afc0d2b9af1c6b889015a225213e0138c3 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 17 Feb 2021 19:39:10 -0500 Subject: [PATCH 066/101] Make changes required for Protocol 2.6.2 --- .../inventory/InventoryTranslator.java | 26 +++++++++---------- .../translators/AnvilInventoryTranslator.java | 8 ++---- .../BeaconInventoryTranslator.java | 4 +-- .../EnchantingInventoryTranslator.java | 8 ++---- .../translators/LoomInventoryTranslator.java | 4 +-- .../PlayerInventoryTranslator.java | 11 ++------ .../StonecutterInventoryTranslator.java | 4 +-- 7 files changed, 25 insertions(+), 40 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index 7fd24080e..7a9b890b3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -33,9 +33,9 @@ import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; import com.github.steveice10.mc.protocol.data.game.window.WindowType; 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.*; -import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import it.unimi.dsi.fastutil.ints.*; import lombok.AllArgsConstructor; @@ -141,14 +141,14 @@ public abstract class InventoryTranslator { /** * If {@link #shouldHandleRequestFirst(StackRequestActionData, Inventory)} returns true, this will be called */ - public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { return null; } - public void translateRequests(GeyserSession session, Inventory inventory, List requests) { + public void translateRequests(GeyserSession session, Inventory inventory, List requests) { boolean refresh = false; ItemStackResponsePacket responsePacket = new ItemStackResponsePacket(); - for (ItemStackRequestPacket.Request request : requests) { + for (ItemStackRequest request : requests) { ItemStackResponsePacket.Response response; if (request.getActions().length > 0) { StackRequestActionData firstAction = request.getActions()[0]; @@ -181,7 +181,7 @@ public abstract class InventoryTranslator { } } - public ItemStackResponsePacket.Response translateRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + public ItemStackResponsePacket.Response translateRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { ClickPlan plan = new ClickPlan(session, this, inventory); IntSet affectedSlots = new IntOpenHashSet(); for (StackRequestActionData action : request.getActions()) { @@ -380,7 +380,7 @@ public abstract class InventoryTranslator { return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); } - public ItemStackResponsePacket.Response translateCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + public ItemStackResponsePacket.Response translateCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { int recipeId = 0; int resultSize = 0; int timesCrafted = 0; @@ -485,7 +485,7 @@ public abstract class InventoryTranslator { return acceptRequest(request, makeContainerEntries(session, inventory, plan.getAffectedSlots())); } - public ItemStackResponsePacket.Response translateAutoCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + public ItemStackResponsePacket.Response translateAutoCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { int gridSize; int gridDimensions; if (this instanceof PlayerInventoryTranslator) { @@ -681,7 +681,7 @@ public abstract class InventoryTranslator { return acceptRequest(request, makeContainerEntries(session, inventory, plan.getAffectedSlots())); } - public ItemStackResponsePacket.Response translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + public ItemStackResponsePacket.Response translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { // Handled in PlayerInventoryTranslator return rejectRequest(request); } @@ -717,15 +717,15 @@ public abstract class InventoryTranslator { } } - public static ItemStackResponsePacket.Response acceptRequest(ItemStackRequestPacket.Request request, List containerEntries) { + public static ItemStackResponsePacket.Response acceptRequest(ItemStackRequest request, List containerEntries) { return new ItemStackResponsePacket.Response(ItemStackResponsePacket.ResponseStatus.OK, request.getRequestId(), containerEntries); } - public static ItemStackResponsePacket.Response rejectRequest(ItemStackRequestPacket.Request request) { + public static ItemStackResponsePacket.Response rejectRequest(ItemStackRequest request) { return rejectRequest(request, true); } - public static ItemStackResponsePacket.Response rejectRequest(ItemStackRequestPacket.Request request, boolean throwError) { + public static ItemStackResponsePacket.Response rejectRequest(ItemStackRequest request, boolean throwError) { if (throwError) { // Currently for debugging, but might be worth it to keep in the future if something goes terribly wrong. new Throwable("DEBUGGING: ItemStackRequest rejected " + request.toString()).printStackTrace(); @@ -811,9 +811,9 @@ public abstract class InventoryTranslator { public static ItemStackResponsePacket.ItemEntry makeItemEntry(int bedrockSlot, GeyserItemStack itemStack) { ItemStackResponsePacket.ItemEntry itemEntry; if (!itemStack.isEmpty()) { - itemEntry = new ItemStackResponsePacket.ItemEntry((byte) bedrockSlot, (byte) bedrockSlot, (byte) itemStack.getAmount(), itemStack.getNetId(), ""); + itemEntry = new ItemStackResponsePacket.ItemEntry((byte) bedrockSlot, (byte) bedrockSlot, (byte) itemStack.getAmount(), itemStack.getNetId(), "", 0); } else { - itemEntry = new ItemStackResponsePacket.ItemEntry((byte) bedrockSlot, (byte) bedrockSlot, (byte) 0, 0, ""); + itemEntry = new ItemStackResponsePacket.ItemEntry((byte) bedrockSlot, (byte) bedrockSlot, (byte) 0, 0, "", 0); } return itemEntry; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java index 854ccb772..ded198ef6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AnvilInventoryTranslator.java @@ -28,14 +28,10 @@ package org.geysermc.connector.network.translators.inventory.translators; import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientRenameItemPacket; import com.nukkitx.nbt.NbtMap; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; -import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +import com.nukkitx.protocol.bedrock.data.inventory.*; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.CraftResultsDeprecatedStackRequestActionData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType; -import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import org.geysermc.connector.inventory.AnvilContainer; import org.geysermc.connector.inventory.GeyserItemStack; @@ -61,7 +57,7 @@ public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { @Override @Deprecated - public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { if (!(request.getActions()[1] instanceof CraftResultsDeprecatedStackRequestActionData)) { // Just silently log an error session.getConnector().getLogger().debug("Something isn't quite right with taking an item out of an anvil."); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java index d0db8f3d6..b0cb77151 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/BeaconInventoryTranslator.java @@ -32,12 +32,12 @@ import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.data.inventory.ItemStackRequest; import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.BeaconPaymentStackRequestActionData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; -import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import org.geysermc.connector.inventory.BeaconContainer; import org.geysermc.connector.inventory.Inventory; @@ -93,7 +93,7 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator } @Override - public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { // Input a beacon payment BeaconPaymentStackRequestActionData beaconPayment = (BeaconPaymentStackRequestActionData) request.getActions()[0]; ClientSetBeaconEffectPacket packet = new ClientSetBeaconEffectPacket(beaconPayment.getPrimaryEffect(), beaconPayment.getSecondaryEffect()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java index 8d2f20145..3a25c2a89 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/EnchantingInventoryTranslator.java @@ -27,14 +27,10 @@ package org.geysermc.connector.network.translators.inventory.translators; import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientClickWindowButtonPacket; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.data.inventory.EnchantOptionData; -import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +import com.nukkitx.protocol.bedrock.data.inventory.*; 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.ItemStackRequestPacket; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import com.nukkitx.protocol.bedrock.packet.PlayerEnchantOptionsPacket; import org.geysermc.connector.inventory.EnchantingContainer; @@ -109,7 +105,7 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla } @Override - public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { // Client has requested an item to be enchanted CraftRecipeStackRequestActionData craftRecipeData = (CraftRecipeStackRequestActionData) request.getActions()[0]; EnchantingContainer enchantingInventory = (EnchantingContainer) inventory; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java index 27e7e0f94..3209a161e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java @@ -32,11 +32,11 @@ import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +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.StackRequestActionData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType; -import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; @@ -120,7 +120,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { } @Override - public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { // TODO: I anticipate this will be changed in the future to use something non-deprecated. Keep an eye out. StackRequestActionData data = request.getActions()[1]; if (!(data instanceof CraftResultsDeprecatedStackRequestActionData)) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java index 288f5926e..50a0ae2c7 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java @@ -33,7 +33,6 @@ import com.nukkitx.protocol.bedrock.data.inventory.*; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.*; import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; -import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; @@ -51,7 +50,6 @@ import org.geysermc.connector.utils.LanguageUtils; import java.util.Arrays; import java.util.Collections; -import java.util.List; public class PlayerInventoryTranslator extends InventoryTranslator { private static final ItemData UNUSUABLE_CRAFTING_SPACE_BLOCK = InventoryUtils.createUnusableSpaceBlock(LanguageUtils.getLocaleStringLog("geyser.inventory.unusable_item.creative")); @@ -211,12 +209,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } @Override - public void translateRequests(GeyserSession session, Inventory inventory, List requests) { - super.translateRequests(session, inventory, requests); - } - - @Override - public ItemStackResponsePacket.Response translateRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + public ItemStackResponsePacket.Response translateRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { if (session.getGameMode() != GameMode.CREATIVE) { return super.translateRequest(session, inventory, request); } @@ -377,7 +370,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } @Override - public ItemStackResponsePacket.Response translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + public ItemStackResponsePacket.Response translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { ItemStack javaCreativeItem = null; IntSet affectedSlots = new IntOpenHashSet(); CraftState craftState = CraftState.START; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java index 78ef48849..3c267e121 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java @@ -30,11 +30,11 @@ import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientClickWindowButtonPacket; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +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.StackRequestActionData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType; -import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import it.unimi.dsi.fastutil.ints.IntList; import org.geysermc.connector.inventory.GeyserItemStack; @@ -58,7 +58,7 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl } @Override - public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + 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)) { From f849a5b9f99f38073d775cf85957c93eb094bb0e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 20 Feb 2021 23:52:49 -0500 Subject: [PATCH 067/101] A bunch of fixes --- .../connector/inventory/Inventory.java | 15 ++++++- .../network/UpstreamPacketHandler.java | 1 + .../network/session/GeyserSession.java | 2 +- .../inventory/InventoryTranslator.java | 41 +++++++++---------- .../holder/BlockInventoryHolder.java | 19 +++++++-- .../chest/SingleChestInventoryTranslator.java | 13 +++++- .../window/JavaCloseWindowTranslator.java | 5 ++- .../java/window/JavaOpenWindowTranslator.java | 6 +-- 8 files changed, 69 insertions(+), 33 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java index 7048ce808..535a9077a 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java @@ -36,7 +36,7 @@ import java.util.Arrays; public class Inventory { @Getter - protected int id; + protected final int id; @Getter protected final int size; @@ -96,4 +96,17 @@ public class Inventory { public short getNextTransactionId() { return ++transactionId; } + + @Override + public String toString() { + return "Inventory{" + + "id=" + id + + ", size=" + size + + ", title='" + title + '\'' + + ", items=" + Arrays.toString(items) + + ", holderPosition=" + holderPosition + + ", holderId=" + holderId + + ", transactionId=" + transactionId + + '}'; + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java index 7ebfaeda5..1245fe558 100644 --- a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java @@ -47,6 +47,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { } private boolean translateAndDefault(BedrockPacket packet) { + System.out.println(packet.toString()); return PacketTranslatorRegistry.BEDROCK_TRANSLATOR.translate(packet.getClass(), packet, session); } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 080e8bf02..41269ebf1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -144,7 +144,7 @@ public class GeyserSession implements CommandSender { * Use {@link #getNextItemNetId()} instead for consistency */ @Getter(AccessLevel.NONE) - private final AtomicInteger itemNetId = new AtomicInteger(1); + private final AtomicInteger itemNetId = new AtomicInteger(2); @Getter(AccessLevel.NONE) private final Object inventoryLock = new Object(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index 7a9b890b3..d924c1b88 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -85,6 +85,8 @@ public abstract class InventoryTranslator { put(WindowType.CARTOGRAPHY, new CartographyInventoryTranslator()); put(WindowType.CRAFTING, new CraftingInventoryTranslator()); put(WindowType.ENCHANTMENT, new EnchantingInventoryTranslator()); + put(WindowType.HOPPER, new HopperInventoryTranslator()); + put(WindowType.GENERIC_3X3, new Generic3X3InventoryTranslator()); put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator()); put(WindowType.LOOM, new LoomInventoryTranslator()); put(WindowType.MERCHANT, new MerchantInventoryTranslator()); @@ -92,10 +94,6 @@ public abstract class InventoryTranslator { put(WindowType.SMITHING, new SmithingInventoryTranslator()); put(WindowType.STONECUTTER, new StonecutterInventoryTranslator()); - /* Generics */ - put(WindowType.GENERIC_3X3, new Generic3X3InventoryTranslator()); - put(WindowType.HOPPER, new HopperInventoryTranslator()); - /* Lectern */ put(WindowType.LECTERN, new LecternInventoryTranslator()); } @@ -195,9 +193,11 @@ public abstract class InventoryTranslator { transferAction.getSource().getSlot() >= 28 && transferAction.getSource().getSlot() <= 31) { return rejectRequest(request, false); } - session.getConnector().getLogger().error("DEBUG: About to reject request made by " + session.getName()); + session.getConnector().getLogger().error("DEBUG: About to reject TAKE/PLACE request made by " + session.getName()); session.getConnector().getLogger().error("Source: " + transferAction.getSource().toString() + " Result: " + checkNetId(session, inventory, transferAction.getSource())); session.getConnector().getLogger().error("Destination: " + transferAction.getDestination().toString() + " Result: " + checkNetId(session, inventory, transferAction.getDestination())); + session.getConnector().getLogger().error("Geyser's record of source slot: " + inventory.getItem(bedrockSlotToJava(transferAction.getSource()))); + session.getConnector().getLogger().error("Geyser's record of destination slot: " + inventory.getItem(bedrockSlotToJava(transferAction.getDestination()))); return rejectRequest(request); } @@ -278,8 +278,14 @@ public abstract class InventoryTranslator { } case SWAP: { //TODO SwapStackRequestActionData swapAction = (SwapStackRequestActionData) action; - if (!(checkNetId(session, inventory, swapAction.getSource()) && checkNetId(session, inventory, swapAction.getDestination()))) + if (!(checkNetId(session, inventory, swapAction.getSource()) && checkNetId(session, inventory, swapAction.getDestination()))) { + session.getConnector().getLogger().error("DEBUG: About to reject SWAP request made by " + session.getName()); + session.getConnector().getLogger().error("Source: " + swapAction.getSource().toString() + " Result: " + checkNetId(session, inventory, swapAction.getSource())); + session.getConnector().getLogger().error("Destination: " + swapAction.getDestination().toString() + " Result: " + checkNetId(session, inventory, swapAction.getDestination())); + session.getConnector().getLogger().error("Geyser's record of source slot: " + inventory.getItem(bedrockSlotToJava(swapAction.getSource()))); + session.getConnector().getLogger().error("Geyser's record of destination slot: " + inventory.getItem(bedrockSlotToJava(swapAction.getDestination()))); return rejectRequest(request); + } if (isCursor(swapAction.getSource()) && isCursor(swapAction.getDestination())) { //??? return rejectRequest(request); @@ -361,14 +367,9 @@ public abstract class InventoryTranslator { } break; } - case CRAFT_NON_IMPLEMENTED_DEPRECATED: { - break; - } - case CRAFT_RESULTS_DEPRECATED: { - break; - } - case CRAFT_RECIPE_OPTIONAL: { - // Anvils and cartography tables will handle this + case CRAFT_NON_IMPLEMENTED_DEPRECATED: + case CRAFT_RESULTS_DEPRECATED: + case CRAFT_RECIPE_OPTIONAL: { // Anvils and cartography tables will handle this break; } default: @@ -381,9 +382,8 @@ public abstract class InventoryTranslator { } public ItemStackResponsePacket.Response translateCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { - int recipeId = 0; int resultSize = 0; - int timesCrafted = 0; + int timesCrafted; CraftState craftState = CraftState.START; int leftover = 0; @@ -396,7 +396,6 @@ public abstract class InventoryTranslator { return rejectRequest(request); } craftState = CraftState.RECIPE_ID; - recipeId = craftAction.getRecipeNetworkId(); break; } case CRAFT_RESULTS_DEPRECATED: { @@ -417,7 +416,6 @@ public abstract class InventoryTranslator { break; } case CONSUME: { - ConsumeStackRequestActionData consumeAction = (ConsumeStackRequestActionData) action; if (craftState != CraftState.DEPRECATED && craftState != CraftState.INGREDIENTS) { return rejectRequest(request); } @@ -507,9 +505,7 @@ public abstract class InventoryTranslator { Int2IntMap consumedSlots = new Int2IntOpenHashMap(); int prioritySlot = -1; - int secondarySlot = -1; - int tempSlot = -1; - boolean intoCursor = false; + int tempSlot; int resultSize; int timesCrafted = 0; @@ -626,7 +622,6 @@ public abstract class InventoryTranslator { int javaSlot = bedrockSlotToJava(transferAction.getDestination()); if (isCursor(transferAction.getDestination())) { //TODO - intoCursor = true; if (timesCrafted > 1) { tempSlot = findTempSlot(inventory, GeyserItemStack.from(output), true); if (tempSlot == -1) { @@ -735,6 +730,8 @@ public abstract class InventoryTranslator { public boolean checkNetId(GeyserSession session, Inventory inventory, StackRequestSlotInfoData slotInfoData) { int netId = slotInfoData.getStackNetworkId(); + // "In my testing, sometimes the client thinks the netId of an item in the crafting grid is 1, even though we never said it was. + // I think it only happens when we manually set the grid but that was my quick fix" if (netId < 0 || netId == 1) return true; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java index 24be49144..3186a85e9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java @@ -31,6 +31,7 @@ import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; +import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.connector.inventory.Container; @@ -76,11 +77,11 @@ public class BlockInventoryHolder extends InventoryHolder { if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) { // Then, check to see if the interacted block is valid for this inventory by ensuring the block state identifier is valid int javaBlockId = session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition()); - String javaBlockString = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(javaBlockId, "minecraft:air").split("\\[")[0]; - if (this.validBlocks.contains(javaBlockString)) { + String[] javaBlockString = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(javaBlockId, "minecraft:air").split("\\["); + if (isValidBlock(javaBlockString)) { // We can safely use this block inventory.setHolderPosition(session.getLastInteractionBlockPosition()); - ((Container) inventory).setUsingRealBlock(true, javaBlockString); + ((Container) inventory).setUsingRealBlock(true, javaBlockString[0]); setCustomName(session, session.getLastInteractionBlockPosition(), inventory); return; } @@ -100,6 +101,13 @@ public class BlockInventoryHolder extends InventoryHolder { setCustomName(session, position, inventory); } + /** + * @return true if this Java block ID can be used for player inventory. + */ + protected boolean isValidBlock(String[] javaBlockString) { + return this.validBlocks.contains(javaBlockString[0]); + } + protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory) { NbtMap tag = NbtMap.builder() .putInt("x", position.getX()) @@ -126,6 +134,11 @@ public class BlockInventoryHolder extends InventoryHolder { public void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { if (((Container) inventory).isUsingRealBlock()) { // No need to reset a block since we didn't change any blocks + // But send a container close packet because we aren't destroying the original. + ContainerClosePacket packet = new ContainerClosePacket(); + packet.setId((byte) inventory.getId()); + packet.setUnknownBool0(true); //TODO needs to be changed in Protocol to "server-side" or something + session.sendUpstreamPacket(packet); return; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java index 7b9b12c4f..42b23d5b4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java @@ -37,7 +37,18 @@ public class SingleChestInventoryTranslator extends ChestInventoryTranslator { public SingleChestInventoryTranslator(int size) { super(size, 27); this.holder = new BlockInventoryHolder("minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER, - "minecraft:ender_chest", "minecraft:trapped_chest"); + "minecraft:ender_chest", "minecraft:trapped_chest") { + @Override + protected boolean isValidBlock(String[] javaBlockString) { + if (javaBlockString[0].equals("minecraft:ender_chest")) { + // Can't have double ender chests + return true; + } + + // Add provision to ensure this isn't a double chest + return super.isValidBlock(javaBlockString) && (javaBlockString.length > 1 && javaBlockString[1].contains("type=single")); + } + }; } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java index b78dc32f2..6d3ae0ab1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java @@ -36,6 +36,9 @@ public class JavaCloseWindowTranslator extends PacketTranslator InventoryUtils.closeInventory(session, packet.getWindowId())); + session.addInventoryTask(() -> { + session.getConnector().getLogger().info("Closing window ID " + packet.getWindowId()); + InventoryUtils.closeInventory(session, packet.getWindowId()); + }); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java index 99af2e73e..fa83de7c2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java @@ -45,6 +45,7 @@ public class JavaOpenWindowTranslator extends PacketTranslator Date: Sat, 20 Feb 2021 23:54:15 -0500 Subject: [PATCH 068/101] oops --- .../geysermc/connector/network/UpstreamPacketHandler.java | 1 - .../translators/java/window/JavaCloseWindowTranslator.java | 5 +---- .../translators/java/window/JavaOpenWindowTranslator.java | 1 - 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java index 1245fe558..7ebfaeda5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java @@ -47,7 +47,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { } private boolean translateAndDefault(BedrockPacket packet) { - System.out.println(packet.toString()); return PacketTranslatorRegistry.BEDROCK_TRANSLATOR.translate(packet.getClass(), packet, session); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java index 6d3ae0ab1..b78dc32f2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java @@ -36,9 +36,6 @@ public class JavaCloseWindowTranslator extends PacketTranslator { - session.getConnector().getLogger().info("Closing window ID " + packet.getWindowId()); - InventoryUtils.closeInventory(session, packet.getWindowId()); - }); + session.addInventoryTask(() -> InventoryUtils.closeInventory(session, packet.getWindowId())); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java index fa83de7c2..2d1f77317 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java @@ -45,7 +45,6 @@ public class JavaOpenWindowTranslator extends PacketTranslator Date: Sun, 21 Feb 2021 18:17:31 -0500 Subject: [PATCH 069/101] Small, inconsequential changes --- .../network/translators/world/GeyserWorldManager.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/GeyserWorldManager.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/GeyserWorldManager.java index 8929b7bfa..6d2d8720d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/GeyserWorldManager.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/GeyserWorldManager.java @@ -37,6 +37,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.cache.ChunkCache; import org.geysermc.connector.network.translators.inventory.translators.LecternInventoryTranslator; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.utils.GameRule; public class GeyserWorldManager extends WorldManager { @@ -49,7 +50,7 @@ public class GeyserWorldManager extends WorldManager { if (chunkCache != null) { // Chunk cache can be null if the session is closed asynchronously return chunkCache.getBlockAt(x, y, z); } - return 0; + return BlockTranslator.JAVA_AIR_ID; } @Override @@ -105,7 +106,7 @@ public class GeyserWorldManager extends WorldManager { .putString("text", "") .build()) .build()); - lecternTag.putInt("page", -1); // I'm surprisingly glad this exists - it forces Bedrock to stop reading immediately + lecternTag.putInt("page", -1); // I'm surprisingly glad this exists - it forces Bedrock to stop reading immediately. Usually. return lecternTag.build(); } From 9e6402c279850e67cec31a66b53c59516d8b62c7 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Wed, 24 Feb 2021 20:14:01 -0900 Subject: [PATCH 070/101] Fixes --- .../connector/inventory/Inventory.java | 4 ++ .../network/session/GeyserSession.java | 2 + .../BedrockContainerCloseTranslator.java | 25 ++++++----- .../BedrockLecternUpdateTranslator.java | 2 +- .../LecternInventoryTranslator.java | 4 +- .../chest/DoubleChestInventoryTranslator.java | 6 +++ .../java/JavaRespawnTranslator.java | 1 + .../window/JavaCloseWindowTranslator.java | 2 +- .../java/window/JavaOpenWindowTranslator.java | 4 +- .../connector/utils/InventoryUtils.java | 42 ++++++++++++------- 10 files changed, 59 insertions(+), 33 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java index 535a9077a..179801825 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java @@ -61,6 +61,10 @@ public class Inventory { @Getter protected short transactionId = 0; + @Getter + @Setter + private boolean pending = false; + protected Inventory(int id, int size) { this("Inventory", id, size); } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 41269ebf1..f2fa98ba4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -136,6 +136,8 @@ public class GeyserSession implements CommandSender { private final PlayerInventory playerInventory; @Setter private Inventory openInventory; + @Setter + private boolean closingInventory; @Setter private InventoryTranslator inventoryTranslator = InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java index 6f0f877c8..d46a51ef1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java @@ -31,6 +31,7 @@ import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.utils.InventoryUtils; @Translator(packet = ContainerClosePacket.class) @@ -42,19 +43,21 @@ public class BedrockContainerCloseTranslator extends PacketTranslator session.addInventoryTask(() -> { session.setInventoryTranslator(InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR); session.setOpenInventory(null); + session.setClosingInventory(false); }); SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java index b78dc32f2..639996203 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java @@ -36,6 +36,6 @@ public class JavaCloseWindowTranslator extends PacketTranslator InventoryUtils.closeInventory(session, packet.getWindowId())); + session.addInventoryTask(() -> InventoryUtils.closeInventory(session, packet.getWindowId(), true)); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java index 2d1f77317..db20dfcd2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java @@ -51,7 +51,7 @@ public class JavaOpenWindowTranslator extends PacketTranslator 0) { + if (translator instanceof DoubleChestInventoryTranslator && !((Container) inventory).isUsingRealBlock()) { GeyserConnector.getInstance().getGeneralThreadPool().schedule(() -> { - translator.openInventory(session, inventory); - translator.updateInventory(session, inventory); - }, delay, TimeUnit.MILLISECONDS); + session.addInventoryTask(() -> { + Inventory openInv = session.getOpenInventory(); + if (openInv != null && openInv.getId() == inventory.getId()) { + translator.openInventory(session, inventory); + translator.updateInventory(session, inventory); + } + }); + }, 200, TimeUnit.MILLISECONDS); } else { translator.openInventory(session, inventory); translator.updateInventory(session, inventory); @@ -78,7 +86,7 @@ public class InventoryUtils { } } - public static void closeInventory(GeyserSession session, int windowId) { + public static void closeInventory(GeyserSession session, int windowId, boolean confirm) { session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); updateCursor(session); @@ -86,7 +94,9 @@ public class InventoryUtils { if (inventory != null) { InventoryTranslator translator = session.getInventoryTranslator(); translator.closeInventory(session, inventory); - session.setLastWindowCloseTime(System.currentTimeMillis()); + if (confirm && !inventory.isPending() && !(translator instanceof LecternInventoryTranslator)) { + session.setClosingInventory(true); + } } session.setInventoryTranslator(InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR); session.setOpenInventory(null); From 07f36affb91a2f507e06b8dd2eb3202bf76c469e Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Thu, 25 Feb 2021 01:41:04 -0900 Subject: [PATCH 071/101] Add barrel as a valid single chest block --- .../translators/chest/SingleChestInventoryTranslator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java index 42b23d5b4..0f3b8ecb9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java @@ -37,10 +37,10 @@ public class SingleChestInventoryTranslator extends ChestInventoryTranslator { public SingleChestInventoryTranslator(int size) { super(size, 27); this.holder = new BlockInventoryHolder("minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER, - "minecraft:ender_chest", "minecraft:trapped_chest") { + "minecraft:ender_chest", "minecraft:trapped_chest", "minecraft:barrel") { @Override protected boolean isValidBlock(String[] javaBlockString) { - if (javaBlockString[0].equals("minecraft:ender_chest")) { + if (javaBlockString[0].equals("minecraft:ender_chest") || javaBlockString[0].equals("minecraft:barrel")) { // Can't have double ender chests return true; } From 255c7ac0d2634d91a7319233703f13bf766bfb16 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 25 Feb 2021 12:22:05 -0500 Subject: [PATCH 072/101] Revert "Add barrel as a valid single chest block" Barrels are a bit more complicated to lump in with chests for the time being. It *can* be fixed, but it requires workarounds. This reverts commit 07f36affb91a2f507e06b8dd2eb3202bf76c469e. --- .../translators/chest/SingleChestInventoryTranslator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java index 0f3b8ecb9..42b23d5b4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/SingleChestInventoryTranslator.java @@ -37,10 +37,10 @@ public class SingleChestInventoryTranslator extends ChestInventoryTranslator { public SingleChestInventoryTranslator(int size) { super(size, 27); this.holder = new BlockInventoryHolder("minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER, - "minecraft:ender_chest", "minecraft:trapped_chest", "minecraft:barrel") { + "minecraft:ender_chest", "minecraft:trapped_chest") { @Override protected boolean isValidBlock(String[] javaBlockString) { - if (javaBlockString[0].equals("minecraft:ender_chest") || javaBlockString[0].equals("minecraft:barrel")) { + if (javaBlockString[0].equals("minecraft:ender_chest")) { // Can't have double ender chests return true; } From 072700888195a7ba33afd17a8745aa52b0fa3448 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 25 Feb 2021 16:12:58 -0500 Subject: [PATCH 073/101] Villager fixes + other stuff - Consoles trading with villagers should work better - Villagers closing their inventory work now --- .../BedrockContainerCloseTranslator.java | 7 +++++- .../inventory/InventoryTranslator.java | 25 +++++++++++-------- .../MerchantInventoryTranslator.java | 8 ++++++ 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java index d46a51ef1..c2e0618ba 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java @@ -28,10 +28,10 @@ package org.geysermc.connector.network.translators.bedrock; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCloseWindowPacket; import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket; import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.MerchantContainer; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.utils.InventoryUtils; @Translator(packet = ContainerClosePacket.class) @@ -47,6 +47,11 @@ public class BedrockContainerCloseTranslator extends PacketTranslator Date: Thu, 25 Feb 2021 18:17:43 -0500 Subject: [PATCH 074/101] Fix closing the inventory from the server --- .../java/window/JavaCloseWindowTranslator.java | 2 +- .../geysermc/connector/utils/InventoryUtils.java | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java index 639996203..13295e424 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java @@ -36,6 +36,6 @@ public class JavaCloseWindowTranslator extends PacketTranslator InventoryUtils.closeInventory(session, packet.getWindowId(), true)); + session.addInventoryTask(() -> InventoryUtils.closeInventory(session, packet.getWindowId(), (session.getOpenInventory() != null && session.getOpenInventory().getId() == packet.getWindowId()))); } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java index cf235b4c7..9588333d1 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -39,7 +39,10 @@ import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import com.nukkitx.protocol.bedrock.packet.PlayerHotbarPacket; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.common.ChatColor; -import org.geysermc.connector.inventory.*; +import org.geysermc.connector.inventory.Container; +import org.geysermc.connector.inventory.GeyserItemStack; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.inventory.translators.LecternInventoryTranslator; @@ -70,19 +73,21 @@ public class InventoryUtils { if (translator != null) { translator.prepareInventory(session, inventory); if (translator instanceof DoubleChestInventoryTranslator && !((Container) inventory).isUsingRealBlock()) { - GeyserConnector.getInstance().getGeneralThreadPool().schedule(() -> { + GeyserConnector.getInstance().getGeneralThreadPool().schedule(() -> session.addInventoryTask(() -> { Inventory openInv = session.getOpenInventory(); if (openInv != null && openInv.getId() == inventory.getId()) { translator.openInventory(session, inventory); translator.updateInventory(session, inventory); } - }); - }, 200, TimeUnit.MILLISECONDS); + }), 200, TimeUnit.MILLISECONDS); } else { translator.openInventory(session, inventory); translator.updateInventory(session, inventory); } + } else { + // Precaution - as of 1.16 every inventory should be translated so this shouldn't happen + session.setOpenInventory(null); } } From acbcf4baf32f3cf21730cbe3aa1270d88ae2d25b Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 25 Feb 2021 21:51:50 -0500 Subject: [PATCH 075/101] Fix shulker boxes resetting data and set all shulker boxes as valid --- .../holder/BlockInventoryHolder.java | 6 ++-- .../AbstractBlockInventoryTranslator.java | 11 +++++++ .../ShulkerInventoryTranslator.java | 33 ++++++++++++++++++- .../ShulkerBoxBlockEntityTranslator.java | 8 ++++- 4 files changed, 53 insertions(+), 5 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java index 3186a85e9..8ea24053a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java @@ -82,7 +82,7 @@ public class BlockInventoryHolder extends InventoryHolder { // We can safely use this block inventory.setHolderPosition(session.getLastInteractionBlockPosition()); ((Container) inventory).setUsingRealBlock(true, javaBlockString[0]); - setCustomName(session, session.getLastInteractionBlockPosition(), inventory); + setCustomName(session, session.getLastInteractionBlockPosition(), inventory, javaBlockId); return; } } @@ -98,7 +98,7 @@ public class BlockInventoryHolder extends InventoryHolder { session.sendUpstreamPacket(blockPacket); inventory.setHolderPosition(position); - setCustomName(session, position, inventory); + setCustomName(session, position, inventory, defaultJavaBlockState); } /** @@ -108,7 +108,7 @@ public class BlockInventoryHolder extends InventoryHolder { return this.validBlocks.contains(javaBlockString[0]); } - protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory) { + protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, int javaBlockState) { NbtMap tag = NbtMap.builder() .putInt("x", position.getX()) .putInt("y", position.getY()) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java index 8664dc192..49caef13b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/AbstractBlockInventoryTranslator.java @@ -53,6 +53,17 @@ public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTran this.updater = updater; } + /** + * @param size the amount of slots that the inventory adds alongside the base inventory slots + * @param holder the custom block holder + * @param updater updater + */ + public AbstractBlockInventoryTranslator(int size, InventoryHolder holder, InventoryUpdater updater) { + super(size); + this.holder = holder; + this.updater = updater; + } + @Override public void prepareInventory(GeyserSession session, Inventory inventory) { holder.prepareInventory(this, session, inventory); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/ShulkerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/ShulkerInventoryTranslator.java index 43584df41..76d1cb1cf 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/ShulkerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/ShulkerInventoryTranslator.java @@ -25,14 +25,45 @@ package org.geysermc.connector.network.translators.inventory.translators; +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; +import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; +import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator { public ShulkerInventoryTranslator() { - super(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER, ContainerInventoryUpdater.INSTANCE); + super(27, new BlockInventoryHolder("minecraft:shulker_box[facing=north]", ContainerType.CONTAINER) { + private final BlockEntityTranslator shulkerBoxTranslator = BlockEntityTranslator.BLOCK_ENTITY_TRANSLATORS.get("ShulkerBox"); + + @Override + protected boolean isValidBlock(String[] javaBlockString) { + return javaBlockString[0].contains("shulker_box"); + } + + @Override + protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, int javaBlockState) { + NbtMapBuilder tag = NbtMap.builder() + .putInt("x", position.getX()) + .putInt("y", position.getY()) + .putInt("z", position.getZ()) + .putString("CustomName", inventory.getTitle()); + // Don't reset facing property + shulkerBoxTranslator.translateTag(tag, null, javaBlockState); + + BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); + dataPacket.setData(tag.build()); + dataPacket.setBlockPosition(position); + session.sendUpstreamPacket(dataPacket); + } + }, ContainerInventoryUpdater.INSTANCE); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/ShulkerBoxBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/ShulkerBoxBlockEntityTranslator.java index c09d2f99d..04d58fcce 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/ShulkerBoxBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/ShulkerBoxBlockEntityTranslator.java @@ -29,10 +29,16 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.nbt.NbtMapBuilder; import org.geysermc.connector.network.translators.world.block.BlockStateValues; +import javax.annotation.Nullable; + @BlockEntity(name = "ShulkerBox") public class ShulkerBoxBlockEntityTranslator extends BlockEntityTranslator { + /** + * Also used in {@link org.geysermc.connector.network.translators.inventory.translators.ShulkerInventoryTranslator} + * where {@code tag} is passed as null. + */ @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public void translateTag(NbtMapBuilder builder, @Nullable CompoundTag tag, int blockState) { byte direction = BlockStateValues.getShulkerBoxDirection(blockState); // Just in case... if (direction == -1) { From ae123f883687ddde3c7dd513a36dc33696f3e298 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 26 Feb 2021 00:44:59 -0500 Subject: [PATCH 076/101] [ci skip] Update README --- README.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/README.md b/README.md index 343fca94a..1af88f078 100644 --- a/README.md +++ b/README.md @@ -34,20 +34,9 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set - Test Server: `test.geysermc.org` port `25565` for Java and `19132` for Bedrock ## What's Left to be Added/Fixed -- Lecterns - Near-perfect movement (to the point where anticheat on large servers is unlikely to ban you) - Resource pack conversion/CustomModelData - Some Entity Flags -- The Following Inventories - - Enchantment Table (as a proper GUI) - - Beacon - - Cartography Table - - Stonecutter - - Structure Block - - Horse Inventory - - Loom - - Smithing Table - - Grindstone ## What can't be fixed The following things can't be fixed because of Bedrock limitations. They might be fixable in the future, but not as of now. From 13c924f841c95b69bc75212550191a914e213467 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 26 Feb 2021 00:54:05 -0500 Subject: [PATCH 077/101] Make lecterns more reliable on chunk load in Spigot --- .../spigot/world/manager/GeyserSpigotWorldManager.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java index 25546a3ad..99dbc7763 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -182,7 +182,7 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager { @Override public NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad) { // Run as a task to prevent async issues - Bukkit.getScheduler().runTask(this.plugin, () -> { + Runnable lecternInfoGet = () -> { Player bukkitPlayer; if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) { return; @@ -220,7 +220,13 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager { lecternTag.putCompound("book", bookTag.build()); NbtMap blockEntityTag = lecternTag.build(); BlockEntityUtils.updateBlockEntity(session, blockEntityTag, Vector3i.from(x, y, z)); - }); + }; + if (isChunkLoad) { + // Delay to ensure the chunk is sent first, and then the lectern data + Bukkit.getScheduler().runTaskLater(this.plugin, lecternInfoGet, 5); + } else { + Bukkit.getScheduler().runTask(this.plugin, lecternInfoGet); + } return LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build(); // Will be updated later } From 7aef6b14416d4d953240e3a7337a82e0b003e41a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 26 Feb 2021 00:59:47 -0500 Subject: [PATCH 078/101] [ci skip] Re-add structure block to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1af88f078..5a126025e 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set - Near-perfect movement (to the point where anticheat on large servers is unlikely to ban you) - Resource pack conversion/CustomModelData - Some Entity Flags +- Stonecutter block UI ## What can't be fixed The following things can't be fixed because of Bedrock limitations. They might be fixable in the future, but not as of now. From 9788ed4dc613788e8acf411efa1a88b86c6b6198 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 26 Feb 2021 14:06:00 -0500 Subject: [PATCH 079/101] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a126025e..205162847 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set - Near-perfect movement (to the point where anticheat on large servers is unlikely to ban you) - Resource pack conversion/CustomModelData - Some Entity Flags -- Stonecutter block UI +- Structure block UI ## What can't be fixed The following things can't be fixed because of Bedrock limitations. They might be fixable in the future, but not as of now. From ab9501da6989f9e3d43ae903729ff9ccf7d5e815 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 26 Feb 2021 19:03:18 -0500 Subject: [PATCH 080/101] Use the inventory name always for villager inventories Testing not crashing on 1.8 and 1.13.2. --- .../java/world/JavaTradeListTranslator.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java index 1874fc5e5..8a29be913 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java @@ -31,12 +31,11 @@ import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerTrade import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtType; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.UpdateTradePacket; import org.geysermc.connector.entity.Entity; -import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.inventory.MerchantContainer; import org.geysermc.connector.network.session.GeyserSession; @@ -71,16 +70,7 @@ public class JavaTradeListTranslator extends PacketTranslator Date: Fri, 26 Feb 2021 20:19:14 -0500 Subject: [PATCH 081/101] Fix confirming when the server double-sends a window ID --- .../translators/java/window/JavaCloseWindowTranslator.java | 5 ++++- .../translators/java/window/JavaOpenWindowTranslator.java | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java index 13295e424..9efdee7fc 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java @@ -36,6 +36,9 @@ public class JavaCloseWindowTranslator extends PacketTranslator InventoryUtils.closeInventory(session, packet.getWindowId(), (session.getOpenInventory() != null && session.getOpenInventory().getId() == packet.getWindowId()))); + session.addInventoryTask(() -> + // Sometimes the server can request a window close of ID 0... when the window isn't even open + // Don't confirm in this instance + InventoryUtils.closeInventory(session, packet.getWindowId(), (session.getOpenInventory() != null && session.getOpenInventory().getId() == packet.getWindowId()))); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java index db20dfcd2..77701f97e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java @@ -63,7 +63,8 @@ public class JavaOpenWindowTranslator extends PacketTranslator Date: Fri, 26 Feb 2021 21:53:24 -0500 Subject: [PATCH 082/101] Handle no-NBT lecterns --- .../manager/GeyserSpigotWorldManager.java | 18 ++++-- .../network/session/GeyserSession.java | 2 +- .../LecternInventoryTranslator.java | 55 +++++++++++++------ .../geysermc/connector/utils/ChunkUtils.java | 1 - 4 files changed, 52 insertions(+), 24 deletions(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java index 99dbc7763..a35dd5fc6 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -203,17 +203,27 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager { return; } BookMeta bookMeta = (BookMeta) itemStack.getItemMeta(); - NbtMapBuilder lecternTag = LecternInventoryTranslator.getBaseLecternTag(x, y, z, bookMeta.getPageCount()); + // On the count: allow the book to show/open even there are no pages. We know there is a book here, after all, and this matches Java behavior + boolean hasBookPages = bookMeta.getPageCount() > 0; + NbtMapBuilder lecternTag = LecternInventoryTranslator.getBaseLecternTag(x, y, z, hasBookPages ? bookMeta.getPageCount() : 1); lecternTag.putInt("page", lectern.getPage() / 2); NbtMapBuilder bookTag = NbtMap.builder() .putByte("Count", (byte) itemStack.getAmount()) .putShort("Damage", (short) 0) .putString("Name", "minecraft:writable_book"); - List pages = new ArrayList<>(); - for (String page : bookMeta.getPages()) { + List pages = new ArrayList<>(bookMeta.getPageCount()); + if (hasBookPages) { + for (String page : bookMeta.getPages()) { + NbtMapBuilder pageBuilder = NbtMap.builder() + .putString("photoname", "") + .putString("text", page); + pages.add(pageBuilder.build()); + } + } else { + // Empty page NbtMapBuilder pageBuilder = NbtMap.builder() .putString("photoname", "") - .putString("text", page); + .putString("text", ""); pages.add(pageBuilder.build()); } bookTag.putCompound("tag", NbtMap.builder().putList("pages", NbtType.COMPOUND, pages).build()); diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index f2fa98ba4..393d6275f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -175,7 +175,7 @@ public class GeyserSession implements CommandSender { * See {@link org.geysermc.connector.network.translators.world.WorldManager#getLecternDataAt(GeyserSession, int, int, int, boolean)} * for more information. */ - private final List lecternCache = new ArrayList<>(); + private final Set lecternCache = new ObjectOpenHashSet<>(); @Setter private boolean droppingLecternBook; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java index 05529da3e..084c4fc17 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LecternInventoryTranslator.java @@ -33,6 +33,7 @@ import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.NbtType; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.Inventory; @@ -43,6 +44,8 @@ import org.geysermc.connector.network.translators.inventory.updater.InventoryUpd import org.geysermc.connector.utils.BlockEntityUtils; import org.geysermc.connector.utils.InventoryUtils; +import java.util.Collections; + public class LecternInventoryTranslator extends BaseInventoryTranslator { private final InventoryUpdater updater; @@ -96,11 +99,12 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { // If the method returns true, this is already handled for us GeyserItemStack geyserItemStack = inventory.getItem(0); CompoundTag tag = geyserItemStack.getNbt(); + // Position has to be the last interacted position... right? + Vector3i position = session.getLastInteractionBlockPosition(); + // shouldRefresh means that we should boot out the client on our side because their lectern GUI isn't updated yet + boolean shouldRefresh = !session.getConnector().getWorldManager().shouldExpectLecternHandled() && !session.getLecternCache().contains(position); + NbtMap blockEntityTag; if (tag != null) { - // Position has to be the last interacted position... right? - Vector3i position = session.getLastInteractionBlockPosition(); - // shouldRefresh means that we should boot out the client on our side because their lectern GUI isn't updated yet - boolean shouldRefresh = !session.getConnector().getWorldManager().shouldExpectLecternHandled() && !session.getLecternCache().contains(position); int pagesSize = ((ListTag) tag.get("pages")).size(); ItemData itemData = geyserItemStack.getItemData(session); NbtMapBuilder lecternTag = getBaseLecternTag(position.getX(), position.getY(), position.getZ(), pagesSize); @@ -111,20 +115,35 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { .putCompound("tag", itemData.getTag()) .build()); lecternTag.putInt("page", lecternContainer.getCurrentBedrockPage()); - NbtMap blockEntityTag = lecternTag.build(); - // Even with serverside access to lecterns, we don't easily know which lectern this is, so we need to rebuild - // the block entity tag - lecternContainer.setBlockEntityTag(blockEntityTag); - lecternContainer.setPosition(position); - if (shouldRefresh) { - // Update the lectern because it's not updated client-side - BlockEntityUtils.updateBlockEntity(session, blockEntityTag, position); - session.getLecternCache().add(position); - // Close the window - we will reopen it once the client has this data synced - ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(lecternContainer.getId()); - session.sendDownstreamPacket(closeWindowPacket); - InventoryUtils.closeInventory(session, inventory.getId(), false); - } + blockEntityTag = lecternTag.build(); + } else { + // There is *a* book here, but... no NBT. + NbtMapBuilder lecternTag = getBaseLecternTag(position.getX(), position.getY(), position.getZ(), 1); + NbtMapBuilder bookTag = NbtMap.builder() + .putByte("Count", (byte) 1) + .putShort("Damage", (short) 0) + .putString("Name", "minecraft:writable_book") + .putCompound("tag", NbtMap.builder().putList("pages", NbtType.COMPOUND, Collections.singletonList( + NbtMap.builder() + .putString("photoname", "") + .putString("text", "") + .build() + )).build()); + + blockEntityTag = lecternTag.putCompound("book", bookTag.build()).build(); + } + // Even with serverside access to lecterns, we don't easily know which lectern this is, so we need to rebuild + // the block entity tag + lecternContainer.setBlockEntityTag(blockEntityTag); + lecternContainer.setPosition(position); + if (shouldRefresh) { + // Update the lectern because it's not updated client-side + BlockEntityUtils.updateBlockEntity(session, blockEntityTag, position); + session.getLecternCache().add(position); + // Close the window - we will reopen it once the client has this data synced + ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(lecternContainer.getId()); + session.sendDownstreamPacket(closeWindowPacket); + InventoryUtils.closeInventory(session, inventory.getId(), false); } } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java index 1b13d5dea..45785545c 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java @@ -401,7 +401,6 @@ public class ChunkUtils { boolean newLecternHasBook = BlockStateValues.getLecternBookStates().get(blockState); if (!session.getConnector().getWorldManager().shouldExpectLecternHandled() && lecternCachedHasBook != newLecternHasBook) { // Refresh the block entirely - it either has a book or no longer has a book - session.getConnector().getLogger().warning("Refreshing lectern entirely"); NbtMap newLecternTag; if (newLecternHasBook) { newLecternTag = session.getConnector().getWorldManager().getLecternDataAt(session, position.getX(), position.getY(), position.getZ(), false); From 7e773c99706c8f216ab1d19a0c5e00d181f8c4ba Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 2 Mar 2021 19:10:17 -0500 Subject: [PATCH 083/101] Quietly handle unmappable Java items If vanilla can handle them, so can we. --- .../connector/network/translators/item/ItemTranslator.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java index f63df2f7e..60aa0b52c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java @@ -125,8 +125,12 @@ public abstract class ItemTranslator { } ItemEntry bedrockItem = ItemRegistry.getItem(stack); + if (bedrockItem == null) { + session.getConnector().getLogger().debug("No matching ItemEntry for " + stack); + return ItemData.AIR; + } - com.github.steveice10.opennbt.tag.builtin.CompoundTag nbt = stack.getNbt() != null ? stack.getNbt().clone() : null; + CompoundTag nbt = stack.getNbt() != null ? stack.getNbt().clone() : null; // This is a fallback for maps with no nbt if (nbt == null && bedrockItem.getJavaIdentifier().equals("minecraft:filled_map")) { From ca3f9550dd466adbdd5e1793eb9673624024ab17 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 4 Mar 2021 12:26:16 -0500 Subject: [PATCH 084/101] Remove unused variables; fix opening double chests quickly --- .../geysermc/connector/network/session/GeyserSession.java | 6 ------ .../bedrock/BedrockContainerCloseTranslator.java | 1 - .../bedrock/BedrockInventoryTransactionTranslator.java | 4 ---- .../translators/java/world/JavaTradeListTranslator.java | 7 ++++--- .../java/org/geysermc/connector/utils/InventoryUtils.java | 3 +++ 5 files changed, 7 insertions(+), 14 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 77ca0d6ff..68f6297e1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -250,12 +250,6 @@ public class GeyserSession implements CommandSender { @Setter private Entity ridingVehicleEntity; - @Setter - private long lastWindowCloseTime = 0; - - @Setter - private long lastInteractedVillagerEid; - @Setter private Int2ObjectMap craftingRecipes; private final Set unlockedRecipes; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java index c2e0618ba..21bc1e437 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java @@ -40,7 +40,6 @@ public class BedrockContainerCloseTranslator extends PacketTranslator { - session.setLastWindowCloseTime(0); byte windowId = packet.getId(); //Client wants close confirmation diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index 79f658188..440dff571 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -327,10 +327,6 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator tags = new ArrayList<>(); + boolean addExtraTrade = packet.isRegularVillager() && packet.getVillagerLevel() < 5; + List tags = new ArrayList<>(addExtraTrade ? packet.getTrades().length + 1 : packet.getTrades().length); for (int i = 0; i < packet.getTrades().length; i++) { VillagerTrade trade = packet.getTrades()[i]; NbtMapBuilder recipe = NbtMap.builder(); @@ -101,7 +102,7 @@ public class JavaTradeListTranslator extends PacketTranslator