From 8f5205a8a127f86c4938bce1a101f4c9f528dc42 Mon Sep 17 00:00:00 2001 From: Syst3ms Date: Thu, 11 Apr 2024 00:02:11 +0200 Subject: [PATCH] Enchantment API (#3627) * ALLOW_ENCHANTING event * Intrinsic enchantments + testmod also fixed a bug in the testmod that prevented the custom damage handler from ever working * Item-based override mechanism * Replaces part of the use cases of the event with a convenient method to override in FabricItem. * Updated and tested the testmod. * javadoc * Move event logic to FabricItemStack * oops * Simplify mixin * Replace ActionResult with TriState * Use TriState in testmod * requests * Clarify jdoc * Ship without intrinsic enchantments at first * Checkstyle * Checkstyle --------- Co-authored-by: modmuss50 --- .../fabric/api/item/v1/EnchantingContext.java | 55 ++++++++++++ .../fabric/api/item/v1/EnchantmentEvents.java | 84 +++++++++++++++++++ .../fabric/api/item/v1/FabricItem.java | 21 +++++ .../fabric/api/item/v1/FabricItemStack.java | 23 +++++ .../mixin/item/AnvilScreenHandlerMixin.java | 50 +++++++++++ .../mixin/item/EnchantCommandMixin.java | 38 +++++++++ .../EnchantRandomlyLootFunctionMixin.java | 38 +++++++++ .../mixin/item/EnchantmentHelperMixin.java | 38 +++++++++ .../resources/fabric-item-api-v1.mixins.json | 4 + .../fabric/test/item/CustomDamageTest.java | 42 +++++++--- .../data/minecraft/tags/items/pickaxes.json | 6 ++ .../object/builder/FabricEntityTypeTest.java | 5 +- 12 files changed, 390 insertions(+), 14 deletions(-) create mode 100644 fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EnchantingContext.java create mode 100644 fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EnchantmentEvents.java create mode 100644 fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/AnvilScreenHandlerMixin.java create mode 100644 fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/EnchantCommandMixin.java create mode 100644 fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/EnchantRandomlyLootFunctionMixin.java create mode 100644 fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/EnchantmentHelperMixin.java create mode 100644 fabric-item-api-v1/src/testmod/resources/data/minecraft/tags/items/pickaxes.json diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EnchantingContext.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EnchantingContext.java new file mode 100644 index 0000000000..8b55209893 --- /dev/null +++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EnchantingContext.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.item.v1; + +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.random.Random; + +/* + * There is one context for each vanilla call to Enchantment#isAcceptableItem. The reason why RANDOM_ENCHANTMENT + * feels like a kitchen sink is because it corresponds to the one in EnchantmentHelper, which is shared across multiple + * uses. + * + * This also gets in the way of adding further context (nullable Player and BlockPos have been suggested + * in the past). It's not impossible to do so, but a probably a bit more brittle. + */ +/** + * An enum that describes the various contexts in which the game checks whether an enchantment can be applied to an item. + */ +public enum EnchantingContext { + /** + * When generating a random enchantment for the item. This includes the enchanting table, random + * mob equipment, and the {@code enchant_with_levels} loot function. + * + * @see EnchantmentHelper#generateEnchantments(Random, ItemStack, int, boolean) + */ + RANDOM_ENCHANTMENT, + /** + * When trying to apply an enchantment in an anvil. + */ + ANVIL, + /** + * When using the {@code /enchant} command. + */ + ENCHANT_COMMAND, + /** + * When randomly enchanting an item using the {@code enchant_randomly} loot function without a list of enchantments + * to choose from. + */ + LOOT_RANDOM_ENCHANTMENT +} diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EnchantmentEvents.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EnchantmentEvents.java new file mode 100644 index 0000000000..5f624ff6ac --- /dev/null +++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EnchantmentEvents.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.item.v1; + +import net.minecraft.enchantment.Enchantment; +import net.minecraft.item.ItemStack; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.fabricmc.fabric.api.util.TriState; + +/** + * Events relating to enchantments, allowing for finer control of what enchantments can apply to different items. + */ +public final class EnchantmentEvents { + private EnchantmentEvents() { } + + /** + * An event that allows overriding whether an {@link Enchantment} can be applied to an {@link ItemStack}. + * + *

This should only be used to modify the behavior of external items with regards to external enchantments, + * where 'external' means either vanilla or from another mod. For instance, a mod might allow enchanting a pickaxe + * with Sharpness (and only Sharpness) under certain specific conditions.

+ * + *

To modify the behavior of your own modded enchantments, use {@link Enchantment#isAcceptableItem(ItemStack)} instead. + * To modify the behavior of your own modded items, use {@link FabricItem#canBeEnchantedWith(ItemStack, Enchantment, EnchantingContext)} instead. + * Note that this event triggers before {@link FabricItem#canBeEnchantedWith(ItemStack, Enchantment, EnchantingContext)}, + * and that method will only be called if no listeners override it.

+ * + *

Note that allowing an enchantment using this event does not guarantee the item will receive that enchantment, + * only that it isn't forbidden from doing so.

+ * + * @see AllowEnchanting#allowEnchanting(Enchantment, ItemStack, EnchantingContext) + * @see Enchantment#isAcceptableItem(ItemStack) + * @see FabricItem#canBeEnchantedWith(ItemStack, Enchantment, EnchantingContext) + */ + public static final Event ALLOW_ENCHANTING = EventFactory.createArrayBacked( + AllowEnchanting.class, + callbacks -> (enchantment, target, context) -> { + for (AllowEnchanting callback : callbacks) { + TriState result = callback.allowEnchanting(enchantment, target, context); + + if (result != TriState.DEFAULT) { + return result; + } + } + + return TriState.DEFAULT; + } + ); + + @FunctionalInterface + public interface AllowEnchanting { + /** + * Checks whether an {@link Enchantment} should be applied to a given {@link ItemStack}. + * + * @param enchantment the enchantment that may be applied + * @param target the target item + * @param enchantingContext the enchanting context in which this check is made + * @return {@link TriState#TRUE} if the enchantment may be applied, {@link TriState#FALSE} if it + * may not, {@link TriState#DEFAULT} to fall back to other callbacks/vanilla behavior + * @see EnchantingContext + */ + TriState allowEnchanting( + Enchantment enchantment, + ItemStack target, + EnchantingContext enchantingContext + ); + } +} diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItem.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItem.java index 8cb80e2e63..a029eb09f7 100644 --- a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItem.java +++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItem.java @@ -17,6 +17,7 @@ package net.fabricmc.fabric.api.item.v1; import net.minecraft.component.type.AttributeModifiersComponent; +import net.minecraft.enchantment.Enchantment; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -107,6 +108,26 @@ default ItemStack getRecipeRemainder(ItemStack stack) { return ((Item) this).hasRecipeRemainder() ? ((Item) this).getRecipeRemainder().getDefaultStack() : ItemStack.EMPTY; } + /** + * Determines if the item is allowed to receive an {@link Enchantment}. This can be used to manually override what + * enchantments a modded item is able to receive. + * + *

For example, one might want a modded item to be able to receive Unbreaking, but not Mending, which cannot be + * achieved with the vanilla tag system alone. Alternatively, one might want to do the same thing with enchantments + * from other mods, which don't have a similar tag system in general.

+ * + *

Note that this method is only called after the {@link EnchantmentEvents#ALLOW_ENCHANTING} event, and + * only if none of the listeners to that event override the result.

+ * + * @param stack the current stack + * @param enchantment the enchantment to check + * @param context the context in which the enchantment is being checked + * @return whether the enchantment is allowed to apply to the stack + */ + default boolean canBeEnchantedWith(ItemStack stack, Enchantment enchantment, EnchantingContext context) { + return enchantment.isAcceptableItem(stack); + } + /** * Fabric-provided extensions for {@link Item.Settings}. * This interface is automatically implemented on all item settings via Mixin and interface injection. diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItemStack.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItemStack.java index 0c646a6aad..50c3959a25 100644 --- a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItemStack.java +++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItemStack.java @@ -16,9 +16,12 @@ package net.fabricmc.fabric.api.item.v1; +import net.minecraft.enchantment.Enchantment; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.fabricmc.fabric.api.util.TriState; + /* * Fabric-provided extensions for {@link ItemStack}. * This interface is automatically implemented on all item stacks via Mixin and interface injection. @@ -36,4 +39,24 @@ public interface FabricItemStack { default ItemStack getRecipeRemainder() { return ((ItemStack) this).getItem().getRecipeRemainder((ItemStack) this); } + + /** + * Determines whether this {@link ItemStack} can be enchanted with the given {@link Enchantment}. + * + *

When checking whether an enchantment can be applied to an {@link ItemStack}, use this method instead of + * {@link Enchantment#isAcceptableItem(ItemStack)}

+ * + * @param enchantment the enchantment to check + * @param context the context in which the enchantment is being checked + * @return whether the enchantment is allowed to apply to the stack + * @see FabricItem#canBeEnchantedWith(ItemStack, Enchantment, EnchantingContext) + */ + default boolean canBeEnchantedWith(Enchantment enchantment, EnchantingContext context) { + TriState result = EnchantmentEvents.ALLOW_ENCHANTING.invoker().allowEnchanting( + enchantment, + (ItemStack) this, + context + ); + return result.orElseGet(() -> ((ItemStack) this).getItem().canBeEnchantedWith((ItemStack) this, enchantment, context)); + } } diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/AnvilScreenHandlerMixin.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/AnvilScreenHandlerMixin.java new file mode 100644 index 0000000000..15771f78ea --- /dev/null +++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/AnvilScreenHandlerMixin.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.item; + +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.minecraft.enchantment.Enchantment; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.AnvilScreenHandler; +import net.minecraft.screen.ForgingScreenHandler; +import net.minecraft.screen.ScreenHandlerContext; +import net.minecraft.screen.ScreenHandlerType; + +import net.fabricmc.fabric.api.item.v1.EnchantingContext; + +@Mixin(AnvilScreenHandler.class) +abstract class AnvilScreenHandlerMixin extends ForgingScreenHandler { + AnvilScreenHandlerMixin(@Nullable ScreenHandlerType type, int syncId, PlayerInventory playerInventory, ScreenHandlerContext context) { + super(type, syncId, playerInventory, context); + } + + @Redirect( + method = "updateResult", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/enchantment/Enchantment;isAcceptableItem(Lnet/minecraft/item/ItemStack;)Z" + ) + ) + private boolean callAllowEnchantingEvent(Enchantment instance, ItemStack stack) { + return stack.canBeEnchantedWith(instance, EnchantingContext.ANVIL); + } +} diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/EnchantCommandMixin.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/EnchantCommandMixin.java new file mode 100644 index 0000000000..2f945c282e --- /dev/null +++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/EnchantCommandMixin.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.item; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.minecraft.enchantment.Enchantment; +import net.minecraft.item.ItemStack; +import net.minecraft.server.command.EnchantCommand; + +import net.fabricmc.fabric.api.item.v1.EnchantingContext; + +@Mixin(EnchantCommand.class) +abstract class EnchantCommandMixin { + @Redirect( + method = "execute", + at = @At(value = "INVOKE", target = "Lnet/minecraft/enchantment/Enchantment;isAcceptableItem(Lnet/minecraft/item/ItemStack;)Z") + ) + private static boolean callAllowEnchantingEvent(Enchantment instance, ItemStack stack) { + return stack.canBeEnchantedWith(instance, EnchantingContext.ENCHANT_COMMAND); + } +} diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/EnchantRandomlyLootFunctionMixin.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/EnchantRandomlyLootFunctionMixin.java new file mode 100644 index 0000000000..d884bb01b3 --- /dev/null +++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/EnchantRandomlyLootFunctionMixin.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.item; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.minecraft.enchantment.Enchantment; +import net.minecraft.item.ItemStack; +import net.minecraft.loot.function.EnchantRandomlyLootFunction; + +import net.fabricmc.fabric.api.item.v1.EnchantingContext; + +@Mixin(EnchantRandomlyLootFunction.class) +abstract class EnchantRandomlyLootFunctionMixin { + @Redirect( + method = "method_53327", + at = @At(value = "INVOKE", target = "Lnet/minecraft/enchantment/Enchantment;isAcceptableItem(Lnet/minecraft/item/ItemStack;)Z") + ) + private static boolean callAllowEnchantingEvent(Enchantment instance, ItemStack stack) { + return stack.canBeEnchantedWith(instance, EnchantingContext.LOOT_RANDOM_ENCHANTMENT); + } +} diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/EnchantmentHelperMixin.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/EnchantmentHelperMixin.java new file mode 100644 index 0000000000..b06fe3284d --- /dev/null +++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/EnchantmentHelperMixin.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.item; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.item.ItemStack; + +import net.fabricmc.fabric.api.item.v1.EnchantingContext; + +@Mixin(EnchantmentHelper.class) +abstract class EnchantmentHelperMixin { + @Redirect( + method = "getPossibleEntries", + at = @At(value = "INVOKE", target = "Lnet/minecraft/enchantment/Enchantment;isAcceptableItem(Lnet/minecraft/item/ItemStack;)Z") + ) + private static boolean useCustomEnchantingChecks(Enchantment instance, ItemStack stack) { + return stack.canBeEnchantedWith(instance, EnchantingContext.RANDOM_ENCHANTMENT); + } +} diff --git a/fabric-item-api-v1/src/main/resources/fabric-item-api-v1.mixins.json b/fabric-item-api-v1/src/main/resources/fabric-item-api-v1.mixins.json index a56c7c35b2..0a0e6e667c 100644 --- a/fabric-item-api-v1/src/main/resources/fabric-item-api-v1.mixins.json +++ b/fabric-item-api-v1/src/main/resources/fabric-item-api-v1.mixins.json @@ -4,7 +4,11 @@ "compatibilityLevel": "JAVA_17", "mixins": [ "AbstractFurnaceBlockEntityMixin", + "AnvilScreenHandlerMixin", "BrewingStandBlockEntityMixin", + "EnchantCommandMixin", + "EnchantmentHelperMixin", + "EnchantRandomlyLootFunctionMixin", "ItemMixin", "ItemSettingsMixin", "ItemStackMixin", diff --git a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/CustomDamageTest.java b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/CustomDamageTest.java index 1db6a5253a..1b39db7f48 100644 --- a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/CustomDamageTest.java +++ b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/CustomDamageTest.java @@ -17,8 +17,12 @@ package net.fabricmc.fabric.test.item; import net.minecraft.component.DataComponentType; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.enchantment.Enchantments; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; import net.minecraft.item.PickaxeItem; import net.minecraft.item.ToolMaterials; import net.minecraft.network.codec.PacketCodecs; @@ -30,21 +34,14 @@ import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.item.v1.CustomDamageHandler; +import net.fabricmc.fabric.api.item.v1.EnchantingContext; +import net.fabricmc.fabric.api.item.v1.EnchantmentEvents; import net.fabricmc.fabric.api.registry.FuelRegistry; +import net.fabricmc.fabric.api.util.TriState; public class CustomDamageTest implements ModInitializer { - public static final Item WEIRD_PICK = new WeirdPick(); public static final DataComponentType WEIRD = Registry.register(Registries.DATA_COMPONENT_TYPE, new Identifier("fabric-item-api-v1-testmod", "weird"), DataComponentType.builder().codec(Codecs.NONNEGATIVE_INT).packetCodec(PacketCodecs.VAR_INT).build()); - - @Override - public void onInitialize() { - Registry.register(Registries.ITEM, new Identifier("fabric-item-api-v1-testmod", "weird_pickaxe"), WEIRD_PICK); - FuelRegistry.INSTANCE.add(WEIRD_PICK, 200); - // TODO 1.20.5 - // FabricBrewingRecipeRegistry.registerPotionRecipe(Potions.WATER, Ingredient.ofItems(WEIRD_PICK), Potions.AWKWARD); - } - public static final CustomDamageHandler WEIRD_DAMAGE_HANDLER = (stack, amount, entity, slot, breakCallback) -> { // If sneaking, apply all damage to vanilla. Otherwise, increment a tag on the stack by one and don't apply any damage if (entity.isSneaking()) { @@ -54,6 +51,25 @@ public void onInitialize() { return 0; } }; + // Do this static init *after* the damage handler otherwise it's still null while inside the constructor + public static final Item WEIRD_PICK = new WeirdPick(); + + @Override + public void onInitialize() { + Registry.register(Registries.ITEM, new Identifier("fabric-item-api-v1-testmod", "weird_pickaxe"), WEIRD_PICK); + FuelRegistry.INSTANCE.add(WEIRD_PICK, 200); + // TODO 1.20.5 + // FabricBrewingRecipeRegistry.registerPotionRecipe(Potions.WATER, Ingredient.ofItems(WEIRD_PICK), Potions.AWKWARD); + EnchantmentEvents.ALLOW_ENCHANTING.register(((enchantment, target, enchantingContext) -> { + if (target.isOf(Items.DIAMOND_PICKAXE) + && enchantment == Enchantments.SHARPNESS + && EnchantmentHelper.hasSilkTouch(target)) { + return TriState.TRUE; + } + + return TriState.DEFAULT; + })); + } public static class WeirdPick extends PickaxeItem { protected WeirdPick() { @@ -77,5 +93,11 @@ public ItemStack getRecipeRemainder(ItemStack stack) { return ItemStack.EMPTY; } + + @Override + public boolean canBeEnchantedWith(ItemStack stack, Enchantment enchantment, EnchantingContext context) { + return context == EnchantingContext.ANVIL && enchantment == Enchantments.FIRE_ASPECT + || enchantment != Enchantments.FORTUNE && super.canBeEnchantedWith(stack, enchantment, context); + } } } diff --git a/fabric-item-api-v1/src/testmod/resources/data/minecraft/tags/items/pickaxes.json b/fabric-item-api-v1/src/testmod/resources/data/minecraft/tags/items/pickaxes.json new file mode 100644 index 0000000000..ff5e7c4601 --- /dev/null +++ b/fabric-item-api-v1/src/testmod/resources/data/minecraft/tags/items/pickaxes.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "fabric-item-api-v1-testmod:weird_pickaxe" + ] +} \ No newline at end of file diff --git a/fabric-object-builder-api-v1/src/test/java/net/fabricmc/fabric/test/object/builder/FabricEntityTypeTest.java b/fabric-object-builder-api-v1/src/test/java/net/fabricmc/fabric/test/object/builder/FabricEntityTypeTest.java index 42f27a8f6b..511b820836 100644 --- a/fabric-object-builder-api-v1/src/test/java/net/fabricmc/fabric/test/object/builder/FabricEntityTypeTest.java +++ b/fabric-object-builder-api-v1/src/test/java/net/fabricmc/fabric/test/object/builder/FabricEntityTypeTest.java @@ -20,10 +20,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import net.minecraft.entity.SpawnLocation; - -import net.minecraft.entity.SpawnLocationTypes; - import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -33,6 +29,7 @@ import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.SpawnGroup; +import net.minecraft.entity.SpawnLocationTypes; import net.minecraft.entity.SpawnRestriction; import net.minecraft.entity.attribute.DefaultAttributeContainer; import net.minecraft.entity.attribute.DefaultAttributeRegistry;