mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-08 21:14:41 -04:00
Enchantment API (#3641)
* Enchantment API * Rework EnchantmentHelperMixin * Fix build * Fix build again
This commit is contained in:
parent
973934d742
commit
bcdd1296c3
15 changed files with 503 additions and 9 deletions
fabric-item-api-v1
build.gradle
src
main
java/net/fabricmc/fabric
api/item/v1
mixin/item
resources
testmod
java/net/fabricmc/fabric/test/item
resources/data/minecraft/tags/items
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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)));
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
accessWidener v2 named
|
||||
|
||||
accessible class net/minecraft/enchantment/EnchantmentHelper$Consumer
|
|
@ -5,13 +5,18 @@
|
|||
"mixins": [
|
||||
"AbstractFurnaceBlockEntityMixin",
|
||||
"ArmorItemMixin",
|
||||
"AnvilScreenHandlerMixin",
|
||||
"BlockItemMixin",
|
||||
"BrewingStandBlockEntityMixin",
|
||||
"CatEntityMixin",
|
||||
"CookingRecipeJsonBuilderMixin",
|
||||
"EnchantCommandMixin",
|
||||
"EnchantmentHelperMixin",
|
||||
"EnchantRandomlyLootFunctionMixin",
|
||||
"FoxEntityMixin",
|
||||
"HungerManagerMixin",
|
||||
"ItemMixin",
|
||||
"ItemPredicateMixin",
|
||||
"ItemStackMixin",
|
||||
"LivingEntityMixin",
|
||||
"RecipeMixin",
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
"environment": "client"
|
||||
}
|
||||
],
|
||||
"accessWidener": "fabric-item-api-v1.accesswidener",
|
||||
"depends": {
|
||||
"fabricloader": ">=0.15.1",
|
||||
"fabric-api-base": "*"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"fabric-item-api-v1-testmod:weird_pickaxe"
|
||||
]
|
||||
}
|
Loading…
Add table
Reference in a new issue