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 f46fd65e0..cfc842419 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 @@ -16,19 +16,9 @@ package net.fabricmc.fabric.api.item.v1; -import java.util.function.Consumer; - import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; - import net.fabricmc.fabric.impl.item.FabricItemInternals; - -import net.minecraft.entity.LivingEntity; - -import net.minecraftforge.common.extensions.IForgeItem; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Nullable; - import net.minecraft.block.BlockState; import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.attribute.EntityAttribute; @@ -37,9 +27,8 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.Hand; - -import net.fabricmc.fabric.impl.client.item.ItemApiClientEventHooks; -import net.fabricmc.fabric.impl.item.ItemExtensions; +import net.minecraftforge.common.extensions.IForgeItem; +import org.jetbrains.annotations.ApiStatus; /** * General-purpose Fabric-provided extensions for {@link Item} subclasses. @@ -49,7 +38,7 @@ *

Note to maintainers: Functions should only be added to this interface if they are general-purpose enough, * to be evaluated on a case-by-case basis. Otherwise, they are better suited for more specialized APIs. */ -public interface FabricItem extends IForgeItem { +public interface FabricItem { /** * When the NBT of an item stack in the main hand or off hand changes, vanilla runs an "update animation". * This function is called on the client side when the NBT or count of the stack has changed, but not the item, @@ -62,7 +51,7 @@ public interface FabricItem extends IForgeItem { * @return true to run the vanilla animation, false to cancel it. */ default boolean allowNbtUpdateAnimation(PlayerEntity player, Hand hand, ItemStack oldStack, ItemStack newStack) { - return !FabricItemInternals.allowForgeCall() || shouldCauseReequipAnimation(oldStack, newStack, false); + return !FabricItemInternals.allowForgeCall() || ((IForgeItem) this).shouldCauseReequipAnimation(oldStack, newStack, false); } /** @@ -76,7 +65,7 @@ default boolean allowNbtUpdateAnimation(PlayerEntity player, Hand hand, ItemStac * @return true to allow continuing block breaking, false to reset the progress. */ default boolean allowContinuingBlockBreaking(PlayerEntity player, ItemStack oldStack, ItemStack newStack) { - return FabricItemInternals.allowForgeCall() && !shouldCauseBlockBreakReset(oldStack, newStack); + return FabricItemInternals.allowForgeCall() && !((IForgeItem) this).shouldCauseBlockBreakReset(oldStack, newStack); } /** @@ -91,7 +80,7 @@ default boolean allowContinuingBlockBreaking(PlayerEntity player, ItemStack oldS */ default Multimap getAttributeModifiers(ItemStack stack, EquipmentSlot slot) { if (FabricItemInternals.allowForgeCall()) { - return getAttributeModifiers(slot, stack); + return ((IForgeItem) this).getAttributeModifiers(slot, stack); } return HashMultimap.create(); } @@ -105,7 +94,7 @@ default Multimap getAttributeModifiers * @return true if drops can be harvested */ default boolean isSuitableFor(ItemStack stack, BlockState state) { - return FabricItemInternals.allowForgeCall() && isCorrectToolForDrops(stack, state); + return FabricItemInternals.allowForgeCall() && ((IForgeItem) this).isCorrectToolForDrops(stack, state); } /** @@ -139,69 +128,8 @@ default boolean isSuitableFor(ItemStack stack, BlockState state) { @ApiStatus.OverrideOnly default ItemStack getRecipeRemainder(ItemStack stack) { if (FabricItemInternals.allowForgeCall()) { - return getCraftingRemainingItem(stack); + return ((IForgeItem) this).getCraftingRemainingItem(stack); } return ItemStack.EMPTY; } - - // FFAPI: Forge default implementation - - @Override - default ItemStack getCraftingRemainingItem(ItemStack stack) { - ItemStack fabricRemainder = FabricItemInternals.nonRecursiveApiCall(() -> getRecipeRemainder(stack)); - if (!fabricRemainder.isEmpty()) { - return fabricRemainder; - } - return IForgeItem.super.hasCraftingRemainingItem(stack) ? new ItemStack(((Item) this).getRecipeRemainder()) : ItemStack.EMPTY; - } - - @Override - default boolean hasCraftingRemainingItem(ItemStack stack) { - return !FabricItemInternals.nonRecursiveApiCall(() -> getRecipeRemainder(stack)).isEmpty() || IForgeItem.super.hasCraftingRemainingItem(stack); - } - - @Override - default Multimap getAttributeModifiers(EquipmentSlot slot, ItemStack stack) { - // Fetch forge attribute modifiers first - Multimap modifiers = HashMultimap.create(IForgeItem.super.getAttributeModifiers(slot, stack)); - // Add all fabric attribute modifiers - modifiers.putAll(FabricItemInternals.nonRecursiveApiCall(() -> getAttributeModifiers(stack, slot))); - return modifiers; - } - - @Override - default boolean isCorrectToolForDrops(ItemStack stack, BlockState state) { - return FabricItemInternals.nonRecursiveApiCall(() -> isSuitableFor(stack, state)) || IForgeItem.super.isCorrectToolForDrops(stack, state); - } - - @Override - default boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { - if (IForgeItem.super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged)) { - PlayerEntity player = ItemApiClientEventHooks.getClientPlayerSafely(); - Hand hand = oldStack == player.getMainHandStack() ? Hand.MAIN_HAND : Hand.OFF_HAND; - return FabricItemInternals.nonRecursiveApiCall(() -> allowNbtUpdateAnimation(player, hand, oldStack, newStack)); - } - return false; - } - - @Override - default boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack) { - return IForgeItem.super.shouldCauseBlockBreakReset(oldStack, newStack) && FabricItemInternals.nonRecursiveApiCall(() -> !allowContinuingBlockBreaking(ItemApiClientEventHooks.getClientPlayerSafely(), oldStack, newStack)); - } - - @Override - @Nullable - default EquipmentSlot getEquipmentSlot(ItemStack stack) { - EquipmentSlotProvider equipmentSlotProvider = ((ItemExtensions) stack.getItem()).fabric_getEquipmentSlotProvider(); - return equipmentSlotProvider != null ? equipmentSlotProvider.getPreferredEquipmentSlot(stack) : IForgeItem.super.getEquipmentSlot(stack); - } - - @Override - default int damageItem(ItemStack stack, int amount, T entity, Consumer onBroken) { - CustomDamageHandler handler = ((ItemExtensions) this).fabric_getCustomDamageHandler(); - if (handler != null) { - return handler.damage(stack, amount, entity, (Consumer) onBroken); - } - return IForgeItem.super.damageItem(stack, amount, entity, onBroken); - } } diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/impl/item/FabricItemImplHooks.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/impl/item/FabricItemImplHooks.java new file mode 100644 index 000000000..5e8807547 --- /dev/null +++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/impl/item/FabricItemImplHooks.java @@ -0,0 +1,69 @@ +/* + * 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.impl.item; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import net.fabricmc.fabric.api.item.v1.FabricItem; +import net.fabricmc.fabric.impl.client.item.ItemApiClientEventHooks; +import net.minecraft.block.BlockState; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.attribute.EntityAttribute; +import net.minecraft.entity.attribute.EntityAttributeModifier; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Hand; + +@SuppressWarnings("unused") +public final class FabricItemImplHooks { + + public static ItemStack getCraftingRemainingItem(FabricItem item, ItemStack stack) { + ItemStack fabricRemainder = FabricItemInternals.nonRecursiveApiCall(() -> item.getRecipeRemainder(stack)); + if (!fabricRemainder.isEmpty()) { + return fabricRemainder; + } + return null; + } + + public static boolean hasCraftingRemainingItem(FabricItem item, ItemStack stack) { + return !FabricItemInternals.nonRecursiveApiCall(() -> item.getRecipeRemainder(stack)).isEmpty(); + } + + public static Multimap getAttributeModifiers(Multimap existing, FabricItem item, EquipmentSlot slot, ItemStack stack) { + // Fetch forge attribute modifiers first + Multimap modifiers = HashMultimap.create(existing); + // Add all fabric attribute modifiers + modifiers.putAll(FabricItemInternals.nonRecursiveApiCall(() -> item.getAttributeModifiers(stack, slot))); + return modifiers; + } + + public static boolean isCorrectToolForDrops(FabricItem item, ItemStack stack, BlockState state) { + return FabricItemInternals.nonRecursiveApiCall(() -> item.isSuitableFor(stack, state)); + } + + public static boolean shouldCauseReequipAnimation(FabricItem item, ItemStack oldStack, ItemStack newStack, boolean slotChanged) { + PlayerEntity player = ItemApiClientEventHooks.getClientPlayerSafely(); + Hand hand = oldStack == player.getMainHandStack() ? Hand.MAIN_HAND : Hand.OFF_HAND; + return FabricItemInternals.nonRecursiveApiCall(() -> item.allowNbtUpdateAnimation(player, hand, oldStack, newStack)); + } + + public static boolean shouldCauseBlockBreakReset(boolean original, FabricItem item, ItemStack oldStack, ItemStack newStack) { + return original && FabricItemInternals.nonRecursiveApiCall(() -> !item.allowContinuingBlockBreaking(ItemApiClientEventHooks.getClientPlayerSafely(), oldStack, newStack)); + } + + private FabricItemImplHooks() {} +} diff --git a/fabric-item-api-v1/src/main/resources/META-INF/asm/implementFabricItem.js b/fabric-item-api-v1/src/main/resources/META-INF/asm/implementFabricItem.js new file mode 100644 index 000000000..b6565e494 --- /dev/null +++ b/fabric-item-api-v1/src/main/resources/META-INF/asm/implementFabricItem.js @@ -0,0 +1,219 @@ +var ASMAPI = Java.type('net.minecraftforge.coremod.api.ASMAPI'); +var Opcodes = Java.type('org.objectweb.asm.Opcodes'); +var MethodInsnNode = Java.type('org.objectweb.asm.tree.MethodInsnNode'); +var InsnNode = Java.type('org.objectweb.asm.tree.InsnNode'); +var JumpInsnNode = Java.type('org.objectweb.asm.tree.JumpInsnNode'); +var LabelNode = Java.type('org.objectweb.asm.tree.LabelNode'); +var VarInsnNode = Java.type('org.objectweb.asm.tree.VarInsnNode'); +var TypeInsnNode = Java.type('org.objectweb.asm.tree.TypeInsnNode'); + +function initializeCoreMod() { + var yarn = ASMAPI.getSystemPropertyFlag('yarn'); + return { + 'extendFabricItem': { + 'target': { + 'type': 'CLASS', + 'name': 'net.minecraftforge.common.extensions.IForgeItem' + }, + 'transformer': function (node) { + node.interfaces.add('net/fabricmc/fabric/api/item/v1/FabricItem'); + return node; + } + }, + 'implementGetCraftingRemainingItem': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraftforge.common.extensions.IForgeItem', + 'methodName': 'getCraftingRemainingItem', + 'methodDesc': yarn ? '(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/item/ItemStack;' : '(Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/world/item/ItemStack;' + }, + 'transformer': function (node) { + var insn = ASMAPI.findFirstInstruction(node, Opcodes.NEW); + if (insn != null && insn.desc === (yarn ? 'net/minecraft/item/ItemStack' : 'net/minecraft/world/item/ItemStack')) { + var target = new LabelNode(); + var callDesc = yarn ? '(Lnet/fabricmc/fabric/api/item/v1/FabricItem;Lnet/minecraft/item/ItemStack;)Lnet/minecraft/item/ItemStack;' : '(Lnet/fabricmc/fabric/api/item/v1/FabricItem;Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/world/item/ItemStack;'; + var list = ASMAPI.listOf( + new VarInsnNode(Opcodes.ALOAD, 0), + new VarInsnNode(Opcodes.ALOAD, 1), + new MethodInsnNode(Opcodes.INVOKESTATIC, 'net/fabricmc/fabric/impl/item/FabricItemImplHooks', 'getCraftingRemainingItem', callDesc), + new InsnNode(Opcodes.DUP), + new JumpInsnNode(Opcodes.IFNULL, target), + new InsnNode(Opcodes.ARETURN), + target + ); + node.instructions.insertBefore(insn, list); + } + return node; + } + }, + 'implementHasCraftingRemainingItem': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraftforge.common.extensions.IForgeItem', + 'methodName': 'hasCraftingRemainingItem', + 'methodDesc': yarn ? '(Lnet/minecraft/item/ItemStack;)Z' : '(Lnet/minecraft/world/item/ItemStack;)Z' + }, + 'transformer': function (node) { + var target = new LabelNode(); + var callDesc = yarn ? '(Lnet/fabricmc/fabric/api/item/v1/FabricItem;Lnet/minecraft/item/ItemStack;)Z' : '(Lnet/fabricmc/fabric/api/item/v1/FabricItem;Lnet/minecraft/world/item/ItemStack;)Z'; + var list = ASMAPI.listOf( + new VarInsnNode(Opcodes.ALOAD, 0), + new VarInsnNode(Opcodes.ALOAD, 1), + new MethodInsnNode(Opcodes.INVOKESTATIC, 'net/fabricmc/fabric/impl/item/FabricItemImplHooks', 'hasCraftingRemainingItem', callDesc), + new JumpInsnNode(Opcodes.IFEQ, target), + new InsnNode(Opcodes.ICONST_1), + new InsnNode(Opcodes.IRETURN), + target + ); + node.instructions.insert(list); + return node; + } + }, + 'implementGetAttributeModifiers': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraftforge.common.extensions.IForgeItem', + 'methodName': 'getAttributeModifiers', + 'methodDesc': yarn ? '(Lnet/minecraft/entity/EquipmentSlot;Lnet/minecraft/item/ItemStack;)Lcom/google/common/collect/Multimap;' : '(Lnet/minecraft/world/entity/EquipmentSlot;Lnet/minecraft/world/item/ItemStack;)Lcom/google/common/collect/Multimap;' + }, + 'transformer': function (node) { + var insn = ASMAPI.findFirstInstruction(node, Opcodes.ARETURN); + if (insn != null) { + var callDesc = yarn ? '(Lcom/google/common/collect/Multimap;Lnet/fabricmc/fabric/api/item/v1/FabricItem;Lnet/minecraft/entity/EquipmentSlot;Lnet/minecraft/item/ItemStack;)Lcom/google/common/collect/Multimap;' : '(Lcom/google/common/collect/Multimap;Lnet/fabricmc/fabric/api/item/v1/FabricItem;Lnet/minecraft/world/entity/EquipmentSlot;Lnet/minecraft/world/item/ItemStack;)Lcom/google/common/collect/Multimap;'; + var list = ASMAPI.listOf( + new VarInsnNode(Opcodes.ALOAD, 0), + new VarInsnNode(Opcodes.ALOAD, 1), + new VarInsnNode(Opcodes.ALOAD, 2), + new MethodInsnNode(Opcodes.INVOKESTATIC, 'net/fabricmc/fabric/impl/item/FabricItemImplHooks', 'getAttributeModifiers', callDesc) + ); + node.instructions.insertBefore(insn, list); + } + return node; + } + }, + 'implementIsCorrectToolForDrops': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraftforge.common.extensions.IForgeItem', + 'methodName': 'isCorrectToolForDrops', + 'methodDesc': yarn ? '(Lnet/minecraft/item/ItemStack;Lnet/minecraft/block/BlockState;)Z' : '(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/level/block/state/BlockState;)Z' + }, + 'transformer': function (node) { + var target = new LabelNode(); + var callDesc = yarn ? '(Lnet/fabricmc/fabric/api/item/v1/FabricItem;Lnet/minecraft/item/ItemStack;Lnet/minecraft/block/BlockState;)Z' : '(Lnet/fabricmc/fabric/api/item/v1/FabricItem;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/level/block/state/BlockState;)Z'; + var list = ASMAPI.listOf( + new VarInsnNode(Opcodes.ALOAD, 0), + new VarInsnNode(Opcodes.ALOAD, 1), + new VarInsnNode(Opcodes.ALOAD, 2), + new MethodInsnNode(Opcodes.INVOKESTATIC, 'net/fabricmc/fabric/impl/item/FabricItemImplHooks', 'isCorrectToolForDrops', callDesc), + new JumpInsnNode(Opcodes.IFEQ, target), + new InsnNode(Opcodes.ICONST_1), + new InsnNode(Opcodes.IRETURN), + target + ); + node.instructions.insert(list); + return node; + } + }, + 'implementShouldCauseReequipAnimation': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraftforge.common.extensions.IForgeItem', + 'methodName': 'shouldCauseReequipAnimation', + 'methodDesc': yarn ? '(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemStack;Z)Z' : '(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemStack;Z)Z' + }, + 'transformer': function (node) { + var insn = ASMAPI.findFirstInstruction(node, Opcodes.IFNE); + if (insn != null) { + var callDesc = yarn ? '(Lnet/fabricmc/fabric/api/item/v1/FabricItem;Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemStack;Z)Z' : '(Lnet/fabricmc/fabric/api/item/v1/FabricItem;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemStack;Z)Z'; + var list = ASMAPI.listOf( + new VarInsnNode(Opcodes.ALOAD, 0), + new VarInsnNode(Opcodes.ALOAD, 1), + new VarInsnNode(Opcodes.ALOAD, 2), + new VarInsnNode(Opcodes.ILOAD, 3), + new MethodInsnNode(Opcodes.INVOKESTATIC, 'net/fabricmc/fabric/impl/item/FabricItemImplHooks', 'shouldCauseReequipAnimation', callDesc), + new JumpInsnNode(Opcodes.IFEQ, insn.label) + ); + node.instructions.insert(insn, list); + } + return node; + } + }, + 'implementShouldCauseBlockBreakReset': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraftforge.common.extensions.IForgeItem', + 'methodName': 'shouldCauseBlockBreakReset', + 'methodDesc': yarn ? '(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemStack;)Z' : '(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemStack;)Z' + }, + 'transformer': function (node) { + for (var i = node.instructions.size() - 1; i >= 0; i--) { + var insn = node.instructions.get(i); + if (insn.opcode === Opcodes.IRETURN) { + var callDesc = yarn ? '(ZLnet/fabricmc/fabric/api/item/v1/FabricItem;Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemStack;)Z' : '(ZLnet/fabricmc/fabric/api/item/v1/FabricItem;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemStack;)Z'; + var list = ASMAPI.listOf( + new VarInsnNode(Opcodes.ALOAD, 0), + new VarInsnNode(Opcodes.ALOAD, 1), + new VarInsnNode(Opcodes.ALOAD, 2), + new MethodInsnNode(Opcodes.INVOKESTATIC, 'net/fabricmc/fabric/impl/item/FabricItemImplHooks', 'shouldCauseBlockBreakReset', callDesc) + ); + node.instructions.insertBefore(insn, list); + } + } + return node; + } + }, + 'implementGetEquipmentSlot': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraftforge.common.extensions.IForgeItem', + 'methodName': 'getEquipmentSlot', + 'methodDesc': yarn ? '(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/entity/EquipmentSlot;' : '(Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/world/entity/EquipmentSlot;' + }, + 'transformer': function (node) { + var target = new LabelNode(); + var list = ASMAPI.listOf( + new VarInsnNode(Opcodes.ALOAD, 1), + new MethodInsnNode(Opcodes.INVOKEVIRTUAL, yarn ? 'net/minecraft/item/ItemStack' : 'net/minecraft/world/item/ItemStack', ASMAPI.mapMethod('m_41720_'), yarn ? '()Lnet/minecraft/item/Item;' : '()Lnet/minecraft/world/item/Item;'), + new TypeInsnNode(Opcodes.CHECKCAST, 'net/fabricmc/fabric/impl/item/ItemExtensions'), + new MethodInsnNode(Opcodes.INVOKEINTERFACE, 'net/fabricmc/fabric/impl/item/ItemExtensions', 'fabric_getEquipmentSlotProvider', '()Lnet/fabricmc/fabric/api/item/v1/EquipmentSlotProvider;'), + new InsnNode(Opcodes.DUP), + new JumpInsnNode(Opcodes.IFNULL, target), + new VarInsnNode(Opcodes.ALOAD, 1), + new MethodInsnNode(Opcodes.INVOKEINTERFACE, 'net/fabricmc/fabric/api/item/v1/EquipmentSlotProvider', 'getPreferredEquipmentSlot', yarn ? '(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/entity/EquipmentSlot;' : '(Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/world/entity/EquipmentSlot;'), + new InsnNode(Opcodes.ARETURN), + target + ); + node.instructions.insert(list); + return node; + } + }, + 'implementDamageItem': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraftforge.common.extensions.IForgeItem', + 'methodName': 'damageItem', + 'methodDesc': yarn ? '(Lnet/minecraft/item/ItemStack;ILnet/minecraft/entity/LivingEntity;Ljava/util/function/Consumer;)I' : '(Lnet/minecraft/world/item/ItemStack;ILnet/minecraft/world/entity/LivingEntity;Ljava/util/function/Consumer;)I' + }, + 'transformer': function (node) { + var target = new LabelNode(); + var list = ASMAPI.listOf( + new VarInsnNode(Opcodes.ALOAD, 0), + new TypeInsnNode(Opcodes.CHECKCAST, 'net/fabricmc/fabric/impl/item/ItemExtensions'), + new MethodInsnNode(Opcodes.INVOKEINTERFACE, 'net/fabricmc/fabric/impl/item/ItemExtensions', 'fabric_getCustomDamageHandler', '()Lnet/fabricmc/fabric/api/item/v1/CustomDamageHandler;'), + new InsnNode(Opcodes.DUP), + new JumpInsnNode(Opcodes.IFNULL, target), + new VarInsnNode(Opcodes.ALOAD, 1), + new VarInsnNode(Opcodes.ILOAD, 2), + new VarInsnNode(Opcodes.ALOAD, 3), + new VarInsnNode(Opcodes.ALOAD, 4), + new MethodInsnNode(Opcodes.INVOKEINTERFACE, 'net/fabricmc/fabric/api/item/v1/CustomDamageHandler', 'damage', yarn ? '(Lnet/minecraft/item/ItemStack;ILnet/minecraft/entity/LivingEntity;Ljava/util/function/Consumer;)I' : '(Lnet/minecraft/world/item/ItemStack;ILnet/minecraft/world/entity/LivingEntity;Ljava/util/function/Consumer;)I'), + new InsnNode(Opcodes.IRETURN), + target + ); + node.instructions.insert(list); + return node; + } + } + } +} diff --git a/fabric-item-api-v1/src/main/resources/META-INF/coremods.json b/fabric-item-api-v1/src/main/resources/META-INF/coremods.json new file mode 100644 index 000000000..6240ffa11 --- /dev/null +++ b/fabric-item-api-v1/src/main/resources/META-INF/coremods.json @@ -0,0 +1,3 @@ +{ + "implementFabricItem": "META-INF/asm/implementFabricItem.js" +} diff --git a/gradle.properties b/gradle.properties index 9c958860b..4b8465cd6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -68,5 +68,5 @@ fabric-client-tags-api-v1-version=1.1.1 loom.platform=forge forge_version=1.20.1-47.1.3 pack_format=15 -forgified_version=1.9.14 +forgified_version=1.9.15 forge_fabric_loader_version=2.2.1+0.14.21+1.20.1