Merge branch 'master' into master

This commit is contained in:
masel.io 2024-07-15 10:02:29 +02:00 committed by GitHub
commit 85c06b9404
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 306 additions and 87 deletions

View file

@ -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<InteractionResult> 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);
}
}

View file

@ -4,6 +4,7 @@
"package": "org.geysermc.geyser.platform.mod.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
"server.BlockPlaceMixin",
"server.ServerConnectionListenerMixin"
],
"server": [

View file

@ -49,7 +49,7 @@ public enum GeyserAttributeType {
ATTACK_KNOCKBACK("minecraft:generic.attack_knockback", null, 1.5f, Float.MAX_VALUE, 0f),
ATTACK_SPEED("minecraft:generic.attack_speed", null, 0f, 1024f, 4f),
MAX_HEALTH("minecraft:generic.max_health", null, 0f, 1024f, 20f),
SCALE("minecraft:generic.scale", null, 0.0625f, 16f, 1f), // Unused. Do we need this?
SCALE("minecraft:generic.scale", null, 0.0625f, 16f, 1f),
// Bedrock Attributes
ABSORPTION(null, "minecraft:absorption", 0f, 1024f, 0f),

View file

@ -48,6 +48,7 @@ import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.item.ItemTranslator;
import org.geysermc.geyser.util.AttributeUtils;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.MathUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.Attribute;
import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
@ -252,7 +253,7 @@ public class LivingEntity extends Entity {
}
private void setAttributeScale(float scale) {
this.attributeScale = scale;
this.attributeScale = MathUtils.clamp(scale, GeyserAttributeType.SCALE.getMinimum(), GeyserAttributeType.SCALE.getMaximum());
applyScale();
}

View file

@ -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!");

View file

@ -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);

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.item;
import org.geysermc.geyser.item.components.Rarity;
import org.geysermc.geyser.item.components.ToolTier;
import org.geysermc.geyser.item.type.*;
import org.geysermc.geyser.level.block.Blocks;
@ -122,7 +123,7 @@ public final class Items {
public static final Item RAW_IRON_BLOCK = register(new BlockItem(builder(), Blocks.RAW_IRON_BLOCK));
public static final Item RAW_COPPER_BLOCK = register(new BlockItem(builder(), Blocks.RAW_COPPER_BLOCK));
public static final Item RAW_GOLD_BLOCK = register(new BlockItem(builder(), Blocks.RAW_GOLD_BLOCK));
public static final Item HEAVY_CORE = register(new BlockItem(builder(), Blocks.HEAVY_CORE));
public static final Item HEAVY_CORE = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.HEAVY_CORE));
public static final Item AMETHYST_BLOCK = register(new BlockItem(builder(), Blocks.AMETHYST_BLOCK));
public static final Item BUDDING_AMETHYST = register(new BlockItem(builder(), Blocks.BUDDING_AMETHYST));
public static final Item IRON_BLOCK = register(new BlockItem(builder(), Blocks.IRON_BLOCK));
@ -416,7 +417,7 @@ public final class Items {
public static final Item END_PORTAL_FRAME = register(new BlockItem(builder(), Blocks.END_PORTAL_FRAME));
public static final Item END_STONE = register(new BlockItem(builder(), Blocks.END_STONE));
public static final Item END_STONE_BRICKS = register(new BlockItem(builder(), Blocks.END_STONE_BRICKS));
public static final Item DRAGON_EGG = register(new BlockItem(builder(), Blocks.DRAGON_EGG));
public static final Item DRAGON_EGG = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.DRAGON_EGG));
public static final Item SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.SANDSTONE_STAIRS));
public static final Item ENDER_CHEST = register(new BlockItem(builder(), Blocks.ENDER_CHEST));
public static final Item EMERALD_BLOCK = register(new BlockItem(builder(), Blocks.EMERALD_BLOCK));
@ -432,8 +433,8 @@ public final class Items {
public static final Item BAMBOO_MOSAIC_STAIRS = register(new BlockItem(builder(), Blocks.BAMBOO_MOSAIC_STAIRS));
public static final Item CRIMSON_STAIRS = register(new BlockItem(builder(), Blocks.CRIMSON_STAIRS));
public static final Item WARPED_STAIRS = register(new BlockItem(builder(), Blocks.WARPED_STAIRS));
public static final Item COMMAND_BLOCK = register(new BlockItem(builder(), Blocks.COMMAND_BLOCK));
public static final Item BEACON = register(new BlockItem(builder(), Blocks.BEACON));
public static final Item COMMAND_BLOCK = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.COMMAND_BLOCK));
public static final Item BEACON = register(new BlockItem(builder().rarity(Rarity.RARE), Blocks.BEACON));
public static final Item COBBLESTONE_WALL = register(new BlockItem(builder(), Blocks.COBBLESTONE_WALL));
public static final Item MOSSY_COBBLESTONE_WALL = register(new BlockItem(builder(), Blocks.MOSSY_COBBLESTONE_WALL));
public static final Item BRICK_WALL = register(new BlockItem(builder(), Blocks.BRICK_WALL));
@ -480,8 +481,8 @@ public final class Items {
public static final Item GREEN_TERRACOTTA = register(new BlockItem(builder(), Blocks.GREEN_TERRACOTTA));
public static final Item RED_TERRACOTTA = register(new BlockItem(builder(), Blocks.RED_TERRACOTTA));
public static final Item BLACK_TERRACOTTA = register(new BlockItem(builder(), Blocks.BLACK_TERRACOTTA));
public static final Item BARRIER = register(new BlockItem(builder(), Blocks.BARRIER));
public static final Item LIGHT = register(new BlockItem(builder(), Blocks.LIGHT));
public static final Item BARRIER = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.BARRIER));
public static final Item LIGHT = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.LIGHT));
public static final Item HAY_BLOCK = register(new BlockItem(builder(), Blocks.HAY_BLOCK));
public static final Item WHITE_CARPET = register(new BlockItem(builder(), Blocks.WHITE_CARPET));
public static final Item ORANGE_CARPET = register(new BlockItem(builder(), Blocks.ORANGE_CARPET));
@ -551,14 +552,14 @@ public final class Items {
public static final Item CHISELED_RED_SANDSTONE = register(new BlockItem(builder(), Blocks.CHISELED_RED_SANDSTONE));
public static final Item CUT_RED_SANDSTONE = register(new BlockItem(builder(), Blocks.CUT_RED_SANDSTONE));
public static final Item RED_SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.RED_SANDSTONE_STAIRS));
public static final Item REPEATING_COMMAND_BLOCK = register(new BlockItem(builder(), Blocks.REPEATING_COMMAND_BLOCK));
public static final Item CHAIN_COMMAND_BLOCK = register(new BlockItem(builder(), Blocks.CHAIN_COMMAND_BLOCK));
public static final Item REPEATING_COMMAND_BLOCK = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.REPEATING_COMMAND_BLOCK));
public static final Item CHAIN_COMMAND_BLOCK = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.CHAIN_COMMAND_BLOCK));
public static final Item MAGMA_BLOCK = register(new BlockItem(builder(), Blocks.MAGMA_BLOCK));
public static final Item NETHER_WART_BLOCK = register(new BlockItem(builder(), Blocks.NETHER_WART_BLOCK));
public static final Item WARPED_WART_BLOCK = register(new BlockItem(builder(), Blocks.WARPED_WART_BLOCK));
public static final Item RED_NETHER_BRICKS = register(new BlockItem(builder(), Blocks.RED_NETHER_BRICKS));
public static final Item BONE_BLOCK = register(new BlockItem(builder(), Blocks.BONE_BLOCK));
public static final Item STRUCTURE_VOID = register(new BlockItem(builder(), Blocks.STRUCTURE_VOID));
public static final Item STRUCTURE_VOID = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.STRUCTURE_VOID));
public static final Item SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.SHULKER_BOX));
public static final Item WHITE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.WHITE_SHULKER_BOX));
public static final Item ORANGE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.ORANGE_SHULKER_BOX));
@ -657,7 +658,7 @@ public final class Items {
public static final Item DEAD_FIRE_CORAL_FAN = register(new BlockItem(builder(), Blocks.DEAD_FIRE_CORAL_FAN, Blocks.DEAD_FIRE_CORAL_WALL_FAN));
public static final Item DEAD_HORN_CORAL_FAN = register(new BlockItem(builder(), Blocks.DEAD_HORN_CORAL_FAN, Blocks.DEAD_HORN_CORAL_WALL_FAN));
public static final Item BLUE_ICE = register(new BlockItem(builder(), Blocks.BLUE_ICE));
public static final Item CONDUIT = register(new BlockItem(builder(), Blocks.CONDUIT));
public static final Item CONDUIT = register(new BlockItem(builder().rarity(Rarity.RARE), Blocks.CONDUIT));
public static final Item POLISHED_GRANITE_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_GRANITE_STAIRS));
public static final Item SMOOTH_RED_SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.SMOOTH_RED_SANDSTONE_STAIRS));
public static final Item MOSSY_STONE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.MOSSY_STONE_BRICK_STAIRS));
@ -810,7 +811,7 @@ public final class Items {
public static final Item HOPPER_MINECART = register(new Item("hopper_minecart", builder().stackSize(1)));
public static final Item CARROT_ON_A_STICK = register(new Item("carrot_on_a_stick", builder().stackSize(1).maxDamage(25)));
public static final Item WARPED_FUNGUS_ON_A_STICK = register(new Item("warped_fungus_on_a_stick", builder().stackSize(1).maxDamage(100)));
public static final Item ELYTRA = register(new ElytraItem("elytra", builder().stackSize(1).maxDamage(432)));
public static final Item ELYTRA = register(new ElytraItem("elytra", builder().stackSize(1).maxDamage(432).rarity(Rarity.UNCOMMON)));
public static final Item OAK_BOAT = register(new BoatItem("oak_boat", builder().stackSize(1)));
public static final Item OAK_CHEST_BOAT = register(new BoatItem("oak_chest_boat", builder().stackSize(1)));
public static final Item SPRUCE_BOAT = register(new BoatItem("spruce_boat", builder().stackSize(1)));
@ -829,8 +830,8 @@ public final class Items {
public static final Item MANGROVE_CHEST_BOAT = register(new BoatItem("mangrove_chest_boat", builder().stackSize(1)));
public static final Item BAMBOO_RAFT = register(new BoatItem("bamboo_raft", builder().stackSize(1)));
public static final Item BAMBOO_CHEST_RAFT = register(new BoatItem("bamboo_chest_raft", builder().stackSize(1)));
public static final Item STRUCTURE_BLOCK = register(new BlockItem(builder(), Blocks.STRUCTURE_BLOCK));
public static final Item JIGSAW = register(new BlockItem(builder(), Blocks.JIGSAW));
public static final Item STRUCTURE_BLOCK = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.STRUCTURE_BLOCK));
public static final Item JIGSAW = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.JIGSAW));
public static final Item TURTLE_HELMET = register(new ArmorItem("turtle_helmet", ArmorMaterial.TURTLE, builder().stackSize(1).maxDamage(275)));
public static final Item TURTLE_SCUTE = register(new Item("turtle_scute", builder()));
public static final Item ARMADILLO_SCUTE = register(new Item("armadillo_scute", builder()));
@ -921,8 +922,8 @@ public final class Items {
public static final Item PORKCHOP = register(new Item("porkchop", builder()));
public static final Item COOKED_PORKCHOP = register(new Item("cooked_porkchop", builder()));
public static final Item PAINTING = register(new Item("painting", builder()));
public static final Item GOLDEN_APPLE = register(new Item("golden_apple", builder()));
public static final Item ENCHANTED_GOLDEN_APPLE = register(new Item("enchanted_golden_apple", builder()));
public static final Item GOLDEN_APPLE = register(new Item("golden_apple", builder().rarity(Rarity.RARE)));
public static final Item ENCHANTED_GOLDEN_APPLE = register(new Item("enchanted_golden_apple", builder().rarity(Rarity.EPIC)));
public static final Item OAK_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.OAK_SIGN, Blocks.OAK_WALL_SIGN));
public static final Item SPRUCE_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.SPRUCE_SIGN, Blocks.SPRUCE_WALL_SIGN));
public static final Item BIRCH_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.BIRCH_SIGN, Blocks.BIRCH_WALL_SIGN));
@ -1042,7 +1043,7 @@ public final class Items {
public static final Item BLAZE_POWDER = register(new Item("blaze_powder", builder()));
public static final Item MAGMA_CREAM = register(new Item("magma_cream", builder()));
public static final Item BREWING_STAND = register(new BlockItem(builder(), Blocks.BREWING_STAND));
public static final Item CAULDRON = register(new BlockItem(builder(), Blocks.CAULDRON, Blocks.WATER_CAULDRON, Blocks.LAVA_CAULDRON, Blocks.POWDER_SNOW_CAULDRON));
public static final Item CAULDRON = register(new BlockItem(builder(), Blocks.CAULDRON, Blocks.WATER_CAULDRON, Blocks.POWDER_SNOW_CAULDRON, Blocks.LAVA_CAULDRON));
public static final Item ENDER_EYE = register(new Item("ender_eye", builder()));
public static final Item GLISTERING_MELON_SLICE = register(new Item("glistering_melon_slice", builder()));
public static final Item ARMADILLO_SPAWN_EGG = register(new SpawnEggItem("armadillo_spawn_egg", builder()));
@ -1125,12 +1126,12 @@ public final class Items {
public static final Item ZOMBIE_HORSE_SPAWN_EGG = register(new SpawnEggItem("zombie_horse_spawn_egg", builder()));
public static final Item ZOMBIE_VILLAGER_SPAWN_EGG = register(new SpawnEggItem("zombie_villager_spawn_egg", builder()));
public static final Item ZOMBIFIED_PIGLIN_SPAWN_EGG = register(new SpawnEggItem("zombified_piglin_spawn_egg", builder()));
public static final Item EXPERIENCE_BOTTLE = register(new Item("experience_bottle", builder()));
public static final Item EXPERIENCE_BOTTLE = register(new Item("experience_bottle", builder().rarity(Rarity.UNCOMMON)));
public static final Item FIRE_CHARGE = register(new Item("fire_charge", builder()));
public static final Item WIND_CHARGE = register(new Item("wind_charge", builder()));
public static final Item WRITABLE_BOOK = register(new WritableBookItem("writable_book", builder().stackSize(1)));
public static final Item WRITTEN_BOOK = register(new WrittenBookItem("written_book", builder().stackSize(16)));
public static final Item MACE = register(new MaceItem("mace", builder().stackSize(1).maxDamage(500)));
public static final Item MACE = register(new MaceItem("mace", builder().stackSize(1).maxDamage(500).rarity(Rarity.EPIC)));
public static final Item ITEM_FRAME = register(new Item("item_frame", builder()));
public static final Item GLOW_ITEM_FRAME = register(new Item("glow_item_frame", builder()));
public static final Item FLOWER_POT = register(new BlockItem(builder(), Blocks.FLOWER_POT));
@ -1140,18 +1141,18 @@ public final class Items {
public static final Item POISONOUS_POTATO = register(new Item("poisonous_potato", builder()));
public static final Item MAP = register(new MapItem("map", builder()));
public static final Item GOLDEN_CARROT = register(new Item("golden_carrot", builder()));
public static final Item SKELETON_SKULL = register(new BlockItem(builder(), Blocks.SKELETON_SKULL, Blocks.SKELETON_WALL_SKULL));
public static final Item WITHER_SKELETON_SKULL = register(new BlockItem(builder(), Blocks.WITHER_SKELETON_SKULL, Blocks.WITHER_SKELETON_WALL_SKULL));
public static final Item PLAYER_HEAD = register(new PlayerHeadItem(builder(), Blocks.PLAYER_HEAD, Blocks.PLAYER_WALL_HEAD));
public static final Item ZOMBIE_HEAD = register(new BlockItem(builder(), Blocks.ZOMBIE_HEAD, Blocks.ZOMBIE_WALL_HEAD));
public static final Item CREEPER_HEAD = register(new BlockItem(builder(), Blocks.CREEPER_HEAD, Blocks.CREEPER_WALL_HEAD));
public static final Item DRAGON_HEAD = register(new BlockItem(builder(), Blocks.DRAGON_HEAD, Blocks.DRAGON_WALL_HEAD));
public static final Item PIGLIN_HEAD = register(new BlockItem(builder(), Blocks.PIGLIN_HEAD, Blocks.PIGLIN_WALL_HEAD));
public static final Item NETHER_STAR = register(new Item("nether_star", builder()));
public static final Item SKELETON_SKULL = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.SKELETON_SKULL, Blocks.SKELETON_WALL_SKULL));
public static final Item WITHER_SKELETON_SKULL = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.WITHER_SKELETON_SKULL, Blocks.WITHER_SKELETON_WALL_SKULL));
public static final Item PLAYER_HEAD = register(new PlayerHeadItem(builder().rarity(Rarity.UNCOMMON), Blocks.PLAYER_HEAD, Blocks.PLAYER_WALL_HEAD));
public static final Item ZOMBIE_HEAD = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.ZOMBIE_HEAD, Blocks.ZOMBIE_WALL_HEAD));
public static final Item CREEPER_HEAD = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.CREEPER_HEAD, Blocks.CREEPER_WALL_HEAD));
public static final Item DRAGON_HEAD = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.DRAGON_HEAD, Blocks.DRAGON_WALL_HEAD));
public static final Item PIGLIN_HEAD = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.PIGLIN_HEAD, Blocks.PIGLIN_WALL_HEAD));
public static final Item NETHER_STAR = register(new Item("nether_star", builder().rarity(Rarity.UNCOMMON)));
public static final Item PUMPKIN_PIE = register(new Item("pumpkin_pie", builder()));
public static final Item FIREWORK_ROCKET = register(new FireworkRocketItem("firework_rocket", builder()));
public static final Item FIREWORK_STAR = register(new FireworkStarItem("firework_star", builder()));
public static final Item ENCHANTED_BOOK = register(new EnchantedBookItem("enchanted_book", builder().stackSize(1)));
public static final Item ENCHANTED_BOOK = register(new EnchantedBookItem("enchanted_book", builder().stackSize(1).rarity(Rarity.UNCOMMON)));
public static final Item NETHER_BRICK = register(new Item("nether_brick", builder()));
public static final Item PRISMARINE_SHARD = register(new Item("prismarine_shard", builder()));
public static final Item PRISMARINE_CRYSTALS = register(new Item("prismarine_crystals", builder()));
@ -1167,7 +1168,7 @@ public final class Items {
public static final Item LEATHER_HORSE_ARMOR = register(new DyeableArmorItem("leather_horse_armor", ArmorMaterial.LEATHER, builder().stackSize(1)));
public static final Item LEAD = register(new Item("lead", builder()));
public static final Item NAME_TAG = register(new Item("name_tag", builder()));
public static final Item COMMAND_BLOCK_MINECART = register(new Item("command_block_minecart", builder().stackSize(1)));
public static final Item COMMAND_BLOCK_MINECART = register(new Item("command_block_minecart", builder().stackSize(1).rarity(Rarity.EPIC)));
public static final Item MUTTON = register(new Item("mutton", builder()));
public static final Item COOKED_MUTTON = register(new Item("cooked_mutton", builder()));
public static final Item WHITE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.WHITE_BANNER, Blocks.WHITE_WALL_BANNER));
@ -1186,7 +1187,7 @@ public final class Items {
public static final Item GREEN_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.GREEN_BANNER, Blocks.GREEN_WALL_BANNER));
public static final Item RED_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.RED_BANNER, Blocks.RED_WALL_BANNER));
public static final Item BLACK_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.BLACK_BANNER, Blocks.BLACK_WALL_BANNER));
public static final Item END_CRYSTAL = register(new Item("end_crystal", builder()));
public static final Item END_CRYSTAL = register(new Item("end_crystal", builder().rarity(Rarity.RARE)));
public static final Item CHORUS_FRUIT = register(new Item("chorus_fruit", builder()));
public static final Item POPPED_CHORUS_FRUIT = register(new Item("popped_chorus_fruit", builder()));
public static final Item TORCHFLOWER_SEEDS = register(new BlockItem("torchflower_seeds", builder(), Blocks.TORCHFLOWER_CROP));
@ -1194,52 +1195,52 @@ public final class Items {
public static final Item BEETROOT = register(new Item("beetroot", builder()));
public static final Item BEETROOT_SEEDS = register(new BlockItem("beetroot_seeds", builder(), Blocks.BEETROOTS));
public static final Item BEETROOT_SOUP = register(new Item("beetroot_soup", builder().stackSize(1)));
public static final Item DRAGON_BREATH = register(new Item("dragon_breath", builder()));
public static final Item DRAGON_BREATH = register(new Item("dragon_breath", builder().rarity(Rarity.UNCOMMON)));
public static final Item SPLASH_POTION = register(new PotionItem("splash_potion", builder().stackSize(1)));
public static final Item SPECTRAL_ARROW = register(new Item("spectral_arrow", builder()));
public static final Item TIPPED_ARROW = register(new TippedArrowItem("tipped_arrow", builder()));
public static final Item LINGERING_POTION = register(new PotionItem("lingering_potion", builder().stackSize(1)));
public static final Item SHIELD = register(new ShieldItem("shield", builder().stackSize(1).maxDamage(336)));
public static final Item TOTEM_OF_UNDYING = register(new Item("totem_of_undying", builder().stackSize(1)));
public static final Item TOTEM_OF_UNDYING = register(new Item("totem_of_undying", builder().stackSize(1).rarity(Rarity.UNCOMMON)));
public static final Item SHULKER_SHELL = register(new Item("shulker_shell", builder()));
public static final Item IRON_NUGGET = register(new Item("iron_nugget", builder()));
public static final Item KNOWLEDGE_BOOK = register(new Item("knowledge_book", builder().stackSize(1)));
public static final Item DEBUG_STICK = register(new Item("debug_stick", builder().stackSize(1)));
public static final Item MUSIC_DISC_13 = register(new Item("music_disc_13", builder().stackSize(1)));
public static final Item MUSIC_DISC_CAT = register(new Item("music_disc_cat", builder().stackSize(1)));
public static final Item MUSIC_DISC_BLOCKS = register(new Item("music_disc_blocks", builder().stackSize(1)));
public static final Item MUSIC_DISC_CHIRP = register(new Item("music_disc_chirp", builder().stackSize(1)));
public static final Item MUSIC_DISC_CREATOR = register(new Item("music_disc_creator", builder().stackSize(1)));
public static final Item MUSIC_DISC_CREATOR_MUSIC_BOX = register(new Item("music_disc_creator_music_box", builder().stackSize(1)));
public static final Item MUSIC_DISC_FAR = register(new Item("music_disc_far", builder().stackSize(1)));
public static final Item MUSIC_DISC_MALL = register(new Item("music_disc_mall", builder().stackSize(1)));
public static final Item MUSIC_DISC_MELLOHI = register(new Item("music_disc_mellohi", builder().stackSize(1)));
public static final Item MUSIC_DISC_STAL = register(new Item("music_disc_stal", builder().stackSize(1)));
public static final Item MUSIC_DISC_STRAD = register(new Item("music_disc_strad", builder().stackSize(1)));
public static final Item MUSIC_DISC_WARD = register(new Item("music_disc_ward", builder().stackSize(1)));
public static final Item MUSIC_DISC_11 = register(new Item("music_disc_11", builder().stackSize(1)));
public static final Item MUSIC_DISC_WAIT = register(new Item("music_disc_wait", builder().stackSize(1)));
public static final Item MUSIC_DISC_OTHERSIDE = register(new Item("music_disc_otherside", builder().stackSize(1)));
public static final Item MUSIC_DISC_RELIC = register(new Item("music_disc_relic", builder().stackSize(1)));
public static final Item MUSIC_DISC_5 = register(new Item("music_disc_5", builder().stackSize(1)));
public static final Item MUSIC_DISC_PIGSTEP = register(new Item("music_disc_pigstep", builder().stackSize(1)));
public static final Item MUSIC_DISC_PRECIPICE = register(new Item("music_disc_precipice", builder().stackSize(1)));
public static final Item KNOWLEDGE_BOOK = register(new Item("knowledge_book", builder().stackSize(1).rarity(Rarity.EPIC)));
public static final Item DEBUG_STICK = register(new Item("debug_stick", builder().stackSize(1).rarity(Rarity.EPIC).glint(true)));
public static final Item MUSIC_DISC_13 = register(new Item("music_disc_13", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_CAT = register(new Item("music_disc_cat", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_BLOCKS = register(new Item("music_disc_blocks", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_CHIRP = register(new Item("music_disc_chirp", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_CREATOR = register(new Item("music_disc_creator", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_CREATOR_MUSIC_BOX = register(new Item("music_disc_creator_music_box", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_FAR = register(new Item("music_disc_far", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_MALL = register(new Item("music_disc_mall", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_MELLOHI = register(new Item("music_disc_mellohi", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_STAL = register(new Item("music_disc_stal", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_STRAD = register(new Item("music_disc_strad", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_WARD = register(new Item("music_disc_ward", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_11 = register(new Item("music_disc_11", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_WAIT = register(new Item("music_disc_wait", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_OTHERSIDE = register(new Item("music_disc_otherside", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_RELIC = register(new Item("music_disc_relic", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_5 = register(new Item("music_disc_5", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_PIGSTEP = register(new Item("music_disc_pigstep", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item MUSIC_DISC_PRECIPICE = register(new Item("music_disc_precipice", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item DISC_FRAGMENT_5 = register(new Item("disc_fragment_5", builder()));
public static final Item TRIDENT = register(new Item("trident", builder().stackSize(1).maxDamage(250).attackDamage(9.0)));
public static final Item TRIDENT = register(new Item("trident", builder().stackSize(1).maxDamage(250).attackDamage(9.0).rarity(Rarity.EPIC)));
public static final Item PHANTOM_MEMBRANE = register(new Item("phantom_membrane", builder()));
public static final Item NAUTILUS_SHELL = register(new Item("nautilus_shell", builder()));
public static final Item HEART_OF_THE_SEA = register(new Item("heart_of_the_sea", builder()));
public static final Item HEART_OF_THE_SEA = register(new Item("heart_of_the_sea", builder().rarity(Rarity.UNCOMMON)));
public static final Item CROSSBOW = register(new CrossbowItem("crossbow", builder().stackSize(1).maxDamage(465)));
public static final Item SUSPICIOUS_STEW = register(new Item("suspicious_stew", builder().stackSize(1)));
public static final Item LOOM = register(new BlockItem(builder(), Blocks.LOOM));
public static final Item FLOWER_BANNER_PATTERN = register(new Item("flower_banner_pattern", builder().stackSize(1)));
public static final Item CREEPER_BANNER_PATTERN = register(new Item("creeper_banner_pattern", builder().stackSize(1)));
public static final Item SKULL_BANNER_PATTERN = register(new Item("skull_banner_pattern", builder().stackSize(1)));
public static final Item MOJANG_BANNER_PATTERN = register(new Item("mojang_banner_pattern", builder().stackSize(1)));
public static final Item CREEPER_BANNER_PATTERN = register(new Item("creeper_banner_pattern", builder().stackSize(1).rarity(Rarity.UNCOMMON)));
public static final Item SKULL_BANNER_PATTERN = register(new Item("skull_banner_pattern", builder().stackSize(1).rarity(Rarity.UNCOMMON)));
public static final Item MOJANG_BANNER_PATTERN = register(new Item("mojang_banner_pattern", builder().stackSize(1).rarity(Rarity.EPIC)));
public static final Item GLOBE_BANNER_PATTERN = register(new Item("globe_banner_pattern", builder().stackSize(1)));
public static final Item PIGLIN_BANNER_PATTERN = register(new Item("piglin_banner_pattern", builder().stackSize(1)));
public static final Item FLOW_BANNER_PATTERN = register(new Item("flow_banner_pattern", builder().stackSize(1)));
public static final Item GUSTER_BANNER_PATTERN = register(new Item("guster_banner_pattern", builder().stackSize(1)));
public static final Item PIGLIN_BANNER_PATTERN = register(new Item("piglin_banner_pattern", builder().stackSize(1).rarity(Rarity.UNCOMMON)));
public static final Item FLOW_BANNER_PATTERN = register(new Item("flow_banner_pattern", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item GUSTER_BANNER_PATTERN = register(new Item("guster_banner_pattern", builder().stackSize(1).rarity(Rarity.RARE)));
public static final Item GOAT_HORN = register(new GoatHornItem("goat_horn", builder().stackSize(1)));
public static final Item COMPOSTER = register(new BlockItem(builder(), Blocks.COMPOSTER));
public static final Item BARREL = register(new BlockItem(builder(), Blocks.BARREL));

View file

@ -0,0 +1,51 @@
/*
* 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.item.components;
import lombok.Getter;
@Getter
public enum Rarity {
COMMON("common", 'f'),
UNCOMMON("uncommon", 'e'),
RARE("rare", 'b'),
EPIC("epic", 'd');
private final String name;
private final char color;
Rarity(final String name, char chatColor) {
this.name = name;
this.color = chatColor;
}
private static final Rarity[] VALUES = values();
public static Rarity fromId(int id) {
return VALUES.length > id ? VALUES[id] : VALUES[0];
}
}

View file

@ -35,6 +35,7 @@ import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.item.BedrockEnchantment;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.components.Rarity;
import org.geysermc.geyser.item.enchantment.Enchantment;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.registry.type.ItemMapping;
@ -63,12 +64,16 @@ public class Item {
private final int stackSize;
private final int attackDamage;
private final int maxDamage;
private final Rarity rarity;
private final boolean glint;
public Item(String javaIdentifier, Builder builder) {
this.javaIdentifier = MinecraftKey.key(javaIdentifier).asString().intern();
this.stackSize = builder.stackSize;
this.maxDamage = builder.maxDamage;
this.attackDamage = builder.attackDamage;
this.rarity = builder.rarity;
this.glint = builder.glint;
}
public String javaIdentifier() {
@ -91,6 +96,14 @@ public class Item {
return stackSize;
}
public Rarity rarity() {
return rarity;
}
public boolean glint() {
return glint;
}
public boolean isValidRepairItem(Item other) {
return false;
}
@ -275,6 +288,8 @@ public class Item {
private int stackSize = 64;
private int maxDamage;
private int attackDamage;
private Rarity rarity = Rarity.COMMON;
private boolean glint = false;
public Builder stackSize(int stackSize) {
this.stackSize = stackSize;
@ -292,6 +307,16 @@ public class Item {
return this;
}
public Builder rarity(Rarity rarity) {
this.rarity = rarity;
return this;
}
public Builder glint(boolean glintOverride) {
this.glint = glintOverride;
return this;
}
private Builder() {
}
}

View file

@ -58,6 +58,8 @@ import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData;
import org.geysermc.geyser.inventory.item.StoredItemMappings;
import org.geysermc.geyser.item.GeyserCustomMappingData;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.components.Rarity;
import org.geysermc.geyser.item.type.BlockItem;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.Registries;
@ -399,9 +401,10 @@ public class ItemRegistryPopulator {
}
}
if (javaOnlyItems.contains(javaItem)) {
if (javaOnlyItems.contains(javaItem) || javaItem.rarity() != Rarity.COMMON) {
// These items don't exist on Bedrock, so set up a variable that indicates they should have custom names
mappingBuilder = mappingBuilder.translationString((bedrockBlock != null ? "block." : "item.") + entry.getKey().replace(":", "."));
// Or, ensure that we are translating these at all times to account for rarity colouring
mappingBuilder = mappingBuilder.translationString((javaItem instanceof BlockItem ? "block." : "item.") + entry.getKey().replace(":", "."));
GeyserImpl.getInstance().getLogger().debug("Adding " + entry.getKey() + " as an item that needs to be translated.");
}

View file

@ -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

View file

@ -33,7 +33,9 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
@ -41,6 +43,7 @@ import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.block.custom.CustomBlockData;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.components.Rarity;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.registry.BlockRegistries;
@ -145,7 +148,20 @@ public final class ItemTranslator {
if (components.get(DataComponentType.HIDE_TOOLTIP) != null) hideTooltips = true;
}
String customName = getCustomName(session, components, bedrockItem);
Rarity rarity = javaItem.rarity();
boolean enchantmentGlint = javaItem.glint();
if (components != null) {
Integer rarityIndex = components.get(DataComponentType.RARITY);
if (rarityIndex != null) {
rarity = Rarity.fromId(rarityIndex);
}
Boolean enchantmentGlintOverride = components.get(DataComponentType.ENCHANTMENT_GLINT_OVERRIDE);
if (enchantmentGlintOverride != null) {
enchantmentGlint = enchantmentGlintOverride;
}
}
String customName = getCustomName(session, components, bedrockItem, rarity.getColor());
if (customName != null) {
nbtBuilder.setCustomName(customName);
}
@ -162,6 +178,12 @@ public final class ItemTranslator {
addAdvancedTooltips(components, nbtBuilder, javaItem, session.locale());
}
// Add enchantment override. We can't remove it - enchantments would stop showing - but we can add it.
if (enchantmentGlint) {
NbtMapBuilder nbtMapBuilder = nbtBuilder.getOrCreateNbt();
nbtMapBuilder.putIfAbsent("ench", NbtList.EMPTY);
}
ItemData.Builder builder = javaItem.translateToBedrock(count, components, bedrockItem, session.getItemMappings());
// Finalize the Bedrock NBT
builder.tag(nbtBuilder.build());
@ -401,16 +423,6 @@ public final class ItemTranslator {
}
}
/**
* Translates the display name of the item
* @param session the Bedrock client's session
* @param components the components to translate
* @param mapping the item entry, in case it requires translation
*/
public static String getCustomName(GeyserSession session, DataComponents components, ItemMapping mapping) {
return getCustomName(session, components, mapping, 'f');
}
/**
* @param translationColor if this item is not available on Java, the color that the new name should be.
* Normally, this should just be white, but for shulker boxes this should be gray.

View file

@ -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<ClientboundEntit
entityEventPacket.setType(EntityEventType.WITCH_HAT_MAGIC); //TODO: CHECK
break;
case TOTEM_OF_UNDYING_MAKE_SOUND:
// Bedrock will not play the spinning animation without the item in the hand o.o
// Fixes https://github.com/GeyserMC/Geyser/issues/2446
boolean totemItemWorkaround = !session.getPlayerInventory().eitherHandMatchesItem(Items.TOTEM_OF_UNDYING);
if (totemItemWorkaround) {
InventoryContentPacket offhandPacket = new InventoryContentPacket();
offhandPacket.setContainerId(ContainerId.OFFHAND);
offhandPacket.setContents(Collections.singletonList(InventoryUtils.getTotemOfUndying().apply(session.getUpstream().getProtocolVersion())));
session.sendUpstreamPacket(offhandPacket);
}
entityEventPacket.setType(EntityEventType.CONSUME_TOTEM);
PlaySoundPacket playSoundPacket = new PlaySoundPacket();
@ -162,7 +178,16 @@ public class JavaEntityEventTranslator extends PacketTranslator<ClientboundEntit
playSoundPacket.setVolume(1.0F);
playSoundPacket.setPitch(1.0F + (ThreadLocalRandom.current().nextFloat() * 0.1F) - 0.05F);
session.sendUpstreamPacket(playSoundPacket);
break;
// Sent here early to ensure we have the totem in our hand
session.sendUpstreamPacket(entityEventPacket);
if (totemItemWorkaround) {
// Reset the item again
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, session.getPlayerInventory(), 45);
}
return;
case SHEEP_GRAZE_OR_TNT_CART_EXPLODE:
if (entity.getDefinition() == EntityDefinitions.SHEEP) {
entityEventPacket.setType(EntityEventType.EAT_GRASS);

View file

@ -70,6 +70,7 @@ public class JavaOpenBookTranslator extends PacketTranslator<ClientboundOpenBook
}
InventoryTranslator translator = InventoryTranslator.inventoryTranslator(ContainerType.LECTERN);
Objects.requireNonNull(translator, "could not find lectern inventory translator!");
session.setInventoryTranslator(translator);
// Should never be null

View file

@ -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<ClientboundBlock
@Override
public void translate(GeyserSession session, ClientboundBlockUpdatePacket packet) {
Vector3i pos = packet.getEntry().getPosition();
boolean updatePlacement = session.getGeyser().getPlatformType() != PlatformType.SPIGOT && // Spigot simply listens for the block place event
!session.getErosionHandler().isActive() && session.getGeyser().getWorldManager().getBlockAt(session, pos) != packet.getEntry().getBlock();
WorldManager worldManager = session.getGeyser().getWorldManager();
// Platforms where Geyser has direct server access don't allow us to detect actual block changes,
// hence why those platforms deal with sounds for block placements differently
boolean updatePlacement = !worldManager.hasOwnChunkCache() &&
!session.getErosionHandler().isActive() && worldManager.getBlockAt(session, pos) != packet.getEntry().getBlock();
session.getWorldCache().updateServerCorrectBlockState(pos, packet.getEntry().getBlock());
if (updatePlacement) {
this.checkPlace(session, packet);
this.checkPlaceSound(session, packet);
}
this.checkInteract(session, packet);
}
private boolean checkPlace(GeyserSession session, ClientboundBlockUpdatePacket packet) {
private void checkPlaceSound(GeyserSession session, ClientboundBlockUpdatePacket packet) {
Vector3i lastPlacePos = session.getLastBlockPlacePosition();
if (lastPlacePos == null) {
return false;
return;
}
if ((lastPlacePos.getX() != packet.getEntry().getPosition().getX()
|| lastPlacePos.getY() != packet.getEntry().getPosition().getY()
|| lastPlacePos.getZ() != packet.getEntry().getPosition().getZ())) {
return false;
return;
}
// We need to check if the identifier is the same, else a packet with the sound of what the
@ -74,7 +77,7 @@ public class JavaBlockUpdateTranslator extends PacketTranslator<ClientboundBlock
if (!contains) {
session.setLastBlockPlacePosition(null);
session.setLastBlockPlaced(null);
return false;
return;
}
// This is not sent from the server, so we need to send it this way
@ -87,7 +90,6 @@ public class JavaBlockUpdateTranslator extends PacketTranslator<ClientboundBlock
session.sendUpstreamPacket(placeBlockSoundPacket);
session.setLastBlockPlacePosition(null);
session.setLastBlockPlaced(null);
return true;
}
private void checkInteract(GeyserSession session, ClientboundBlockUpdatePacket packet) {

View file

@ -57,6 +57,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundPickItemPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket;
import org.jetbrains.annotations.Contract;
@ -91,7 +92,7 @@ public class InventoryUtils {
public static void displayInventory(GeyserSession session, Inventory inventory) {
InventoryTranslator translator = session.getInventoryTranslator();
if (translator != null && translator.prepareInventory(session, inventory)) {
if (translator.prepareInventory(session, inventory)) {
if (translator instanceof DoubleChestInventoryTranslator && !((Container) inventory).isUsingRealBlock()) {
session.scheduleInEventLoop(() -> {
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);
}
}
@ -248,6 +253,12 @@ public class InventoryUtils {
.count(1).build();
}
public static IntFunction<ItemData> 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}.
*