Enchantment API ()

* Enchantment API

* Rework EnchantmentHelperMixin

* Fix build

* Fix build again
This commit is contained in:
Syst3ms 2024-04-10 20:35:19 +02:00 committed by GitHub
parent 973934d742
commit bcdd1296c3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 503 additions and 9 deletions

View file

@ -5,3 +5,7 @@ moduleDependencies(project, ['fabric-api-base'])
testDependencies(project, [
':fabric-content-registries-v0',
])
loom {
accessWidenerPath = file("src/main/resources/fabric-item-api-v1.accesswidener")
}

View file

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

View file

@ -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}.
*
* <p>This should only be used to modify the behavior of <em>external</em> items with regards to <em>external</em> 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.</p>
*
* <p>To modify the behavior of your own modded <em>enchantments</em>, use {@link Enchantment#isAcceptableItem(ItemStack)} instead.
* To modify the behavior of your own modded <em>items</em>, use {@link FabricItem#canBeEnchantedWith(ItemStack, Enchantment, EnchantingContext)} instead.
* Note that this event triggers <em>before</em> {@link FabricItem#canBeEnchantedWith(ItemStack, Enchantment, EnchantingContext)},
* and that method will only be called if no listeners override it.</p>
*
* <p>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.</p>
*
* @see AllowEnchanting#allowEnchanting(Enchantment, ItemStack, EnchantingContext)
* @see Enchantment#isAcceptableItem(ItemStack)
* @see FabricItem#canBeEnchantedWith(ItemStack, Enchantment, EnchantingContext)
*/
public static final Event<AllowEnchanting> 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
);
}
}

View file

@ -17,9 +17,12 @@
package net.fabricmc.fabric.api.item.v1;
import com.google.common.collect.Multimap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntMaps;
import org.jetbrains.annotations.Nullable;
import net.minecraft.block.BlockState;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.attribute.EntityAttribute;
import net.minecraft.entity.attribute.EntityAttributeModifier;
@ -135,4 +138,42 @@ public interface FabricItem {
default @Nullable FoodComponent getFoodComponent(ItemStack stack) {
return ((Item) this).getFoodComponent();
}
/**
* 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.
*
* <p>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.</p>
*
* <p>Note that this method is only called <em>after</em> the {@link EnchantmentEvents#ALLOW_ENCHANTING} event, and
* only if none of the listeners to that event override the result.</p>
*
* @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);
}
/**
* Returns a (stack-aware) map of <em>intrinsic enchantments</em> for this item.
* These enchantments have their usual gameplay effects, but do not produce glint or otherwise show on the item,
* and cannot be removed with a grindstone. For example, a mod that adds an electric multi-tool might want to give
* it a Silk Touch-like effect, without relying on the vanilla system.
*
* <p>By default, having an intrinsic enchantment does not prevent the item from being enchanted with the same one
* by normal means. In such a case, only the highest level of the enchantment will be retained. To prevent the item
* from receiving certain enchantments, use {@link #canBeEnchantedWith(ItemStack, Enchantment, EnchantingContext)}.</p>
*
* @param stack the current stack
* @return an immutable map from each intrinsic enchantment to its level
* @see #canBeEnchantedWith(ItemStack, Enchantment, EnchantingContext)
*/
default Object2IntMap<Enchantment> getIntrinsicEnchantments(ItemStack stack) {
return Object2IntMaps.emptyMap();
}
}

View file

