From 49f31c96615805a592fc938ba04ab17c702c743f Mon Sep 17 00:00:00 2001 From: Eclipse <eclipse@eclipseisoffline.xyz> Date: Fri, 6 Dec 2024 10:17:48 +0000 Subject: [PATCH] Work on range dispatch predicate --- .../{data => }/ConditionPredicate.java | 5 +- .../v2/predicate/CustomItemPredicate.java | 2 +- ...cate.java => CustomModelDataProperty.java} | 4 +- .../{data/match => }/MatchPredicate.java | 4 +- .../v2/predicate/RangeDispatchPredicate.java | 37 +++++++++++++++ .../{data => }/match/ChargeType.java | 2 +- .../match/MatchPredicateProperty.java | 8 ++-- .../org/geysermc/geyser/item/type/Item.java | 2 +- .../geysermc/geyser/item/type/PotionItem.java | 2 +- .../geyser/item/type/ShulkerBoxItem.java | 2 +- .../mappings/versions/MappingsReader_v2.java | 14 +++--- .../translator/item/CustomItemTranslator.java | 47 +++++++++++++++---- .../translator/item/ItemTranslator.java | 8 ++-- .../player/input/BedrockBlockActions.java | 2 +- 14 files changed, 102 insertions(+), 37 deletions(-) rename api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/{data => }/ConditionPredicate.java (86%) rename api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/{data/CustomModelDataPredicate.java => CustomModelDataProperty.java} (90%) rename api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/{data/match => }/MatchPredicate.java (90%) create mode 100644 api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/RangeDispatchPredicate.java rename api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/{data => }/match/ChargeType.java (94%) rename api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/{data => }/match/MatchPredicateProperty.java (88%) diff --git a/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/data/ConditionPredicate.java b/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/ConditionPredicate.java similarity index 86% rename from api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/data/ConditionPredicate.java rename to api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/ConditionPredicate.java index 7ea71e3a8..8295777ea 100644 --- a/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/data/ConditionPredicate.java +++ b/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/ConditionPredicate.java @@ -23,11 +23,8 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.api.item.custom.v2.predicate.data; +package org.geysermc.geyser.api.item.custom.v2.predicate; -import org.geysermc.geyser.api.item.custom.v2.predicate.CustomItemPredicate; - -// TODO maybe type should be a generic class with data, but this works for now public record ConditionPredicate(ConditionProperty property, boolean expected, int index) implements CustomItemPredicate { // TODO maybe we can extend this diff --git a/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/CustomItemPredicate.java b/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/CustomItemPredicate.java index eab23e449..abb61efbe 100644 --- a/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/CustomItemPredicate.java +++ b/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/CustomItemPredicate.java @@ -25,5 +25,5 @@ package org.geysermc.geyser.api.item.custom.v2.predicate; -public interface CustomItemPredicate { // TODO this probably needs to be different since people can implement this +public sealed interface CustomItemPredicate permits ConditionPredicate, MatchPredicate, RangeDispatchPredicate { // TODO maybe we need to move the predicate classes out of API } diff --git a/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/data/CustomModelDataPredicate.java b/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/CustomModelDataProperty.java similarity index 90% rename from api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/data/CustomModelDataPredicate.java rename to api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/CustomModelDataProperty.java index 04646cc50..799a0d91f 100644 --- a/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/data/CustomModelDataPredicate.java +++ b/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/CustomModelDataProperty.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.api.item.custom.v2.predicate.data; +package org.geysermc.geyser.api.item.custom.v2.predicate; -public record CustomModelDataPredicate<T>(T data, int index) { +public record CustomModelDataProperty<T>(T data, int index) { } diff --git a/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/data/match/MatchPredicate.java b/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/MatchPredicate.java similarity index 90% rename from api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/data/match/MatchPredicate.java rename to api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/MatchPredicate.java index cbecc88f7..eca29d2e4 100644 --- a/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/data/match/MatchPredicate.java +++ b/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/MatchPredicate.java @@ -23,9 +23,9 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.api.item.custom.v2.predicate.data.match; +package org.geysermc.geyser.api.item.custom.v2.predicate; -import org.geysermc.geyser.api.item.custom.v2.predicate.CustomItemPredicate; +import org.geysermc.geyser.api.item.custom.v2.predicate.match.MatchPredicateProperty; public record MatchPredicate<T>(MatchPredicateProperty<T> property, T data) implements CustomItemPredicate { } diff --git a/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/RangeDispatchPredicate.java b/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/RangeDispatchPredicate.java new file mode 100644 index 000000000..1ecb4f618 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/RangeDispatchPredicate.java @@ -0,0 +1,37 @@ +/* + * 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.api.item.custom.v2.predicate; + +public record RangeDispatchPredicate(RangeDispatchProperty property, double threshold, double scale, boolean normalizeIfPossible, int index) implements CustomItemPredicate { + + // TODO check if we can change items while bedrock is using them, and if bedrock will continue to use them + public enum RangeDispatchProperty { + BUNDLE_FULLNESS, + DAMAGE, + COUNT, + CUSTOM_MODEL_DATA + } +} diff --git a/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/data/match/ChargeType.java b/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/match/ChargeType.java similarity index 94% rename from api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/data/match/ChargeType.java rename to api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/match/ChargeType.java index 438cee772..950ee128a 100644 --- a/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/data/match/ChargeType.java +++ b/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/match/ChargeType.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.api.item.custom.v2.predicate.data.match; +package org.geysermc.geyser.api.item.custom.v2.predicate.match; public enum ChargeType { NONE, diff --git a/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/data/match/MatchPredicateProperty.java b/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/match/MatchPredicateProperty.java similarity index 88% rename from api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/data/match/MatchPredicateProperty.java rename to api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/match/MatchPredicateProperty.java index a512ff3f7..b9f0ee3de 100644 --- a/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/data/match/MatchPredicateProperty.java +++ b/api/src/main/java/org/geysermc/geyser/api/item/custom/v2/predicate/match/MatchPredicateProperty.java @@ -23,10 +23,10 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.api.item.custom.v2.predicate.data.match; +package org.geysermc.geyser.api.item.custom.v2.predicate.match; import net.kyori.adventure.key.Key; -import org.geysermc.geyser.api.item.custom.v2.predicate.data.CustomModelDataPredicate; +import org.geysermc.geyser.api.item.custom.v2.predicate.CustomModelDataProperty; // TODO can we do more? public class MatchPredicateProperty<T> { @@ -34,7 +34,9 @@ public class MatchPredicateProperty<T> { public static final MatchPredicateProperty<ChargeType> CHARGE_TYPE = create(); public static final MatchPredicateProperty<Key> TRIM_MATERIAL = create(); public static final MatchPredicateProperty<Key> CONTEXT_DIMENSION = create(); - public static final MatchPredicateProperty<CustomModelDataPredicate<String>> CUSTOM_MODEL_DATA = create(); + public static final MatchPredicateProperty<CustomModelDataProperty<String>> CUSTOM_MODEL_DATA = create(); + + private MatchPredicateProperty() {} private static <T> MatchPredicateProperty<T> create() { return new MatchPredicateProperty<>(); 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 881012b98..d666f8818 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 @@ -125,7 +125,7 @@ public class Item { .damage(mapping.getBedrockData()) .count(count); - ItemTranslator.translateCustomItem(session, components, builder, mapping); + ItemTranslator.translateCustomItem(session, count, components, builder, mapping); return builder; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java b/core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java index 1cfbdd68d..03508262b 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java @@ -49,7 +49,7 @@ public class PotionItem extends Item { if (components == null) return super.translateToBedrock(session, count, components, mapping, mappings); PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); if (potionContents != null) { - ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(session, components, mapping); + ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(session, count, components, mapping); if (customItemDefinition == null) { Potion potion = Potion.getByJavaId(potionContents.getPotionId()); if (potion != null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java index f57733e71..2fca0fdca 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java @@ -74,7 +74,7 @@ public class ShulkerBoxItem extends BlockItem { if (boxComponents != null) { // Check for custom items - ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(session, boxComponents, boxMapping); + ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(session, item.getAmount(), boxComponents, boxMapping); if (customItemDefinition != null) { bedrockIdentifier = customItemDefinition.getIdentifier(); bedrockData = 0; diff --git a/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v2.java b/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v2.java index a90114273..40a711884 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v2.java +++ b/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v2.java @@ -35,11 +35,11 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.item.custom.v2.BedrockCreativeTab; import org.geysermc.geyser.api.item.custom.v2.CustomItemBedrockOptions; import org.geysermc.geyser.api.item.custom.v2.CustomItemDefinition; -import org.geysermc.geyser.api.item.custom.v2.predicate.data.ConditionPredicate; -import org.geysermc.geyser.api.item.custom.v2.predicate.data.CustomModelDataPredicate; -import org.geysermc.geyser.api.item.custom.v2.predicate.data.match.ChargeType; -import org.geysermc.geyser.api.item.custom.v2.predicate.data.match.MatchPredicate; -import org.geysermc.geyser.api.item.custom.v2.predicate.data.match.MatchPredicateProperty; +import org.geysermc.geyser.api.item.custom.v2.predicate.ConditionPredicate; +import org.geysermc.geyser.api.item.custom.v2.predicate.CustomModelDataProperty; +import org.geysermc.geyser.api.item.custom.v2.predicate.match.ChargeType; +import org.geysermc.geyser.api.item.custom.v2.predicate.MatchPredicate; +import org.geysermc.geyser.api.item.custom.v2.predicate.match.MatchPredicateProperty; import org.geysermc.geyser.item.exception.InvalidCustomMappingsFileException; import org.geysermc.geyser.registry.mappings.components.DataComponentReaders; import org.geysermc.geyser.registry.mappings.util.CustomBlockMapping; @@ -270,9 +270,9 @@ public class MappingsReader_v2 extends MappingsReader { case "custom_model_data" -> { JsonNode index = node.get("index"); if (index == null || !index.isIntegralNumber()) { - throw new InvalidCustomMappingsFileException("Predicate missing index key"); + throw new InvalidCustomMappingsFileException("Predicate missing index key"); // TODO default to 0 } - builder.predicate(new MatchPredicate<>(MatchPredicateProperty.CUSTOM_MODEL_DATA, new CustomModelDataPredicate<>(value.asText(), index.asInt()))); + builder.predicate(new MatchPredicate<>(MatchPredicateProperty.CUSTOM_MODEL_DATA, new CustomModelDataProperty<>(value.asText(), index.asInt()))); } default -> throw new InvalidCustomMappingsFileException("Unknown property " + property); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java index 87ea8f5b8..0e3d629c1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java @@ -30,10 +30,11 @@ import net.kyori.adventure.key.Key; import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; import org.geysermc.geyser.api.item.custom.v2.CustomItemDefinition; import org.geysermc.geyser.api.item.custom.v2.predicate.CustomItemPredicate; -import org.geysermc.geyser.api.item.custom.v2.predicate.data.ConditionPredicate; -import org.geysermc.geyser.api.item.custom.v2.predicate.data.match.ChargeType; -import org.geysermc.geyser.api.item.custom.v2.predicate.data.match.MatchPredicate; -import org.geysermc.geyser.api.item.custom.v2.predicate.data.match.MatchPredicateProperty; +import org.geysermc.geyser.api.item.custom.v2.predicate.ConditionPredicate; +import org.geysermc.geyser.api.item.custom.v2.predicate.RangeDispatchPredicate; +import org.geysermc.geyser.api.item.custom.v2.predicate.match.ChargeType; +import org.geysermc.geyser.api.item.custom.v2.predicate.MatchPredicate; +import org.geysermc.geyser.api.item.custom.v2.predicate.match.MatchPredicateProperty; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.session.GeyserSession; @@ -57,7 +58,7 @@ import java.util.List; public final class CustomItemTranslator { @Nullable - public static ItemDefinition getCustomItem(GeyserSession session, DataComponents components, ItemMapping mapping) { + public static ItemDefinition getCustomItem(GeyserSession session, int stackSize, DataComponents components, ItemMapping mapping) { if (components == null) { return null; } @@ -78,7 +79,7 @@ public final class CustomItemTranslator { if (customModel.first().model().equals(itemModel)) { boolean allMatch = true; for (CustomItemPredicate predicate : customModel.first().predicates()) { - if (!predicateMatches(session, predicate, components)) { + if (!predicateMatches(session, predicate, stackSize, components)) { allMatch = false; break; } @@ -91,7 +92,7 @@ public final class CustomItemTranslator { return null; } - private static boolean predicateMatches(GeyserSession session, CustomItemPredicate predicate, DataComponents components) { + private static boolean predicateMatches(GeyserSession session, CustomItemPredicate predicate, int stackSize, DataComponents components) { if (predicate instanceof ConditionPredicate condition) { return switch (condition.property()) { case BROKEN -> nextDamageWillBreak(components); @@ -124,18 +125,46 @@ public final class CustomItemTranslator { } else if (match.property() == MatchPredicateProperty.CONTEXT_DIMENSION) { Key dimension = (Key) match.data(); RegistryEntryData<JavaDimension> registered = session.getRegistryCache().dimensions().entryByValue(session.getDimensionType()); - return registered != null && dimension.equals(registered.key()); // TODO check if this works + return registered != null && dimension.equals(registered.key()); } else if (match.property() == MatchPredicateProperty.CUSTOM_MODEL_DATA) { // TODO 1.21.4 return false; } + } else if (predicate instanceof RangeDispatchPredicate rangeDispatch) { + double propertyValue = switch (rangeDispatch.property()) { + case BUNDLE_FULLNESS -> { + List<ItemStack> stacks = components.get(DataComponentType.BUNDLE_CONTENTS); + if (stacks == null) { + yield 0; + } + int bundleWeight = 0; + for (ItemStack stack : stacks) { + bundleWeight += stack.getAmount(); + } + yield bundleWeight; + } + case DAMAGE -> tryNormalize(rangeDispatch, components.get(DataComponentType.DAMAGE), components.get(DataComponentType.MAX_DAMAGE)); + case COUNT -> tryNormalize(rangeDispatch, stackSize, components.get(DataComponentType.MAX_STACK_SIZE)); + case CUSTOM_MODEL_DATA -> 0.0; // TODO 1.21.4 + } * rangeDispatch.scale(); + return propertyValue >= rangeDispatch.threshold(); } throw new IllegalStateException("Unimplemented predicate type"); } - /* These three functions are based off their Mojmap equivalents from 1.21.3 */ + private static double tryNormalize(RangeDispatchPredicate predicate, @Nullable Integer value, @Nullable Integer max) { + if (value == null) { + return 0.0; + } else if (max == null) { + return value; + } else if (!predicate.normalizeIfPossible()) { + return Math.min(value, max); + } + return Math.max(0.0, Math.min(1.0, (double) value / max)); + } + /* These three functions are based off their Mojmap equivalents from 1.21.3 */ private static boolean nextDamageWillBreak(DataComponents components) { return isDamageableItem(components) && components.getOrDefault(DataComponentType.DAMAGE, 0) >= components.getOrDefault(DataComponentType.MAX_DAMAGE, 0) - 1; } 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 5951eea2f..a927fedf3 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 @@ -215,7 +215,7 @@ public final class ItemTranslator { translatePlayerHead(session, components, builder); } - translateCustomItem(session, components, builder, bedrockItem); + translateCustomItem(session, count, components, builder, bedrockItem); if (components != null) { // Translate the canDestroy and canPlaceOn Java components @@ -428,7 +428,7 @@ public final class ItemTranslator { } } - ItemDefinition definition = CustomItemTranslator.getCustomItem(session, itemStack.getComponents(), mapping); + ItemDefinition definition = CustomItemTranslator.getCustomItem(session, itemStack.getAmount(), itemStack.getComponents(), mapping); if (definition == null) { // No custom item return itemDefinition; @@ -469,8 +469,8 @@ public final class ItemTranslator { /** * Translates the custom model data of an item */ - public static void translateCustomItem(GeyserSession session, DataComponents components, ItemData.Builder builder, ItemMapping mapping) { - ItemDefinition definition = CustomItemTranslator.getCustomItem(session, components, mapping); + public static void translateCustomItem(GeyserSession session, int stackSize, DataComponents components, ItemData.Builder builder, ItemMapping mapping) { + ItemDefinition definition = CustomItemTranslator.getCustomItem(session, stackSize, components, mapping); if (definition != null) { builder.definition(definition); builder.blockDefinition(null); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockBlockActions.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockBlockActions.java index 2d593dc09..e35679f80 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockBlockActions.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockBlockActions.java @@ -93,7 +93,7 @@ final class BedrockBlockActions { // If the block is custom or the breaking item is custom, we must keep track of break time ourselves GeyserItemStack item = session.getPlayerInventory().getItemInHand(); ItemMapping mapping = item.getMapping(session); - ItemDefinition customItem = mapping.isTool() ? CustomItemTranslator.getCustomItem(session, item.getComponents(), mapping) : null; + ItemDefinition customItem = mapping.isTool() ? CustomItemTranslator.getCustomItem(session, item.getAmount(), item.getComponents(), mapping) : null; CustomBlockState blockStateOverride = BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get(blockState); SkullCache.Skull skull = session.getSkullCache().getSkulls().get(vector);