From 9cdda707a31d299a24dcff8081fc306c69902e7b Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 14 Jul 2024 20:17:22 +0200 Subject: [PATCH 1/3] Fix: Send a container close packet to Java for containers that could not be opened (#4861) * Close containers if we did not manage to open it * Mark session inventory translator as nonnull --- .../java/org/geysermc/geyser/session/GeyserSession.java | 2 +- .../protocol/java/inventory/JavaOpenBookTranslator.java | 1 + .../main/java/org/geysermc/geyser/util/InventoryUtils.java | 7 ++++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 25dd21662..c2f94b1c6 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -222,7 +222,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private boolean closingInventory; @Setter - private InventoryTranslator inventoryTranslator = InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR; + private @NonNull InventoryTranslator inventoryTranslator = InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR; /** * Use {@link #getNextItemNetId()} instead for consistency diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenBookTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenBookTranslator.java index e7cf21a69..172880725 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenBookTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenBookTranslator.java @@ -70,6 +70,7 @@ public class JavaOpenBookTranslator extends PacketTranslator { Inventory openInv = session.getOpenInventory(); @@ -110,7 +111,11 @@ public class InventoryUtils { inventory.setDisplayed(true); } } else { + // Can occur if we e.g. did not find a spot to put a fake container in + ServerboundContainerClosePacket closePacket = new ServerboundContainerClosePacket(inventory.getJavaId()); + session.sendDownstreamGamePacket(closePacket); session.setOpenInventory(null); + session.setInventoryTranslator(InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR); } } From 06890504a2bfcdbf218a9d2c2874fa1262d91cca Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 14 Jul 2024 21:55:57 +0200 Subject: [PATCH 2/3] Fix: Totem animation when playing totem effects manually (#4860) * Fix: Totem animation for manually played totem effects * Ensure we always reset the offhand correctly --- .../geyser/inventory/PlayerInventory.java | 5 ++++ .../inventory/item/StoredItemMappings.java | 2 ++ .../entity/JavaEntityEventTranslator.java | 27 ++++++++++++++++++- .../geysermc/geyser/util/InventoryUtils.java | 6 +++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java b/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java index 9bef4b08e..c3756d663 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java @@ -29,6 +29,7 @@ import lombok.Getter; import lombok.Setter; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.jetbrains.annotations.Range; @@ -73,6 +74,10 @@ public class PlayerInventory extends Inventory { return items[36 + heldItemSlot]; } + public boolean eitherHandMatchesItem(@NonNull Item item) { + return getItemInHand().asItem() == item || getItemInHand(Hand.OFF_HAND).asItem() == item; + } + public void setItemInHand(@NonNull GeyserItemStack item) { if (36 + heldItemSlot > this.size) { GeyserImpl.getInstance().getLogger().debug("Held item slot was larger than expected!"); diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java b/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java index 05f6ba6cc..475a3e588 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java @@ -50,6 +50,7 @@ public class StoredItemMappings { private final ItemMapping milkBucket; private final ItemMapping powderSnowBucket; private final ItemMapping shield; + private final ItemMapping totem; private final ItemMapping upgradeTemplate; private final ItemMapping wheat; private final ItemMapping writableBook; @@ -66,6 +67,7 @@ public class StoredItemMappings { this.milkBucket = load(itemMappings, Items.MILK_BUCKET); this.powderSnowBucket = load(itemMappings, Items.POWDER_SNOW_BUCKET); this.shield = load(itemMappings, Items.SHIELD); + this.totem = load(itemMappings, Items.TOTEM_OF_UNDYING); this.upgradeTemplate = load(itemMappings, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE); this.wheat = load(itemMappings, Items.WHEAT); this.writableBook = load(itemMappings, Items.WRITABLE_BOOK); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java index e119d39ce..6c2e02cd3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java @@ -29,7 +29,9 @@ import org.cloudburstmc.protocol.bedrock.data.ParticleType; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; +import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; +import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket; @@ -42,11 +44,15 @@ import org.geysermc.geyser.entity.type.FishingHookEntity; import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.entity.type.living.animal.ArmadilloEntity; import org.geysermc.geyser.entity.type.living.monster.WardenEntity; +import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundEntityEventPacket; +import java.util.Collections; import java.util.concurrent.ThreadLocalRandom; @Translator(packet = ClientboundEntityEventPacket.class) @@ -154,6 +160,16 @@ public class JavaEntityEventTranslator extends PacketTranslator getTotemOfUndying() { + return protocolVersion -> ItemData.builder() + .definition(Registries.ITEMS.forVersion(protocolVersion).getStoredItems().totem().getBedrockDefinition()) + .count(1).build(); + } + /** * See {@link #findOrCreateItem(GeyserSession, String)}. This is for finding a specified {@link ItemStack}. * From efc8ba061028a2c67ea7120079fa8ce8c42ea701 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 15 Jul 2024 01:31:03 +0200 Subject: [PATCH 3/3] Fix: Block place sounds on mod platforms (#4859) --- .../mod/mixin/server/BlockPlaceMixin.java | 79 +++++++++++++++++++ .../mod/src/main/resources/geyser.mixins.json | 1 + .../java/level/JavaBlockUpdateTranslator.java | 20 ++--- 3 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/BlockPlaceMixin.java diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/BlockPlaceMixin.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/BlockPlaceMixin.java new file mode 100644 index 000000000..98620588e --- /dev/null +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/BlockPlaceMixin.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.platform.mod.mixin.server; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.state.BlockState; +import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.data.SoundEvent; +import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.session.GeyserSession; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +@Mixin(BlockItem.class) +public class BlockPlaceMixin { + + @Inject(method = "place", locals = LocalCapture.CAPTURE_FAILSOFT, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;playSound(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/core/BlockPos;Lnet/minecraft/sounds/SoundEvent;Lnet/minecraft/sounds/SoundSource;FF)V")) + private void geyser$hijackPlaySound(BlockPlaceContext blockPlaceContext, CallbackInfoReturnable cir, BlockPlaceContext blockPlaceContext2, BlockState blockState, BlockPos blockPos, Level level, Player player, ItemStack itemStack, BlockState blockState2, SoundType soundType) { + if (player == null) { + return; + } + + GeyserSession session = GeyserImpl.getInstance().connectionByUuid(player.getUUID()); + if (session == null) { + return; + } + + Vector3f position = Vector3f.from( + blockPos.getX(), + blockPos.getY(), + blockPos.getZ() + ); + + LevelSoundEventPacket placeBlockSoundPacket = new LevelSoundEventPacket(); + placeBlockSoundPacket.setSound(SoundEvent.PLACE); + placeBlockSoundPacket.setPosition(position); + placeBlockSoundPacket.setBabySound(false); + placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(Block.BLOCK_STATE_REGISTRY.getId(blockState2))); + placeBlockSoundPacket.setIdentifier(":"); + session.sendUpstreamPacket(placeBlockSoundPacket); + session.setLastBlockPlacePosition(null); + session.setLastBlockPlaced(null); + } +} diff --git a/bootstrap/mod/src/main/resources/geyser.mixins.json b/bootstrap/mod/src/main/resources/geyser.mixins.json index 47b2f60f3..2576e1ce6 100644 --- a/bootstrap/mod/src/main/resources/geyser.mixins.json +++ b/bootstrap/mod/src/main/resources/geyser.mixins.json @@ -4,6 +4,7 @@ "package": "org.geysermc.geyser.platform.mod.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ + "server.BlockPlaceMixin", "server.ServerConnectionListenerMixin" ], "server": [ diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java index d89775662..6d5fbc113 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java @@ -28,8 +28,8 @@ package org.geysermc.geyser.translator.protocol.java.level; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; -import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; @@ -43,24 +43,27 @@ public class JavaBlockUpdateTranslator extends PacketTranslator