From 48ae28432e2e0015889844cc5c6d4001851966a8 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Mon, 2 Dec 2024 02:23:02 +0800 Subject: [PATCH] More changes - remove getPickItemComponents in WorldManager, separate additional and base component --- .../mod/world/GeyserModWorldManager.java | 72 ------------------- .../manager/GeyserSpigotWorldManager.java | 19 ----- .../living/animal/tameable/WolfEntity.java | 25 ++++--- .../geyser/inventory/AnvilContainer.java | 10 +-- .../geyser/inventory/GeyserItemStack.java | 58 ++++++++------- .../updater/AnvilInventoryUpdater.java | 37 ++++++---- .../java/org/geysermc/geyser/item/Items.java | 4 -- .../org/geysermc/geyser/item/type/Item.java | 28 ++++---- .../geyser/level/GeyserWorldManager.java | 20 ------ .../geysermc/geyser/level/WorldManager.java | 10 --- .../geyser/session/cache/TagCache.java | 6 +- .../session/cache/tags/GeyserHolderSet.java | 30 ++++++-- .../geyser/skin/FakeHeadProvider.java | 15 ++-- .../inventory/InventoryTranslator.java | 14 ++-- .../inventory/LecternInventoryTranslator.java | 7 +- .../inventory/LoomInventoryTranslator.java | 11 +-- .../inventory/PlayerInventoryTranslator.java | 9 +-- .../translator/item/ItemTranslator.java | 58 +++++++-------- .../bedrock/BedrockBookEditTranslator.java | 2 +- .../org/geysermc/geyser/util/BlockUtils.java | 5 +- .../org/geysermc/geyser/util/ItemUtils.java | 12 ---- 21 files changed, 176 insertions(+), 276 deletions(-) diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/world/GeyserModWorldManager.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/world/GeyserModWorldManager.java index f85b6e079..f791aab7a 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/world/GeyserModWorldManager.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/world/GeyserModWorldManager.java @@ -28,37 +28,24 @@ package org.geysermc.geyser.platform.mod.world; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.minecraft.SharedConstants; import net.minecraft.core.BlockPos; -import net.minecraft.core.RegistryAccess; -import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BannerBlockEntity; -import net.minecraft.world.level.block.entity.BannerPatternLayers; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.DecoratedPotBlockEntity; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunkSection; -import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.geyser.level.GeyserWorldManager; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.MinecraftKey; -import org.geysermc.mcprotocollib.protocol.data.game.Holder; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; -import java.util.HashMap; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; public class GeyserModWorldManager extends GeyserWorldManager { @@ -117,49 +104,6 @@ public class GeyserModWorldManager extends GeyserWorldManager { return GameMode.byId(server.getDefaultGameType().getId()); } - @NonNull - @Override - public CompletableFuture getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) { - CompletableFuture future = new CompletableFuture<>(); - server.execute(() -> { - ServerPlayer player = getPlayer(session); - if (player == null) { - future.complete(null); - return; - } - - BlockPos pos = new BlockPos(x, y, z); - // Don't create a new block entity if invalid - //noinspection resource - level() is just a getter - BlockEntity blockEntity = player.level().getChunkAt(pos).getBlockEntity(pos); - if (blockEntity instanceof BannerBlockEntity banner) { - // Potentially exposes other NBT data? But we need to get the NBT data for the banner patterns *and* - // the banner might have a custom name, both of which a Java client knows and caches - ItemStack itemStack = banner.getItem(); - - org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents components = - new org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents(new HashMap<>()); - - components.put(DataComponentType.DAMAGE, itemStack.getDamageValue()); - - Component customName = itemStack.getComponents().get(DataComponents.CUSTOM_NAME); - if (customName != null) { - components.put(DataComponentType.CUSTOM_NAME, toKyoriComponent(customName)); - } - - BannerPatternLayers pattern = itemStack.get(DataComponents.BANNER_PATTERNS); - if (pattern != null) { - components.put(DataComponentType.BANNER_PATTERNS, toPatternList(pattern)); - } - - future.complete(components); - return; - } - future.complete(null); - }); - return future; - } - @Override public void getDecoratedPotData(GeyserSession session, Vector3i pos, Consumer> apply) { server.execute(() -> { @@ -184,20 +128,4 @@ public class GeyserModWorldManager extends GeyserWorldManager { private ServerPlayer getPlayer(GeyserSession session) { return server.getPlayerList().getPlayer(session.getPlayerEntity().getUuid()); } - - private static net.kyori.adventure.text.Component toKyoriComponent(Component component) { - String json = Component.Serializer.toJson(component, RegistryAccess.EMPTY); - return GSON_SERIALIZER.deserializeOr(json, net.kyori.adventure.text.Component.empty()); - } - - private static List toPatternList(BannerPatternLayers patternLayers) { - return patternLayers.layers().stream() - .map(layer -> { - BannerPatternLayer.BannerPattern pattern = new BannerPatternLayer.BannerPattern( - MinecraftKey.key(layer.pattern().value().assetId().toString()), layer.pattern().value().translationKey() - ); - return new BannerPatternLayer(Holder.ofCustom(pattern), layer.color().getId()); - }) - .toList(); - } } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index 6588a22a3..54b5b9178 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -25,18 +25,14 @@ package org.geysermc.geyser.platform.spigot.world.manager; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.DecoratedPot; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.erosion.bukkit.BukkitUtils; -import org.geysermc.erosion.bukkit.PickBlockUtils; import org.geysermc.erosion.bukkit.SchedulerUtils; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.GameRule; @@ -44,7 +40,6 @@ import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.List; import java.util.Objects; @@ -128,20 +123,6 @@ public class GeyserSpigotWorldManager extends WorldManager { return GameMode.byId(Bukkit.getDefaultGameMode().ordinal()); } - @Override - public @NonNull CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) { - Player bukkitPlayer; - if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) { - return CompletableFuture.completedFuture(null); - } - CompletableFuture> future = new CompletableFuture<>(); - Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z); - // Paper 1.19.3 complains about async access otherwise. - // java.lang.IllegalStateException: Tile is null, asynchronous access? - SchedulerUtils.runTask(this.plugin, () -> future.complete(PickBlockUtils.pickBlock(block)), block); - return future.thenApply(RAW_TRANSFORMER); - } - public void getDecoratedPotData(GeyserSession session, Vector3i pos, Consumer> apply) { Player bukkitPlayer; if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java index f0b554ef9..67e5788c6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java @@ -38,6 +38,8 @@ import org.geysermc.geyser.item.enchantment.EnchantmentComponent; import org.geysermc.geyser.item.type.DyeItem; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.registry.JavaRegistries; +import org.geysermc.geyser.session.cache.tags.GeyserHolderSet; import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.InteractionResult; @@ -51,6 +53,8 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.Object import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import java.util.Collections; import java.util.Locale; @@ -58,7 +62,7 @@ import java.util.UUID; public class WolfEntity extends TameableEntity { private byte collarColor = 14; // Red - default - + private GeyserHolderSet repairableItems = null; private boolean isCurseOfBinding = false; public WolfEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { @@ -123,9 +127,11 @@ public class WolfEntity extends TameableEntity { } @Override - public void setChestplate(ItemStack stack) { - super.setChestplate(stack); - isCurseOfBinding = ItemUtils.hasEffect(session, stack, EnchantmentComponent.PREVENT_ARMOR_CHANGE); // TODO test + public void setBody(ItemStack stack) { + super.setBody(stack); + isCurseOfBinding = ItemUtils.hasEffect(session, stack, EnchantmentComponent.PREVENT_ARMOR_CHANGE); + HolderSet set = GeyserItemStack.from(stack).getComponent(DataComponentType.REPAIRABLE); + repairableItems = GeyserHolderSet.convertHolderSet(JavaRegistries.ITEM, set); } @Override @@ -152,16 +158,17 @@ public class WolfEntity extends TameableEntity { return super.testMobInteraction(hand, itemInHand); } } - if (itemInHand.asItem() == Items.WOLF_ARMOR && !this.chestplate.isValid() && !getFlag(EntityFlag.BABY)) { + if (itemInHand.asItem() == Items.WOLF_ARMOR && !this.body.isValid() && !getFlag(EntityFlag.BABY)) { return InteractiveTag.EQUIP_WOLF_ARMOR; } - if (itemInHand.asItem() == Items.SHEARS && this.chestplate.isValid() + if (itemInHand.asItem() == Items.SHEARS && this.body.isValid() && (!isCurseOfBinding || session.getGameMode().equals(GameMode.CREATIVE))) { return InteractiveTag.REMOVE_WOLF_ARMOR; } - if (Items.WOLF_ARMOR.isValidRepairItem(itemInHand.asItem()) && getFlag(EntityFlag.SITTING) && - this.chestplate.isValid() && this.chestplate.getTag() != null && - this.chestplate.getTag().getInt("Damage") > 0) { + if (getFlag(EntityFlag.SITTING) && + session.getTagCache().is(repairableItems, itemInHand.asItem()) && + this.body.isValid() && this.body.getTag() != null && + this.body.getTag().getInt("Damage") > 0) { return InteractiveTag.REPAIR_WOLF_ARMOR; } // Tamed and owned by player - can sit/stand diff --git a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java index 45a062468..f5969efbb 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java @@ -25,15 +25,15 @@ package org.geysermc.geyser.inventory; -import net.kyori.adventure.text.Component; -import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; import lombok.Getter; import lombok.Setter; +import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.geyser.util.ItemUtils; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; /** * Used to determine if rename packets should be sent and stores @@ -73,7 +73,7 @@ public class AnvilContainer extends Container { String correctRename; newName = rename; - Component originalName = ItemUtils.getCustomName(getInput().getComponents()); + Component originalName = getInput().getComponent(DataComponentType.CUSTOM_NAME); String plainOriginalName = MessageTranslator.convertToPlainText(originalName, session.locale()); String plainNewName = MessageTranslator.convertToPlainText(rename); diff --git a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java index 256de7799..c595ea1b5 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -25,7 +25,11 @@ package org.geysermc.geyser.inventory; -import lombok.*; +import lombok.AccessLevel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; @@ -104,10 +108,27 @@ public class GeyserItemStack { return isEmpty() ? 0 : amount; } + /** + * Returns all components of this item - base and additional components sent over the network. + * These are NOT modifiable! To add components, use {@link #getOrCreateComponents()}. + * + * @return the item's base data components and the "additional" ones that may exist. + */ + public @Nullable DataComponents getAllComponents() { + return isEmpty() ? null : asItem().gatherComponents(components); + } + + /** + * @return the {@link DataComponents} that aren't the base/default components. + */ public @Nullable DataComponents getComponents() { return isEmpty() ? null : components; } + public boolean hasNonBaseComponents() { + return components != null; + } + @NonNull public DataComponents getOrCreateComponents() { if (components == null) { @@ -119,33 +140,20 @@ public class GeyserItemStack { @Nullable public T getComponent(@NonNull DataComponentType type) { if (components == null) { - return null; + return asItem().getComponent(type); } - return components.get(type); + + T value = components.get(type); + if (value == null) { + return asItem().getComponent(type); + } + + return value; } - public boolean getComponent(@NonNull DataComponentType type, boolean def) { - if (components == null) { - return def; - } - - Boolean result = components.get(type); - if (result != null) { - return result; - } - return def; - } - - public int getComponent(@NonNull DataComponentType type, int def) { - if (components == null) { - return def; - } - - Integer result = components.get(type); - if (result != null) { - return result; - } - return def; + public T getComponentOrFallback(@NonNull DataComponentType type, T def) { + T value = getComponent(type); + return value == null ? def : value; } public int getNetId() { diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java index 00270e47a..459d8adf8 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java @@ -40,12 +40,15 @@ import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.enchantment.Enchantment; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.registry.JavaRegistries; +import org.geysermc.geyser.session.cache.tags.GeyserHolderSet; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.geyser.util.ItemUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; @@ -63,7 +66,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { super.updateInventory(translator, session, inventory); AnvilContainer anvilContainer = (AnvilContainer) inventory; updateInventoryState(session, anvilContainer); - int targetSlot = getTargetSlot(anvilContainer); + int targetSlot = getTargetSlot(anvilContainer, session); for (int i = 0; i < translator.size; i++) { final int bedrockSlot = translator.javaSlotToBedrock(i); if (bedrockSlot == 50) @@ -88,7 +91,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { updateInventoryState(session, anvilContainer); int lastTargetSlot = anvilContainer.getLastTargetSlot(); - int targetSlot = getTargetSlot(anvilContainer); + int targetSlot = getTargetSlot(anvilContainer, session); if (targetSlot != javaSlot) { // Update the requested slot InventorySlotPacket slotPacket = new InventorySlotPacket(); @@ -117,7 +120,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { // Changing the item in the input slot resets the name field on Bedrock, but // does not result in a FilterTextPacket - String originalName = MessageTranslator.convertToPlainText(ItemUtils.getCustomName(input.getComponents()), session.locale()); + String originalName = MessageTranslator.convertToPlainText(input.getComponent(DataComponentType.CUSTOM_NAME), session.locale()); ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(originalName); session.sendDownstreamGamePacket(renameItemPacket); @@ -135,12 +138,12 @@ public class AnvilInventoryUpdater extends InventoryUpdater { * @param anvilContainer the anvil inventory * @return the slot to change the repair cost */ - private int getTargetSlot(AnvilContainer anvilContainer) { + private int getTargetSlot(AnvilContainer anvilContainer, GeyserSession session) { GeyserItemStack input = anvilContainer.getInput(); GeyserItemStack material = anvilContainer.getMaterial(); if (!material.isEmpty()) { - if (!input.isEmpty() && isRepairing(input, material)) { + if (!input.isEmpty() && isRepairing(input, material, session)) { // Changing the repair cost on the material item makes it non-stackable return 0; } @@ -233,7 +236,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { // Can't repair or merge enchantments return -1; } - } else if (hasDurability(input) && isRepairing(input, material)) { + } else if (hasDurability(input) && isRepairing(input, material, session)) { cost = calcRepairLevelCost(input, material); if (cost == -1) { // No damage to repair @@ -394,8 +397,14 @@ public class AnvilInventoryUpdater extends InventoryUpdater { return isEnchantedBook(material) || (input.getJavaId() == material.getJavaId() && hasDurability(input)); } - private boolean isRepairing(GeyserItemStack input, GeyserItemStack material) { - return input.asItem().isValidRepairItem(material.asItem()); + private boolean isRepairing(GeyserItemStack input, GeyserItemStack material, GeyserSession session) { + HolderSet repairable = input.getComponent(DataComponentType.REPAIRABLE); + if (repairable == null) { + return false; + } + + GeyserHolderSet set = GeyserHolderSet.convertHolderSet(JavaRegistries.ITEM, repairable); + return session.getTagCache().is(set, material.asItem()); } private boolean isRenaming(GeyserSession session, AnvilContainer anvilContainer, boolean bedrock) { @@ -404,27 +413,27 @@ public class AnvilInventoryUpdater extends InventoryUpdater { } // This should really check the name field in all cases, but that requires the localized name // of the item which can change depending on NBT and Minecraft Edition - Component originalName = ItemUtils.getCustomName(anvilContainer.getInput().getComponents()); + Component originalName = anvilContainer.getInput().getComponent(DataComponentType.CUSTOM_NAME); if (bedrock && originalName != null && anvilContainer.getNewName() != null) { // Check text and formatting String legacyOriginalName = MessageTranslator.convertMessage(originalName, session.locale()); return !legacyOriginalName.equals(anvilContainer.getNewName()); } - return !Objects.equals(originalName, ItemUtils.getCustomName(anvilContainer.getResult().getComponents())); + return !Objects.equals(originalName, anvilContainer.getResult().getComponent(DataComponentType.CUSTOM_NAME)); } private int getRepairCost(GeyserItemStack itemStack) { - return itemStack.getComponent(DataComponentType.REPAIR_COST, 0); + return itemStack.getComponentOrFallback(DataComponentType.REPAIR_COST, 0); } private boolean hasDurability(GeyserItemStack itemStack) { if (itemStack.asItem().defaultMaxDamage() > 0) { - return itemStack.getComponent(DataComponentType.UNBREAKABLE, false); + return itemStack.getComponentOrFallback(DataComponentType.UNBREAKABLE, false); } return false; } private int getDamage(GeyserItemStack itemStack) { - return itemStack.getComponent(DataComponentType.DAMAGE, 0); + return itemStack.getComponentOrFallback(DataComponentType.DAMAGE, 0); } } diff --git a/core/src/main/java/org/geysermc/geyser/item/Items.java b/core/src/main/java/org/geysermc/geyser/item/Items.java index d2ae08ec4..4a2d5827a 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.item; -import org.geysermc.geyser.item.components.ToolTier; import org.geysermc.geyser.item.type.ArmorItem; import org.geysermc.geyser.item.type.ArrowItem; import org.geysermc.geyser.item.type.AxolotlBucketItem; @@ -45,16 +44,13 @@ import org.geysermc.geyser.item.type.FireworkStarItem; import org.geysermc.geyser.item.type.FishingRodItem; import org.geysermc.geyser.item.type.GoatHornItem; import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.item.type.LightItem; import org.geysermc.geyser.item.type.MaceItem; import org.geysermc.geyser.item.type.MapItem; -import org.geysermc.geyser.item.type.OminousBottleItem; import org.geysermc.geyser.item.type.PlayerHeadItem; import org.geysermc.geyser.item.type.PotionItem; import org.geysermc.geyser.item.type.ShieldItem; import org.geysermc.geyser.item.type.ShulkerBoxItem; import org.geysermc.geyser.item.type.SpawnEggItem; -import org.geysermc.geyser.item.type.TieredItem; import org.geysermc.geyser.item.type.TippedArrowItem; import org.geysermc.geyser.item.type.TropicalFishBucketItem; import org.geysermc.geyser.item.type.WolfArmorItem; diff --git a/core/src/main/java/org/geysermc/geyser/item/type/Item.java b/core/src/main/java/org/geysermc/geyser/item/type/Item.java index 7f0d9099e..c851ee332 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/Item.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/Item.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.item.type; +import com.google.common.collect.ImmutableMap; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; @@ -45,7 +46,6 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; -import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; @@ -98,16 +98,23 @@ public class Item { return Rarity.fromId(baseComponents.getOrDefault(DataComponentType.RARITY, 0)); } + /** + * Returns a modifiable DataComponents map. Should only be used when it must be modified. + * Otherwise, prefer using GeyserItemStack's getComponent + */ + @NonNull public DataComponents gatherComponents(DataComponents others) { - if (others == null) return baseComponents.clone(); - DataComponents components = baseComponents.clone(); + if (others == null) { + return new DataComponents(ImmutableMap.copyOf(components.getDataComponents())); + } components.getDataComponents().putAll(others.getDataComponents()); - return components; + return new DataComponents(ImmutableMap.copyOf(components.getDataComponents())); } - public boolean isValidRepairItem(Item other) { - return false; + @Nullable + public T getComponent(@NonNull DataComponentType type) { + return baseComponents.get(type); } public String translationKey() { @@ -121,14 +128,11 @@ public class Item { // Return, essentially, air return ItemData.builder(); } - ItemData.Builder builder = ItemData.builder() + + return ItemData.builder() .definition(mapping.getBedrockDefinition()) .damage(mapping.getBedrockData()) .count(count); - - ItemTranslator.translateCustomItem(components, builder, mapping); - - return builder; } public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { @@ -292,7 +296,7 @@ public class Item { } public static Builder builder() { - return new Builder().components(new DataComponents(new HashMap<>())); // TODO actually set components here + return new Builder().components(new DataComponents(ImmutableMap.of())); // TODO actually set components here } public static final class Builder { diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java index befcfa4b7..ca2ebcb08 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java @@ -25,20 +25,15 @@ package org.geysermc.geyser.level; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.erosion.packet.backendbound.BackendboundBatchBlockRequestPacket; import org.geysermc.erosion.packet.backendbound.BackendboundBlockRequestPacket; -import org.geysermc.erosion.packet.backendbound.BackendboundPickBlockPacket; import org.geysermc.erosion.util.BlockPositionIterator; import org.geysermc.geyser.erosion.ErosionCancellationException; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.concurrent.CompletableFuture; @@ -124,19 +119,4 @@ public class GeyserWorldManager extends WorldManager { public GameMode getDefaultGameMode(GeyserSession session) { return GameMode.SURVIVAL; } - - @NonNull - @Override - public CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) { - var erosionHandler = session.getErosionHandler().getAsActive(); - if (erosionHandler == null) { - return super.getPickItemComponents(session, x, y, z, addNbtData); - } else if (session.isClosed()) { - return CompletableFuture.failedFuture(new ErosionCancellationException()); - } - CompletableFuture> future = new CompletableFuture<>(); - erosionHandler.setPickBlockLookup(future); - erosionHandler.sendPacket(new BackendboundPickBlockPacket(Vector3i.from(x, y, z))); - return future.thenApply(RAW_TRANSFORMER); - } } diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index 6baf9c2b4..a85462108 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -192,16 +192,6 @@ public abstract class WorldManager { return null; } - /** - * Used for pick block, so we don't need to cache more data than necessary. - * - * @return expected NBT for this item. - */ - @NonNull - public CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addExtraData) { - return CompletableFuture.completedFuture(null); - } - /** * Retrieves decorated pot sherds from the server. Used to ensure the data is not erased on animation sent * through the BlockEntityDataPacket. diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java index 2b0f257a3..26b6aad96 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.session.cache; import it.unimi.dsi.fastutil.ints.IntArrays; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.kyori.adventure.key.Key; +import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.type.Item; @@ -119,7 +120,10 @@ public final class TagCache { /** * @return true if the specified network ID is in the given holder set. */ - public boolean is(GeyserHolderSet holderSet, T object) { + public boolean is(@Nullable GeyserHolderSet holderSet, @Nullable T object) { + if (holderSet == null || object == null) { + return false; + } return contains(holderSet.resolveRaw(this), holderSet.getRegistry().toNetworkId(session, object)); } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/tags/GeyserHolderSet.java b/core/src/main/java/org/geysermc/geyser/session/cache/tags/GeyserHolderSet.java index 3c6e02e53..0e0d117a4 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/tags/GeyserHolderSet.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/tags/GeyserHolderSet.java @@ -25,10 +25,6 @@ package org.geysermc.geyser.session.cache.tags; -import java.util.List; -import java.util.Objects; -import java.util.function.ToIntFunction; - import it.unimi.dsi.fastutil.ints.IntArrays; import lombok.Data; import net.kyori.adventure.key.Key; @@ -37,6 +33,11 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.TagCache; import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; + +import java.util.List; +import java.util.Objects; +import java.util.function.ToIntFunction; /** * Similar to vanilla Minecraft's HolderSets, stores either a tag or a list of IDs (this list can also be represented as a single ID in vanilla HolderSets). @@ -87,6 +88,27 @@ public final class GeyserHolderSet { return tagCache.getRaw(Objects.requireNonNull(tag, "HolderSet must have a tag if it doesn't have a list of IDs")); } + /** + * Reads a MCPL {@link HolderSet} and turns it into a GeyserHolderSet. + * @param registry the registry the HolderSet contains IDs from. + * @param holderSet the HolderSet as the MCPL HolderSet object + */ + public static GeyserHolderSet convertHolderSet(@NonNull JavaRegistryKey registry, @Nullable HolderSet holderSet) { + if (holderSet == null) { + return new GeyserHolderSet<>(registry, IntArrays.EMPTY_ARRAY); + } + + if (holderSet.getHolders() != null) { + return new GeyserHolderSet<>(registry, holderSet.getHolders()); + } + + if (holderSet.getLocation() != null) { + return new GeyserHolderSet<>(registry, new Tag<>(registry, holderSet.getLocation())); + } + + throw new IllegalStateException("HolderSet must have a tag or a list of IDs! " + holderSet); + } + /** * Reads a HolderSet from an object from NBT. * diff --git a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java index 22786a4ee..2434d6d91 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java @@ -25,10 +25,6 @@ package org.geysermc.geyser.skin; -import org.geysermc.mcprotocollib.auth.GameProfile; -import org.geysermc.mcprotocollib.auth.GameProfile.Texture; -import org.geysermc.mcprotocollib.auth.GameProfile.TextureModel; -import org.geysermc.mcprotocollib.auth.GameProfile.TextureType; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -36,6 +32,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.skin.Cape; import org.geysermc.geyser.api.skin.Skin; @@ -46,8 +43,10 @@ import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.skin.SkinManager.GameProfileData; import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; +import org.geysermc.mcprotocollib.auth.GameProfile; +import org.geysermc.mcprotocollib.auth.GameProfile.Texture; +import org.geysermc.mcprotocollib.auth.GameProfile.TextureModel; +import org.geysermc.mcprotocollib.auth.GameProfile.TextureType; import java.awt.*; import java.awt.image.BufferedImage; @@ -105,9 +104,7 @@ public class FakeHeadProvider { } }); - public static void setHead(GeyserSession session, PlayerEntity entity, DataComponents components) { - GameProfile profile = components.get(DataComponentType.PROFILE); - + public static void setHead(GeyserSession session, PlayerEntity entity, @Nullable GameProfile profile) { if (profile == null) { return; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java index 15c19c542..ffaae13d2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java @@ -76,7 +76,6 @@ import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.geyser.util.ItemUtils; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.EmptySlotDisplay; import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; @@ -252,8 +251,8 @@ public abstract class InventoryTranslator { //only set the head if the destination is the head slot GeyserItemStack javaItem = inventory.getItem(sourceSlot); if (javaItem.asItem() == Items.PLAYER_HEAD - && javaItem.getComponents() != null) { - FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponents()); + && javaItem.hasNonBaseComponents()) { + FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponent(DataComponentType.PROFILE)); } } else if (sourceSlot == 5) { //we are probably removing the head, so restore the original skin @@ -1020,12 +1019,9 @@ public abstract class InventoryTranslator { // As of 1.16.210: Bedrock needs confirmation on what the current item durability is. // If 0 is sent, then Bedrock thinks the item is not damaged int durability = 0; - DataComponents components = itemStack.getComponents(); - if (components != null) { - Integer damage = components.get(DataComponentType.DAMAGE); - if (damage != null) { - durability = ItemUtils.getCorrectBedrockDurability(itemStack.asItem(), damage); - } + Integer damage = itemStack.getComponent(DataComponentType.DAMAGE); + if (damage != null) { + durability = ItemUtils.getCorrectBedrockDurability(itemStack.asItem(), damage); } itemEntry = new ItemStackResponseSlot((byte) bedrockSlot, (byte) bedrockSlot, (byte) itemStack.getAmount(), itemStack.getNetId(), "", durability); 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..e72de744f 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,7 +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; @@ -158,13 +157,13 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator session.getLastInteractionBlockPosition() : inventory.getHolderPosition(); NbtMap blockEntityTag; - if (book.getComponents() != null) { + if (book.hasNonBaseComponents()) { int pages = 0; - WrittenBookContent writtenBookComponents = book.getComponents().get(DataComponentType.WRITTEN_BOOK_CONTENT); + WrittenBookContent writtenBookComponents = book.getComponent(DataComponentType.WRITTEN_BOOK_CONTENT); if (writtenBookComponents != null) { pages = writtenBookComponents.getPages().size(); } else { - WritableBookContent writableBookComponents = book.getComponents().get(DataComponentType.WRITABLE_BOOK_CONTENT); + WritableBookContent writableBookComponents = book.getComponent(DataComponentType.WRITABLE_BOOK_CONTENT); if (writableBookComponents != null) { pages = writableBookComponents.getPages().size(); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java index 0694e2ac6..7cdcbe8a9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java @@ -49,11 +49,9 @@ import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { @@ -156,16 +154,11 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { GeyserItemStack inputCopy = inventory.getItem(0).copy(1); inputCopy.setNetId(session.getNextItemNetId()); - // Add the pattern manually, for better item synchronization - if (inputCopy.getComponents() == null) { - inputCopy.setComponents(new DataComponents(new HashMap<>())); - } - BannerPatternLayer bannerPatternLayer = BannerItem.getJavaBannerPattern(session, pattern); // TODO if (bannerPatternLayer != null) { - List patternsList = inputCopy.getComponents().getOrDefault(DataComponentType.BANNER_PATTERNS, new ArrayList<>()); + List patternsList = inputCopy.getComponentOrFallback(DataComponentType.BANNER_PATTERNS, new ArrayList<>()); patternsList.add(bannerPatternLayer); - inputCopy.getComponents().put(DataComponentType.BANNER_PATTERNS, patternsList); + inputCopy.getOrCreateComponents().put(DataComponentType.BANNER_PATTERNS, patternsList); } // Set the new item as the output diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index 8fd365d7f..f08b90765 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -58,6 +58,7 @@ import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket; import java.util.Arrays; @@ -103,8 +104,8 @@ public class PlayerInventoryTranslator extends InventoryTranslator { contents[i - 5] = item.getItemData(session); if (i == 5 && item.asItem() == Items.PLAYER_HEAD && - item.getComponents() != null) { - FakeHeadProvider.setHead(session, session.getPlayerEntity(), item.getComponents()); + item.hasNonBaseComponents()) { + FakeHeadProvider.setHead(session, session.getPlayerEntity(), item.getComponent(DataComponentType.PROFILE)); } } armorContentPacket.setContents(Arrays.asList(contents)); @@ -147,8 +148,8 @@ public class PlayerInventoryTranslator extends InventoryTranslator { if (slot == 5) { // Check for custom skull if (javaItem.asItem() == Items.PLAYER_HEAD - && javaItem.getComponents() != null) { - FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponents()); + && javaItem.hasNonBaseComponents()) { + FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponent(DataComponentType.PROFILE)); } else { FakeHeadProvider.restoreOriginalSkin(session, session.getPlayerEntity()); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java index 062666f84..284296209 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java @@ -112,7 +112,7 @@ public final class ItemTranslator { NbtMap nbt = data.getTag(); if (nbt != null && !nbt.isEmpty()) { // translateToJava may have added components - DataComponents components = itemStack.getComponents() == null ? new DataComponents(new HashMap<>()) : itemStack.getComponents(); + DataComponents components = itemStack.getOrCreateComponents(); javaItem.translateNbtToJava(session, nbt, components, bedrockItem); if (!components.getDataComponents().isEmpty()) { itemStack.setComponents(components); @@ -193,7 +193,7 @@ public final class ItemTranslator { } if (bedrockItem.getJavaItem().equals(Items.PLAYER_HEAD)) { - translatePlayerHead(session, components, builder); + translatePlayerHead(session, components.get(DataComponentType.PROFILE), builder); } translateCustomItem(components, builder, bedrockItem); @@ -391,7 +391,7 @@ public final class ItemTranslator { return ItemDefinition.AIR; } - ItemMapping mapping = itemStack.asItem().toBedrockDefinition(itemStack.getComponents(), session.getItemMappings()); + ItemMapping mapping = itemStack.asItem().toBedrockDefinition(itemStack.getAllComponents(), session.getItemMappings()); ItemDefinition itemDefinition = mapping.getBedrockDefinition(); CustomBlockData customBlockData = BlockRegistries.CUSTOM_BLOCK_ITEM_OVERRIDES.getOrDefault( @@ -401,7 +401,7 @@ public final class ItemTranslator { } if (mapping.getJavaItem().equals(Items.PLAYER_HEAD)) { - CustomSkull customSkull = getCustomSkull(itemStack.getComponents()); + CustomSkull customSkull = getCustomSkull(itemStack.getComponent(DataComponentType.PROFILE)); if (customSkull != null) { itemDefinition = session.getItemMappings().getCustomBlockItemDefinitions().get(customSkull.getCustomBlockData()); } @@ -466,39 +466,35 @@ public final class ItemTranslator { builder.blockDefinition(blockDefinition); } - private static @Nullable CustomSkull getCustomSkull(DataComponents components) { - if (components == null) { + private static @Nullable CustomSkull getCustomSkull(@Nullable GameProfile profile) { + if (profile == null) { return null; } - - GameProfile profile = components.get(DataComponentType.PROFILE); - if (profile != null) { - Map textures; - try { - textures = profile.getTextures(false); - } catch (IllegalStateException e) { - GeyserImpl.getInstance().getLogger().debug("Could not decode player head from profile %s, got: %s".formatted(profile, e.getMessage())); - return null; - } - if (textures == null || textures.isEmpty()) { - return null; - } - - Texture skinTexture = textures.get(TextureType.SKIN); - - if (skinTexture == null) { - return null; - } - - String skinHash = skinTexture.getURL().substring(skinTexture.getURL().lastIndexOf('/') + 1); - return BlockRegistries.CUSTOM_SKULLS.get(skinHash); + Map textures; + try { + textures = profile.getTextures(false); + } catch (IllegalStateException e) { + GeyserImpl.getInstance().getLogger().debug("Could not decode player head from profile %s, got: %s".formatted(profile, e.getMessage())); + return null; } - return null; + + if (textures == null || textures.isEmpty()) { + return null; + } + + Texture skinTexture = textures.get(TextureType.SKIN); + + if (skinTexture == null) { + return null; + } + + String skinHash = skinTexture.getURL().substring(skinTexture.getURL().lastIndexOf('/') + 1); + return BlockRegistries.CUSTOM_SKULLS.get(skinHash); } - private static void translatePlayerHead(GeyserSession session, DataComponents components, ItemData.Builder builder) { - CustomSkull customSkull = getCustomSkull(components); + private static void translatePlayerHead(GeyserSession session, GameProfile profile, ItemData.Builder builder) { + CustomSkull customSkull = getCustomSkull(profile); if (customSkull != null) { CustomBlockData customBlockData = customSkull.getCustomBlockData(); ItemDefinition itemDefinition = session.getItemMappings().getCustomBlockItemDefinitions().get(customBlockData); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java index 456b6507f..700ba0532 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java @@ -53,7 +53,7 @@ public class BedrockBookEditTranslator extends PacketTranslator GeyserItemStack itemStack = session.getPlayerInventory().getItemInHand(); if (itemStack != null) { - DataComponents components = itemStack.getComponents() != null ? itemStack.getComponents() : new DataComponents(new HashMap<>()); + DataComponents components = itemStack.getOrCreateComponents(); ItemStack bookItem = new ItemStack(itemStack.getJavaId(), itemStack.getAmount(), components); List pages = new LinkedList<>(); diff --git a/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java b/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java index 6367b2d14..1d84c169e 100644 --- a/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java @@ -131,6 +131,7 @@ public final class BlockUtils { return 1.0 / speed; } + // TODO 1.21.4 this changed probably; no more tiers public static double getBreakTime(GeyserSession session, Block block, ItemMapping item, @Nullable DataComponents components, boolean isSessionPlayer) { boolean isShearsEffective = session.getTagCache().is(BlockTag.LEAVES, block) || session.getTagCache().is(BlockTag.WOOL, block); //TODO called twice boolean canHarvestWithHand = !block.requiresCorrectToolForDrops(); @@ -160,7 +161,7 @@ public final class BlockUtils { boolean waterInEyes = session.getCollisionManager().isWaterInEyes(); boolean insideOfWaterWithoutAquaAffinity = waterInEyes && - ItemUtils.getEnchantmentLevel(session, session.getPlayerInventory().getItem(5).getComponents(), BedrockEnchantment.AQUA_AFFINITY) < 1; + ItemUtils.getEnchantmentLevel(session, session.getPlayerInventory().getItem(5).getAllComponents(), BedrockEnchantment.AQUA_AFFINITY) < 1; return calculateBreakTime(block.destroyTime(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, session.getPlayerEntity().isOnGround()); @@ -173,7 +174,7 @@ public final class BlockUtils { DataComponents components = null; if (item != null) { mapping = item.getMapping(session); - components = item.getComponents(); + components = item.getAllComponents(); } return getBreakTime(session, block, mapping, components, true); } diff --git a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java index eec0d173d..eca9756e6 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.util; -import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.item.Items; @@ -102,17 +101,6 @@ public final class ItemUtils { return original; } - /** - * @param components the data components of the item - * @return the custom name of the item - */ - public static @Nullable Component getCustomName(DataComponents components) { - if (components == null) { - return null; - } - return components.get(DataComponentType.CUSTOM_NAME); - } - private ItemUtils() { } }