From c145c3f495b1e9f05e15b65da8c813b2e9a5f11f Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 27 Nov 2024 22:51:59 +0800 Subject: [PATCH 1/3] Fix: Don't include player offset when querying player position in the api (#5168) --- .../geyser/api/entity/type/player/GeyserPlayerEntity.java | 4 ++-- .../geysermc/geyser/entity/type/player/PlayerEntity.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/type/player/GeyserPlayerEntity.java b/api/src/main/java/org/geysermc/geyser/api/entity/type/player/GeyserPlayerEntity.java index bba4dbf3e..d31def996 100644 --- a/api/src/main/java/org/geysermc/geyser/api/entity/type/player/GeyserPlayerEntity.java +++ b/api/src/main/java/org/geysermc/geyser/api/entity/type/player/GeyserPlayerEntity.java @@ -31,9 +31,9 @@ import org.geysermc.geyser.api.entity.type.GeyserEntity; public interface GeyserPlayerEntity extends GeyserEntity { /** - * Gets the position of the player. + * Gets the position of the player, as it is known to the Java server. * - * @return the position of the player. + * @return the player's position */ Vector3f position(); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java index 7e747e33d..7a443d6e8 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java @@ -97,11 +97,11 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { /** * Saves the parrot currently on the player's left shoulder; otherwise null */ - private ParrotEntity leftParrot; + private @Nullable ParrotEntity leftParrot; /** * Saves the parrot currently on the player's right shoulder; otherwise null */ - private ParrotEntity rightParrot; + private @Nullable ParrotEntity rightParrot; public PlayerEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw, String username, @Nullable String texturesProperty) { @@ -450,6 +450,6 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { @Override public Vector3f position() { - return this.position.clone(); + return this.position.down(definition.offset()); } } From c240c1cfb540b79145a4bf758621dbcfe6f06551 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 29 Nov 2024 11:43:58 +0800 Subject: [PATCH 2/3] Fix: Virtual lecterns not displaying book contents (#5169) --- .../geyser/inventory/LecternContainer.java | 14 ++++++-------- .../holder/BlockInventoryHolder.java | 2 +- .../inventory/LecternInventoryTranslator.java | 19 +++++++++---------- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java index 389611c67..ff21f561e 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java @@ -34,17 +34,15 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.java.inventory.JavaOpenBookTranslator; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; +@Getter public class LecternContainer extends Container { - @Getter @Setter + @Setter private int currentBedrockPage = 0; - @Getter @Setter + @Setter private NbtMap blockEntityTag; - @Getter @Setter + @Setter private Vector3i position; - // Sigh. When the lectern container is created, we don't know (yet) if it's fake or not. - // So... time for a manual check :/ - @Getter private boolean isFakeLectern = false; public LecternContainer(String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory) { @@ -52,8 +50,8 @@ public class LecternContainer extends Container { } /** - * When we are using a fake lectern, the Java server expects us to still be in a player inventory. - * We can't use {@link #isUsingRealBlock()} as that may not be determined yet. + * When the Java server asks the client to open a book in their hotbar, we create a fake lectern to show it to the client. + * We can't use the {@link #isUsingRealBlock()} check as we may also be dealing with a real virtual lectern (with its own inventory). */ @Override public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) { diff --git a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java index cdda4fe4c..385a1e2bd 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java @@ -157,7 +157,7 @@ public class BlockInventoryHolder extends InventoryHolder { @Override public void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { if (inventory instanceof Container container) { - if (container.isUsingRealBlock() && !(inventory instanceof LecternContainer)) { + if (container.isUsingRealBlock() && !(container instanceof LecternContainer)) { // 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(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java index 3b33f5909..007811999 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java @@ -30,8 +30,6 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.erosion.util.LecternUtils; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.LecternContainer; @@ -55,7 +53,7 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator * Hack: Java opens a lectern first, and then follows it up with a ClientboundContainerSetContentPacket * to actually send the book's contents. We delay opening the inventory until the book was sent. */ - private boolean initialized = false; + private boolean receivedBook = false; public LecternInventoryTranslator() { super(1, Blocks.LECTERN, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.LECTERN , ContainerInventoryUpdater.INSTANCE); @@ -64,11 +62,12 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator @Override public boolean prepareInventory(GeyserSession session, Inventory inventory) { super.prepareInventory(session, inventory); - if (((Container) inventory).isUsingRealBlock()) { - initialized = false; // We have to wait until we get the book to show to the client + if (((LecternContainer) inventory).isFakeLectern()) { + // See JavaOpenBookTranslator; this isn't a lectern but a book in the player inventory + updateBook(session, inventory, inventory.getItem(0)); + receivedBook = true; } else { - updateBook(session, inventory, inventory.getItem(0)); // See JavaOpenBookTranslator; placed here manually - initialized = true; + receivedBook = false; // We have to wait until we get the book } return true; } @@ -79,7 +78,7 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator // "initialized" indicates whether we've received the book from the Java server yet. // dropping lectern book is the fun workaround when we have to enter the gui to drop the book. // Since we leave it immediately... don't open it! - if (initialized && !session.isDroppingLecternBook()) { + if (receivedBook && !session.isDroppingLecternBook()) { super.openInventory(session, inventory); } } @@ -122,8 +121,8 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator boolean isDropping = session.isDroppingLecternBook(); updateBook(session, inventory, itemStack); - if (!initialized && !isDropping) { - initialized = true; + if (!receivedBook && !isDropping) { + receivedBook = true; openInventory(session, inventory); } } From 1eedf1987c786115dee571e5198a69bd93cb0601 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 1 Dec 2024 11:50:52 -0500 Subject: [PATCH 3/3] Fix #5150 --- .../java/JavaUpdateRecipesTranslator.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 7ea66e0a3..3872321af 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -43,7 +43,6 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.inventory.recipe.TrimRecipe; import org.geysermc.geyser.item.Items; -import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.ItemTranslator; @@ -58,7 +57,6 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.Clientbound import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.Objects; import java.util.UUID; @@ -117,7 +115,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator> unsortedStonecutterData = new Int2ObjectOpenHashMap<>(); + Int2ObjectMap> rawStonecutterData = new Int2ObjectOpenHashMap<>(); List stonecutterRecipes = packet.getStonecutterRecipes(); for (SelectableRecipe recipe : stonecutterRecipes) { @@ -131,19 +129,15 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator new ArrayList<>()).add(recipe); + rawStonecutterData.computeIfAbsent(ingredient.getHolders()[0], $ -> new ArrayList<>()).add(recipe); } Int2ObjectMap stonecutterRecipeMap = new Int2ObjectOpenHashMap<>(); - for (Int2ObjectMap.Entry> data : unsortedStonecutterData.int2ObjectEntrySet()) { - // Sort the list by each output item's Java identifier - this is how it's sorted on Java, and therefore - // We can get the correct order for button pressing - data.getValue().sort(Comparator.comparing((stoneCuttingRecipeData -> - Registries.JAVA_ITEMS.get().get(((ItemStackSlotDisplay) stoneCuttingRecipeData.recipe()).itemStack().getId()) - // See RecipeManager#getRecipesFor as of 1.21 - .translationKey()))); - - // Now that it's sorted, let's translate these recipes + for (Int2ObjectMap.Entry> data : rawStonecutterData.int2ObjectEntrySet()) { + // Implementation note: data used to have to be sorted according to the item translation key. + // This is no longer necessary as of 1.21.2, and is instead presented in the order the server sends us. + // (Recipes are ordered differently between Paper and vanilla) + // See #5150. int buttonId = 0; for (SelectableRecipe recipe : data.getValue()) { // As of 1.16.4, all stonecutter recipes have one ingredient option