@ -18,10 +18,13 @@ package net.fabricmc.fabric.api.item.v1;
import org.jetbrains.annotations.Nullable;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.item.FoodComponent;
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.
@ -49,4 +52,24 @@ public interface FabricItemStack {
default @Nullable FoodComponent getFoodComponent() {
return ((ItemStack) this).getItem().getFoodComponent(((ItemStack) this));
}
/**
* Determines whether this {@link ItemStack} can be enchanted with the given {@link Enchantment}.
*
* <p>When checking whether an enchantment can be applied to an {@link ItemStack}, use this method instead of
* {@link Enchantment#isAcceptableItem(ItemStack)}</p>
*
* @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));
}
}

View file

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

View file

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

View file

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

View file

@ -0,0 +1,66 @@
/*
* 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 java.util.Optional;
import java.util.function.Consumer;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import com.llamalad7.mixinextras.sugar.Local;
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.enchantment.EnchantmentTarget;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
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/EnchantmentTarget;isAcceptableItem(Lnet/minecraft/item/Item;)Z")
)
private static boolean useCustomEnchantingChecks(EnchantmentTarget target, Item item, int power, ItemStack stack, boolean treasureAllowed, @Local Enchantment enchantment) {
return stack.canBeEnchantedWith(enchantment, EnchantingContext.RANDOM_ENCHANTMENT);
}
@ModifyReturnValue(method = "getLevel", at = @At("RETURN"))
private static int getIntrinsicLevelIfPresent(int original, Enchantment ench, ItemStack stack) {
int intrinsicLevel = stack.getItem().getIntrinsicEnchantments(stack).getOrDefault(ench, 0);
return Math.max(original, intrinsicLevel);
}
@Redirect(
method = "forEachEnchantment(Lnet/minecraft/enchantment/EnchantmentHelper$Consumer;Lnet/minecraft/item/ItemStack;)V",
at = @At(value = "INVOKE", target = "Ljava/util/Optional;ifPresent(Ljava/util/function/Consumer;)V", remap = false)
)
private static void setCurrentStack(
Optional<Enchantment> instance, Consumer<? super Enchantment> action,
EnchantmentHelper.Consumer consumer, ItemStack stack, @Local NbtCompound compound
) {
instance.ifPresent(ench -> {
int intrinsicLevel = stack.getItem().getIntrinsicEnchantments(stack).getOrDefault(ench, 0);
consumer.accept(ench, Math.max(intrinsicLevel, EnchantmentHelper.getLevelFromNbt(compound)));
});
}
}

View file

@ -0,0 +1,44 @@
/*
* 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 java.util.Map;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.item.ItemStack;
import net.minecraft.predicate.item.EnchantmentPredicate;
import net.minecraft.predicate.item.ItemPredicate;
@Mixin(ItemPredicate.class)
abstract class ItemPredicateMixin {
@WrapOperation(
method = "test",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/predicate/item/EnchantmentPredicate;test(Ljava/util/Map;)Z",
ordinal = 0
)
)
private boolean checkForIntrinsicEnchantments(EnchantmentPredicate instance, Map<Enchantment, Integer> enchantments, Operation<Boolean> original, ItemStack stack) {
return original.call(instance, enchantments) || instance.test(stack.getItem().getIntrinsicEnchantments(stack));
}
}

View file

@ -0,0 +1,3 @@
accessWidener v2 named
accessible class net/minecraft/enchantment/EnchantmentHelper$Consumer

View file

@ -5,13 +5,18 @@
"mixins": [
"AbstractFurnaceBlockEntityMixin",
"ArmorItemMixin",
"AnvilScreenHandlerMixin",
"BlockItemMixin",
"BrewingStandBlockEntityMixin",
"CatEntityMixin",
"CookingRecipeJsonBuilderMixin",
"EnchantCommandMixin",
"EnchantmentHelperMixin",
"EnchantRandomlyLootFunctionMixin",
"FoxEntityMixin",
"HungerManagerMixin",
"ItemMixin",
"ItemPredicateMixin",
"ItemStackMixin",
"LivingEntityMixin",
"RecipeMixin",

View file

@ -22,6 +22,7 @@
"environment": "client"
}
],
"accessWidener": "fabric-item-api-v1.accesswidener",
"depends": {
"fabricloader": ">=0.15.1",
"fabric-api-base": "*"

View file

@ -16,8 +16,15 @@
package net.fabricmc.fabric.test.item;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntMaps;
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.nbt.NbtCompound;
@ -29,20 +36,14 @@ import net.minecraft.util.Identifier;
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.item.v1.FabricItemSettings;
import net.fabricmc.fabric.api.registry.FuelRegistry;
import net.fabricmc.fabric.api.util.TriState;
import net.fabricmc.fabric.test.item.mixin.BrewingRecipeRegistryAccessor;
public class CustomDamageTest implements ModInitializer {
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);
BrewingRecipeRegistryAccessor.callRegisterPotionRecipe(Potions.WATER, WEIRD_PICK, Potions.AWKWARD);
}
public static final CustomDamageHandler WEIRD_DAMAGE_HANDLER = (stack, amount, entity, 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()) {
@ -53,6 +54,26 @@ public class CustomDamageTest implements ModInitializer {
return 0;
}
};
// Declare damage handler before Item instance otherwise it will be null during init
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);
BrewingRecipeRegistryAccessor.callRegisterPotionRecipe(Potions.WATER, 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 final Object2IntMap<Enchantment> INTRINSIC_ENCHANTMENTS = Object2IntMaps.singleton(Enchantments.SILK_TOUCH, 1);
public static class WeirdPick extends PickaxeItem {
protected WeirdPick() {
@ -76,5 +97,20 @@ public class CustomDamageTest implements ModInitializer {
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);
}
@Override
public Object2IntMap<Enchantment> getIntrinsicEnchantments(ItemStack stack) {
if (stack.isDamaged()) {
return INTRINSIC_ENCHANTMENTS;
} else {
return super.getIntrinsicEnchantments(stack);
}
}
}
}

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"fabric-item-api-v1-testmod:weird_pickaxe"
]
}