diff --git a/patches/minecraft/net/minecraft/advancements/critereon/ItemPredicate.java.patch b/patches/minecraft/net/minecraft/advancements/critereon/ItemPredicate.java.patch index 88d98aaacf..dfcae00b2f 100644 --- a/patches/minecraft/net/minecraft/advancements/critereon/ItemPredicate.java.patch +++ b/patches/minecraft/net/minecraft/advancements/critereon/ItemPredicate.java.patch @@ -9,6 +9,15 @@ public static final ItemPredicate f_45028_ = new ItemPredicate(); @Nullable private final TagKey f_45029_; +@@ -80,7 +_,7 @@ + return false; + } else { + if (this.f_45033_.length > 0) { +- Map map = EnchantmentHelper.m_44882_(p_45050_.m_41785_()); ++ Map map = p_45050_.getAllEnchantments(); + + for(EnchantmentPredicate enchantmentpredicate : this.f_45033_) { + if (!enchantmentpredicate.m_30476_(map)) { @@ -107,6 +_,11 @@ public static ItemPredicate m_45051_(@Nullable JsonElement p_45052_) { if (p_45052_ != null && !p_45052_.isJsonNull()) { diff --git a/patches/minecraft/net/minecraft/world/inventory/GrindstoneMenu.java.patch b/patches/minecraft/net/minecraft/world/inventory/GrindstoneMenu.java.patch index 536abff41a..0d498a63db 100644 --- a/patches/minecraft/net/minecraft/world/inventory/GrindstoneMenu.java.patch +++ b/patches/minecraft/net/minecraft/world/inventory/GrindstoneMenu.java.patch @@ -19,3 +19,12 @@ if (!ItemStack.m_41728_(itemstack, itemstack1)) { this.f_39559_.m_6836_(0, ItemStack.f_41583_); this.m_38946_(); +@@ -175,7 +_,7 @@ + + for(Map.Entry entry : map.entrySet()) { + Enchantment enchantment = entry.getKey(); +- if (!enchantment.m_6589_() || EnchantmentHelper.m_44843_(enchantment, itemstack) == 0) { ++ if (!enchantment.m_6589_() || EnchantmentHelper.getTagEnchantmentLevel(enchantment, itemstack) == 0) { + itemstack.m_41663_(enchantment, entry.getValue()); + } + } diff --git a/patches/minecraft/net/minecraft/world/item/enchantment/EnchantmentHelper.java.patch b/patches/minecraft/net/minecraft/world/item/enchantment/EnchantmentHelper.java.patch index a7d017c796..161dd37007 100644 --- a/patches/minecraft/net/minecraft/world/item/enchantment/EnchantmentHelper.java.patch +++ b/patches/minecraft/net/minecraft/world/item/enchantment/EnchantmentHelper.java.patch @@ -1,5 +1,34 @@ --- a/net/minecraft/world/item/enchantment/EnchantmentHelper.java +++ b/net/minecraft/world/item/enchantment/EnchantmentHelper.java +@@ -59,7 +_,14 @@ + return Registry.f_122825_.m_7981_(p_182433_); + } + ++ /** @deprecated forge: use {@link #getTagEnchantmentLevel(Enchantment, ItemStack)} or {@link ItemStack#getEnchantmentLevel(Enchantment)} */ ++ @Deprecated + public static int m_44843_(Enchantment p_44844_, ItemStack p_44845_) { ++ return p_44845_.getEnchantmentLevel(p_44844_); ++ } ++ ++ /** Gets the enchantment level from NBT. Generally should use {@link ItemStack#getEnchantmentLevel(Enchantment)} for gameplay logic */ ++ public static int getTagEnchantmentLevel(Enchantment p_44844_, ItemStack p_44845_) { + if (p_44845_.m_41619_()) { + return 0; + } else { +@@ -120,6 +_,13 @@ + + private static void m_44850_(EnchantmentHelper.EnchantmentVisitor p_44851_, ItemStack p_44852_) { + if (!p_44852_.m_41619_()) { ++ if (true) { // forge: redirect enchantment logic to allow non-NBT enchants ++ for (Map.Entry entry : p_44852_.getAllEnchantments().entrySet()) { ++ p_44851_.m_44944_(entry.getKey(), entry.getValue()); ++ } ++ return; ++ } ++ + ListTag listtag = p_44852_.m_41785_(); + + for(int i = 0; i < listtag.size(); ++i) { @@ -150,7 +_,7 @@ public static float m_44833_(ItemStack p_44834_, MobType p_44835_) { MutableFloat mutablefloat = new MutableFloat(); diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeItem.java b/src/main/java/net/minecraftforge/common/extensions/IForgeItem.java index dbb1753aae..3c87909b5a 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeItem.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeItem.java @@ -6,6 +6,7 @@ package net.minecraftforge.common.extensions; import java.util.HashSet; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Consumer; @@ -16,6 +17,7 @@ import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.food.FoodProperties; import net.minecraft.world.item.*; import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import net.minecraft.world.level.block.Blocks; @@ -519,6 +521,35 @@ public interface IForgeItem return enchantment.category.canEnchant(stack.getItem()); } + /** + * Gets the level of the enchantment currently present on the stack. By default, returns the enchantment level present in NBT. + * Most enchantment implementations rely upon this method. + * For consistency, results of this method should be the same as getting the enchantment from {@link #getAllEnchantments(ItemStack)} + * + * @param stack the item stack being checked + * @param enchantment the enchantment being checked for + * @return Level of the enchantment, or 0 if not present + * @see #getAllEnchantments(ItemStack) + */ + default int getEnchantmentLevel(ItemStack stack, Enchantment enchantment) + { + return EnchantmentHelper.getTagEnchantmentLevel(enchantment, stack); + } + + /** + * Gets a map of all enchantments present on the stack. By default, returns the enchantments present in NBT. + * Used in several places in code including armor enchantment hooks. + * For consistency, any enchantments in the returned map should include the same level in {@link #getEnchantmentLevel(ItemStack, Enchantment)} + * + * @param stack the item stack being checked + * @return Map of all enchantments on the stack, empty if no enchantments are present + * @see #getEnchantmentLevel(ItemStack, Enchantment) + */ + default Map getAllEnchantments(ItemStack stack) + { + return EnchantmentHelper.deserializeEnchantments(stack.getEnchantmentTags()); + } + /** * Determine if the player switching between these two item stacks * diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeItemStack.java b/src/main/java/net/minecraftforge/common/extensions/IForgeItemStack.java index a2c91ff302..4104f18a4f 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeItemStack.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeItemStack.java @@ -35,6 +35,8 @@ import net.minecraftforge.common.capabilities.ICapabilitySerializable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Map; + /* * Extension added to ItemStack that bounces to ItemSack sensitive Item methods. Typically this is just for convince. */ @@ -158,6 +160,38 @@ public interface IForgeItemStack extends ICapabilitySerializable return self().getItem().canApplyAtEnchantingTable(self(), enchantment); } + /** + * Gets the level of the enchantment currently present on the stack. By default, returns the enchantment level present in NBT. + * + * Equivalent to calling {@link net.minecraft.world.item.enchantment.EnchantmentHelper#getItemEnchantmentLevel(Enchantment, ItemStack)} + * Use in place of {@link net.minecraft.world.item.enchantment.EnchantmentHelper#getTagEnchantmentLevel(Enchantment, ItemStack)} for checking presence of an enchantment in logic implementing the enchantment behavior. + * Use {@link net.minecraft.world.item.enchantment.EnchantmentHelper#getTagEnchantmentLevel(Enchantment, ItemStack)} instead when modifying an item's enchantments. + * + * @param enchantment the enchantment being checked for + * @return Level of the enchantment, or 0 if not present + * @see #getAllEnchantments() + * @see net.minecraft.world.item.enchantment.EnchantmentHelper#getTagEnchantmentLevel(Enchantment, ItemStack) + */ + default int getEnchantmentLevel(Enchantment enchantment) + { + return self().getItem().getEnchantmentLevel(self(), enchantment); + } + + /** + * Gets a map of all enchantments present on the stack. By default, returns the enchantments present in NBT, ignoring book enchantments. + * + * Use in place of {@link net.minecraft.world.item.enchantment.EnchantmentHelper#getEnchantments(ItemStack)} for checking presence of an enchantment in logic implementing the enchantment behavior. + * Use {@link net.minecraft.world.item.enchantment.EnchantmentHelper#getEnchantments(ItemStack)} instead when modifying an item's enchantments. + * + * @return Map of all enchantments on the stack, empty if no enchantments are present + * @see #getEnchantmentLevel(Enchantment) + * @see net.minecraft.world.item.enchantment.EnchantmentHelper#getEnchantments(ItemStack) + */ + default Map getAllEnchantments() + { + return self().getItem().getAllEnchantments(self()); + } + /** * ItemStack sensitive version of getItemEnchantability * diff --git a/src/main/resources/forge.exc b/src/main/resources/forge.exc index 1fe2169358..db79b23b57 100644 --- a/src/main/resources/forge.exc +++ b/src/main/resources/forge.exc @@ -56,6 +56,7 @@ net/minecraft/world/item/ItemStack.onItemUse(Lnet/minecraft/world/item/context/U net/minecraft/world/item/ItemStack.onItemUseFirst(Lnet/minecraft/world/item/context/UseOnContext;)Lnet/minecraft/world/InteractionResult;=|p_41662_ net/minecraft/world/item/MapItem.getCustomMapData(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/level/Level;)Lnet/minecraft/world/level/saveddata/maps/MapItemSavedData;=|p_42910_,p_42911_ net/minecraft/world/item/alchemy/PotionBrewing$Mix.(Lnet/minecraftforge/registries/IForgeRegistry;Ljava/lang/Object;Lnet/minecraft/world/item/crafting/Ingredient;Ljava/lang/Object;)V=|registry,p_43536_,p_43537_,p_43538_ +net/minecraft/world/item/enchantment/EnchantmentHelper.getTagEnchantmentLevel(Lnet/minecraft/world/item/enchantment/Enchantment;Lnet/minecraft/world/item/ItemStack;)I=|p_44844_,p_44845_ net/minecraft/world/item/crafting/RecipeManager.(Lnet/minecraftforge/common/crafting/conditions/ICondition$IContext;)V=|context net/minecraft/world/item/crafting/RecipeManager.fromJson(Lnet/minecraft/resources/ResourceLocation;Lcom/google/gson/JsonObject;Lnet/minecraftforge/common/crafting/conditions/ICondition$IContext;)Lnet/minecraft/world/item/crafting/Recipe;=|p_44046_,p_44047_,context net/minecraft/world/level/Level.markAndNotifyBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/chunk/LevelChunk;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;II)V=|p_46605_,levelchunk,blockstate,p_46606_,p_46607_,p_46608_ diff --git a/src/test/java/net/minecraftforge/debug/gameplay/loot/GlobalLootModifiersTest.java b/src/test/java/net/minecraftforge/debug/gameplay/loot/GlobalLootModifiersTest.java index dae7fc90b9..5daba5f1bb 100644 --- a/src/test/java/net/minecraftforge/debug/gameplay/loot/GlobalLootModifiersTest.java +++ b/src/test/java/net/minecraftforge/debug/gameplay/loot/GlobalLootModifiersTest.java @@ -177,7 +177,7 @@ public class GlobalLootModifiersTest { public ObjectArrayList doApply(ObjectArrayList generatedLoot, LootContext context) { ItemStack ctxTool = context.getParamOrNull(LootContextParams.TOOL); //return early if silk-touch is already applied (otherwise we'll get stuck in an infinite loop). - if(EnchantmentHelper.getEnchantments(ctxTool).containsKey(Enchantments.SILK_TOUCH)) return generatedLoot; + if(ctxTool == null || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, ctxTool) > 0) return generatedLoot; ItemStack fakeTool = ctxTool.copy(); fakeTool.enchant(Enchantments.SILK_TOUCH, 1); LootContext.Builder builder = new LootContext.Builder(context); diff --git a/src/test/resources/data/global_loot_test/loot_modifiers/silk_touch_bamboo.json b/src/test/resources/data/global_loot_test/loot_modifiers/silk_touch_bamboo.json index c21599966b..826cdeaac5 100644 --- a/src/test/resources/data/global_loot_test/loot_modifiers/silk_touch_bamboo.json +++ b/src/test/resources/data/global_loot_test/loot_modifiers/silk_touch_bamboo.json @@ -4,7 +4,7 @@ { "condition": "minecraft:match_tool", "predicate": { - "item": "minecraft:bamboo" + "items": [ "minecraft:bamboo" ] } } ]