diff --git a/common/src/main/java/me/shedaniel/architectury/extensions/ItemExtension.java b/common/src/main/java/me/shedaniel/architectury/extensions/ItemExtension.java index a28a2945..053b752e 100644 --- a/common/src/main/java/me/shedaniel/architectury/extensions/ItemExtension.java +++ b/common/src/main/java/me/shedaniel/architectury/extensions/ItemExtension.java @@ -19,15 +19,29 @@ package me.shedaniel.architectury.extensions; +import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; public interface ItemExtension { /** * Invoked every tick when this item is equipped. * - * @param stack the item stack of the armor + * @param stack the item stack * @param player the player wearing the armor */ - void tickArmor(ItemStack stack, Player player); + default void tickArmor(ItemStack stack, Player player) { + } + + /** + * Returns the {@link EquipmentSlot} for {@link ItemStack}. + * + * @param stack the item stack + * @return the {@link EquipmentSlot}, return {@code null} to default to vanilla's {@link net.minecraft.world.entity.Mob#getEquipmentSlotForItem(ItemStack)} + */ + @Nullable + default EquipmentSlot getCustomEquipmentSlot(ItemStack stack) { + return null; + } } diff --git a/fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinMob.java b/fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinMob.java new file mode 100644 index 00000000..a785d67f --- /dev/null +++ b/fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinMob.java @@ -0,0 +1,44 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 shedaniel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package me.shedaniel.architectury.mixin.fabric; + +import me.shedaniel.architectury.extensions.ItemExtension; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(Mob.class) +public class MixinMob { + @Inject(method = "getEquipmentSlotForItem", at = @At("HEAD"), cancellable = true) + private static void getEquipmentSlotForItem(ItemStack stack, CallbackInfoReturnable cir) { + Item item = stack.getItem(); + if (item instanceof ItemExtension) { + EquipmentSlot slot = ((ItemExtension) item).getCustomEquipmentSlot(stack); + if (slot != null) { + cir.setReturnValue(slot); + } + } + } +} diff --git a/fabric/src/main/resources/architectury.mixins.json b/fabric/src/main/resources/architectury.mixins.json index 4f3433e6..1807f492 100644 --- a/fabric/src/main/resources/architectury.mixins.json +++ b/fabric/src/main/resources/architectury.mixins.json @@ -1,31 +1,31 @@ { - "required": true, - "package": "me.shedaniel.architectury.mixin.fabric", - "plugin": "me.shedaniel.architectury.plugin.fabric.ArchitecturyMixinPlugin", - "compatibilityLevel": "JAVA_8", - "minVersion": "0.7.11", - "client": [ - "client.MixinClientLevel", - "client.MixinClientPacketListener", - "client.MixinDebugScreenOverlay", - "client.MixinEffectInstance", - "client.MixinGameRenderer", - "client.MixinIntegratedServer", - "client.MixinKeyboardHandler", - "client.MixinMinecraft", - "client.MixinMouseHandler", - "client.MixinMultiPlayerGameMode", - "client.MixinScreen", - "client.MixinTextureAtlas" - ], - "mixins": [ - "ExplosionPreInvoker", "LivingDeathInvoker", "MixinBlockEntityExtension", "MixinBlockItem", "MixinCollisionContext", "MixinCommands", - "MixinDedicatedServer", "MixinEntityCollisionContext", "MixinExplosion", "MixinFurnaceResultSlot", "MixinInventory", "MixinItemEntity", "MixinLivingEntity", - "MixinPlayer", "MixinPlayerAdvancements", "MixinPlayerList", "MixinResultSlot", "MixinServerGamePacketListenerImpl", "MixinServerLevel", - "MixinServerPlayer", "MixinServerPlayerGameMode", "PlayerAttackInvoker" - ], - "injectors": { - "maxShiftBy": 5, - "defaultRequire": 1 - } + "required": true, + "package": "me.shedaniel.architectury.mixin.fabric", + "plugin": "me.shedaniel.architectury.plugin.fabric.ArchitecturyMixinPlugin", + "compatibilityLevel": "JAVA_8", + "minVersion": "0.7.11", + "client": [ + "client.MixinClientLevel", + "client.MixinClientPacketListener", + "client.MixinDebugScreenOverlay", + "client.MixinEffectInstance", + "client.MixinGameRenderer", + "client.MixinIntegratedServer", + "client.MixinKeyboardHandler", + "client.MixinMinecraft", + "client.MixinMouseHandler", + "client.MixinMultiPlayerGameMode", + "client.MixinScreen", + "client.MixinTextureAtlas" + ], + "mixins": [ + "ExplosionPreInvoker", "LivingDeathInvoker", "MixinBlockEntityExtension", "MixinBlockItem", "MixinCollisionContext", "MixinCommands", + "MixinDedicatedServer", "MixinEntityCollisionContext", "MixinExplosion", "MixinFurnaceResultSlot", "MixinInventory", "MixinItemEntity", + "MixinLivingEntity", "MixinMob", "MixinPlayer", "MixinPlayerAdvancements", "MixinPlayerList", "MixinResultSlot", "MixinServerGamePacketListenerImpl", + "MixinServerLevel", "MixinServerPlayer", "MixinServerPlayerGameMode", "PlayerAttackInvoker" + ], + "injectors": { + "maxShiftBy": 5, + "defaultRequire": 1 + } } diff --git a/forge/src/main/java/me/shedaniel/architectury/mixin/forge/MixinItemExtension.java b/forge/src/main/java/me/shedaniel/architectury/mixin/forge/MixinItemExtension.java index 8bbd20c5..8e07115e 100644 --- a/forge/src/main/java/me/shedaniel/architectury/mixin/forge/MixinItemExtension.java +++ b/forge/src/main/java/me/shedaniel/architectury/mixin/forge/MixinItemExtension.java @@ -20,10 +20,12 @@ package me.shedaniel.architectury.mixin.forge; import me.shedaniel.architectury.extensions.ItemExtension; +import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraftforge.common.extensions.IForgeItem; +import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; @Mixin(ItemExtension.class) @@ -32,4 +34,10 @@ public interface MixinItemExtension extends IForgeItem { default void onArmorTick(ItemStack stack, Level world, Player player) { ((ItemExtension) this).tickArmor(stack, player); } + + @Nullable + @Override + default EquipmentSlot getEquipmentSlot(ItemStack stack) { + return ((ItemExtension) this).getCustomEquipmentSlot(stack); + } } diff --git a/testmod-common/src/main/java/me/shedaniel/architectury/test/registry/TestRegistries.java b/testmod-common/src/main/java/me/shedaniel/architectury/test/registry/TestRegistries.java index a0d789c6..f4234efb 100644 --- a/testmod-common/src/main/java/me/shedaniel/architectury/test/registry/TestRegistries.java +++ b/testmod-common/src/main/java/me/shedaniel/architectury/test/registry/TestRegistries.java @@ -24,6 +24,7 @@ import me.shedaniel.architectury.registry.BlockProperties; import me.shedaniel.architectury.registry.DeferredRegister; import me.shedaniel.architectury.registry.RegistrySupplier; import me.shedaniel.architectury.test.TestMod; +import me.shedaniel.architectury.test.registry.objects.EquippableTickingItem; import me.shedaniel.architectury.test.tab.TestCreativeTabs; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; @@ -44,6 +45,8 @@ public class TestRegistries { public static final RegistrySupplier TEST_ITEM = ITEMS.register("test_item", () -> new Item(new Item.Properties().tab(TestCreativeTabs.TEST_TAB))); + public static final RegistrySupplier TEST_EQUIPPABLE = ITEMS.register("test_eqippable", () -> + new EquippableTickingItem(new Item.Properties().tab(TestCreativeTabs.TEST_TAB))); public static final RegistrySupplier TEST_BLOCK = BLOCKS.register("test_block", () -> new Block(BlockProperties.copy(Blocks.STONE))); diff --git a/testmod-common/src/main/java/me/shedaniel/architectury/test/registry/objects/EquippableTickingItem.java b/testmod-common/src/main/java/me/shedaniel/architectury/test/registry/objects/EquippableTickingItem.java new file mode 100644 index 00000000..c1fe3b37 --- /dev/null +++ b/testmod-common/src/main/java/me/shedaniel/architectury/test/registry/objects/EquippableTickingItem.java @@ -0,0 +1,46 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 shedaniel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package me.shedaniel.architectury.test.registry.objects; + +import me.shedaniel.architectury.extensions.ItemExtension; +import me.shedaniel.architectury.test.TestMod; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +public class EquippableTickingItem extends Item implements ItemExtension { + public EquippableTickingItem(Properties properties) { + super(properties); + } + + @Override + public void tickArmor(ItemStack stack, Player player) { + TestMod.SINK.accept("Ticking " + new TranslatableComponent(stack.getDescriptionId()).getString()); + } + + @Nullable + @Override + public EquipmentSlot getCustomEquipmentSlot(ItemStack stack) { + return EquipmentSlot.HEAD; + } +}