mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-02 02:00:14 -04:00
Add stack-aware getAttributeModifiers and isSuitableFor to FabricItem (#2090)
* Add stack-aware getAttributeModifiers to FabricItem * Add stack-aware version of isSuitableFor * Use the standard attack damage UUID
This commit is contained in:
parent
91896a4963
commit
4457765521
6 changed files with 105 additions and 11 deletions
fabric-item-api-v1/src
main
java/net/fabricmc/fabric
api/item/v1
mixin/item
resources
testmod/java/net/fabricmc/fabric/test/item
|
@ -16,7 +16,13 @@
|
|||
|
||||
package net.fabricmc.fabric.api.item.v1;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
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.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
@ -25,9 +31,7 @@ import net.minecraft.util.Hand;
|
|||
/**
|
||||
* General-purpose Fabric-provided extensions for {@link Item} subclasses.
|
||||
*
|
||||
* <p>Note: This interface is automatically implemented on all items via Mixin,
|
||||
* however it has to be implemented explicitly by modders to be able to override functions.
|
||||
* In the future, it is planned that {@code public class Item implements FabricItem} will be visible in a development environment.
|
||||
* <p>Note: This interface is automatically implemented on all items via Mixin and interface injection.
|
||||
*
|
||||
* <p>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.
|
||||
|
@ -61,4 +65,30 @@ public interface FabricItem {
|
|||
default boolean allowContinuingBlockBreaking(PlayerEntity player, ItemStack oldStack, ItemStack newStack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the attribute modifiers to apply when this stack is worn in a living entity equipment slot.
|
||||
* Stack-aware version of {@link Item#getAttributeModifiers(EquipmentSlot)}.
|
||||
*
|
||||
* <p>Note that attribute modifiers are only updated when the stack changes, i.e. when {@code ItemStack.areEqual(old, new)} is false.
|
||||
*
|
||||
* @param stack the current stack
|
||||
* @param slot the equipment slot this stack is in
|
||||
* @return the attribute modifiers
|
||||
*/
|
||||
default Multimap<EntityAttribute, EntityAttributeModifier> getAttributeModifiers(ItemStack stack, EquipmentSlot slot) {
|
||||
return ((Item) this).getAttributeModifiers(slot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if mining with this item allows drops to be harvested from the specified block state.
|
||||
* Stack-aware version of {@link Item#isSuitableFor(BlockState)}.
|
||||
*
|
||||
* @param stack the current stack
|
||||
* @param state the block state of the targeted block
|
||||
* @return true if drops can be harvested
|
||||
*/
|
||||
default boolean isSuitableFor(ItemStack stack, BlockState state) {
|
||||
return ((Item) this).isSuitableFor(state);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,15 +18,21 @@ package net.fabricmc.fabric.mixin.item;
|
|||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.attribute.EntityAttribute;
|
||||
import net.minecraft.entity.attribute.EntityAttributeModifier;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
|
@ -65,4 +71,26 @@ public abstract class ItemStackMixin {
|
|||
this.fabric_damagingEntity = null;
|
||||
this.fabric_breakCallback = null;
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "getAttributeModifiers",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/item/Item;getAttributeModifiers(Lnet/minecraft/entity/EquipmentSlot;)Lcom/google/common/collect/Multimap;"
|
||||
)
|
||||
)
|
||||
public Multimap<EntityAttribute, EntityAttributeModifier> hookGetAttributeModifiers(Item item, EquipmentSlot slot) {
|
||||
return item.getAttributeModifiers((ItemStack) (Object) this, slot);
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "isSuitableFor",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/item/Item;isSuitableFor(Lnet/minecraft/block/BlockState;)Z"
|
||||
)
|
||||
)
|
||||
public boolean hookIsSuitableFor(Item item, BlockState state) {
|
||||
return item.isSuitableFor((ItemStack) (Object) this, state);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,8 +27,6 @@ import net.minecraft.client.network.ClientPlayerInteractionManager;
|
|||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import net.fabricmc.fabric.api.item.v1.FabricItem;
|
||||
|
||||
@Mixin(ClientPlayerInteractionManager.class)
|
||||
public class ClientPlayerInteractionManagerMixin {
|
||||
@Shadow
|
||||
|
@ -58,7 +56,7 @@ public class ClientPlayerInteractionManagerMixin {
|
|||
ItemStack oldStack = this.selectedStack;
|
||||
ItemStack newStack = this.client.player.getMainHandStack();
|
||||
|
||||
if (oldStack.isOf(newStack.getItem()) && ((FabricItem) oldStack.getItem()).allowContinuingBlockBreaking(this.client.player, oldStack, newStack)) {
|
||||
if (oldStack.isOf(newStack.getItem()) && oldStack.getItem().allowContinuingBlockBreaking(this.client.player, oldStack, newStack)) {
|
||||
stackUnchanged = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ public class HeldItemRendererMixin {
|
|||
ItemStack newMainStack = client.player.getMainHandStack();
|
||||
|
||||
if (mainHand.getItem() == newMainStack.getItem()) {
|
||||
if (!((FabricItem) mainHand.getItem()).allowNbtUpdateAnimation(client.player, Hand.MAIN_HAND, mainHand, newMainStack)) {
|
||||
if (!mainHand.getItem().allowNbtUpdateAnimation(client.player, Hand.MAIN_HAND, mainHand, newMainStack)) {
|
||||
mainHand = newMainStack;
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ public class HeldItemRendererMixin {
|
|||
ItemStack newOffStack = client.player.getOffHandStack();
|
||||
|
||||
if (offHand.getItem() == newOffStack.getItem()) {
|
||||
if (!((FabricItem) offHand.getItem()).allowNbtUpdateAnimation(client.player, Hand.OFF_HAND, offHand, newOffStack)) {
|
||||
if (!offHand.getItem().allowNbtUpdateAnimation(client.player, Hand.OFF_HAND, offHand, newOffStack)) {
|
||||
offHand = newOffStack;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
},
|
||||
"description": "Hooks for items",
|
||||
"custom": {
|
||||
"fabric-api:module-lifecycle": "stable"
|
||||
"fabric-api:module-lifecycle": "stable",
|
||||
"loom:injected_interfaces": {
|
||||
"net/minecraft/class_1792": ["net/fabricmc/fabric/api/item/v1/FabricItem"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,15 @@
|
|||
|
||||
package net.fabricmc.fabric.test.item;
|
||||
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.attribute.EntityAttribute;
|
||||
import net.minecraft.entity.attribute.EntityAttributeModifier;
|
||||
import net.minecraft.entity.attribute.EntityAttributes;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
|
@ -25,9 +33,10 @@ import net.minecraft.nbt.NbtCompound;
|
|||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.fabricmc.fabric.api.item.v1.FabricItem;
|
||||
public class UpdatingItem extends Item {
|
||||
private static final EntityAttributeModifier PLUS_FIVE = new EntityAttributeModifier(
|
||||
ATTACK_DAMAGE_MODIFIER_ID, "updating item", 5, EntityAttributeModifier.Operation.ADDITION);
|
||||
|
||||
public class UpdatingItem extends Item implements FabricItem {
|
||||
private final boolean allowUpdateAnimation;
|
||||
|
||||
public UpdatingItem(boolean allowUpdateAnimation) {
|
||||
|
@ -52,4 +61,30 @@ public class UpdatingItem extends Item implements FabricItem {
|
|||
public boolean allowContinuingBlockBreaking(PlayerEntity player, ItemStack oldStack, ItemStack newStack) {
|
||||
return true; // set to false and you won't be able to break a block in survival with this item
|
||||
}
|
||||
|
||||
// True for 15 seconds every 30 seconds
|
||||
private boolean isEnabled(ItemStack stack) {
|
||||
return !stack.hasNbt() || stack.getNbt().getLong("ticks") % 600 < 300;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Multimap<EntityAttribute, EntityAttributeModifier> getAttributeModifiers(ItemStack stack, EquipmentSlot slot) {
|
||||
// Give + 5 attack damage for 15 seconds every 30 seconds.
|
||||
if (slot == EquipmentSlot.MAINHAND && isEnabled(stack)) {
|
||||
return ImmutableMultimap.of(EntityAttributes.GENERIC_ATTACK_DAMAGE, PLUS_FIVE);
|
||||
} else {
|
||||
return ImmutableMultimap.of();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuitableFor(ItemStack stack, BlockState state) {
|
||||
// Suitable for everything for 15 seconds every 30 seconds.
|
||||
return isEnabled(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMiningSpeedMultiplier(ItemStack stack, BlockState state) {
|
||||
return isEnabled(stack) ? 20 : super.getMiningSpeedMultiplier(stack, state);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue