mirror of
https://github.com/FabricMC/fabric.git
synced 2025-03-31 09:10:00 -04:00
Add hook for custom damage logic (#964)
* Add hook for custom damage logic * Address comments * Change to use new FabricItemSettings * Make CustomDamageHandler a functional interface
This commit is contained in:
parent
c1aa8ed8d7
commit
616c01224d
10 changed files with 214 additions and 1 deletions
fabric-item-api-v1/src
main
java/net/fabricmc/fabric
api/item/v1
impl/item
mixin/item
resources
testmod
java/net/fabricmc/fabric/test/item
resources
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 java.util.function.Consumer;
|
||||
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
/**
|
||||
* Allows an item to run custom logic when {@link ItemStack#damage(int, LivingEntity, Consumer)} is called.
|
||||
* This is useful for items that, for example, may drain durability from some other source before damaging
|
||||
* the stack itself.
|
||||
*
|
||||
* <p>Custom damage handlers can be set with {@link FabricItemSettings#customDamage}.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface CustomDamageHandler {
|
||||
/**
|
||||
* Called to apply damage to the given stack.
|
||||
* This can be used to e.g. drain from a battery before actually damaging the item.
|
||||
* @param amount The amount of damage originally requested
|
||||
* @param breakCallback Callback when the stack reaches zero damage. See {@link ItemStack#damage(int, LivingEntity, Consumer)} and its callsites for more information.
|
||||
* @return The amount of damage to pass to vanilla's logic
|
||||
*/
|
||||
int damage(ItemStack stack, int amount, LivingEntity entity, Consumer<LivingEntity> breakCallback);
|
||||
}
|
|
@ -19,6 +19,7 @@ package net.fabricmc.fabric.api.item.v1;
|
|||
import net.minecraft.item.FoodComponent;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Rarity;
|
||||
|
||||
import net.fabricmc.fabric.impl.item.FabricItemInternals;
|
||||
|
@ -42,6 +43,16 @@ public class FabricItemSettings extends Item.Settings {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom damage handler of the item.
|
||||
* Note that this is only called on an ItemStack if {@link ItemStack#isDamageable()} returns true.
|
||||
* @see CustomDamageHandler
|
||||
*/
|
||||
public FabricItemSettings customDamage(CustomDamageHandler handler) {
|
||||
FabricItemInternals.computeExtraData(this).customDamage(handler);
|
||||
return this;
|
||||
}
|
||||
|
||||
// Overrides of vanilla methods
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.WeakHashMap;
|
|||
|
||||
import net.minecraft.item.Item;
|
||||
|
||||
import net.fabricmc.fabric.api.item.v1.CustomDamageHandler;
|
||||
import net.fabricmc.fabric.api.item.v1.EquipmentSlotProvider;
|
||||
|
||||
public final class FabricItemInternals {
|
||||
|
@ -37,14 +38,20 @@ public final class FabricItemInternals {
|
|||
|
||||
if (data != null) {
|
||||
((ItemExtensions) item).fabric_setEquipmentSlotProvider(data.equipmentSlotProvider);
|
||||
((ItemExtensions) item).fabric_setCustomDamageHandler(data.customDamageHandler);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ExtraData {
|
||||
private /* @Nullable */ EquipmentSlotProvider equipmentSlotProvider;
|
||||
private /* @Nullable */ CustomDamageHandler customDamageHandler;
|
||||
|
||||
public void equipmentSlot(EquipmentSlotProvider equipmentSlotProvider) {
|
||||
this.equipmentSlotProvider = equipmentSlotProvider;
|
||||
}
|
||||
|
||||
public void customDamage(CustomDamageHandler handler) {
|
||||
this.customDamageHandler = handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,9 +16,12 @@
|
|||
|
||||
package net.fabricmc.fabric.impl.item;
|
||||
|
||||
import net.fabricmc.fabric.api.item.v1.CustomDamageHandler;
|
||||
import net.fabricmc.fabric.api.item.v1.EquipmentSlotProvider;
|
||||
|
||||
public interface ItemExtensions {
|
||||
EquipmentSlotProvider fabric_getEquipmentSlotProvider();
|
||||
/* @Nullable */ EquipmentSlotProvider fabric_getEquipmentSlotProvider();
|
||||
void fabric_setEquipmentSlotProvider(EquipmentSlotProvider equipmentSlotProvider);
|
||||
/* @Nullable */ CustomDamageHandler fabric_getCustomDamageHandler();
|
||||
void fabric_setCustomDamageHandler(CustomDamageHandler handler);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||
|
||||
import net.minecraft.item.Item;
|
||||
|
||||
import net.fabricmc.fabric.api.item.v1.CustomDamageHandler;
|
||||
import net.fabricmc.fabric.api.item.v1.EquipmentSlotProvider;
|
||||
import net.fabricmc.fabric.impl.item.FabricItemInternals;
|
||||
import net.fabricmc.fabric.impl.item.ItemExtensions;
|
||||
|
@ -33,6 +34,9 @@ abstract class ItemMixin implements ItemExtensions {
|
|||
@Unique
|
||||
private EquipmentSlotProvider equipmentSlotProvider;
|
||||
|
||||
@Unique
|
||||
private CustomDamageHandler customDamageHandler;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void onConstruct(Item.Settings settings, CallbackInfo info) {
|
||||
FabricItemInternals.onBuild(settings, (Item) (Object) this);
|
||||
|
@ -47,4 +51,14 @@ abstract class ItemMixin implements ItemExtensions {
|
|||
public void fabric_setEquipmentSlotProvider(EquipmentSlotProvider equipmentSlotProvider) {
|
||||
this.equipmentSlotProvider = equipmentSlotProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomDamageHandler fabric_getCustomDamageHandler() {
|
||||
return customDamageHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fabric_setCustomDamageHandler(CustomDamageHandler handler) {
|
||||
this.customDamageHandler = handler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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.function.Consumer;
|
||||
|
||||
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.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import net.fabricmc.fabric.api.item.v1.CustomDamageHandler;
|
||||
import net.fabricmc.fabric.impl.item.ItemExtensions;
|
||||
|
||||
@Mixin(ItemStack.class)
|
||||
public abstract class ItemStackMixin {
|
||||
@Shadow public abstract Item getItem();
|
||||
|
||||
@Unique
|
||||
private LivingEntity fabric_damagingEntity;
|
||||
|
||||
@Unique
|
||||
private Consumer<LivingEntity> fabric_breakCallback;
|
||||
|
||||
@Inject(method = "damage(ILnet/minecraft/entity/LivingEntity;Ljava/util/function/Consumer;)V", at = @At("HEAD"))
|
||||
private void saveDamager(int amount, LivingEntity entity, Consumer<LivingEntity> breakCallback, CallbackInfo ci) {
|
||||
this.fabric_damagingEntity = entity;
|
||||
this.fabric_breakCallback = breakCallback;
|
||||
}
|
||||
|
||||
@ModifyArg(method = "damage(ILnet/minecraft/entity/LivingEntity;Ljava/util/function/Consumer;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;damage(ILjava/util/Random;Lnet/minecraft/server/network/ServerPlayerEntity;)Z"), index = 0)
|
||||
private int hookDamage(int amount) {
|
||||
CustomDamageHandler handler = ((ItemExtensions) getItem()).fabric_getCustomDamageHandler();
|
||||
|
||||
if (handler != null) {
|
||||
return handler.damage((ItemStack) (Object) this, amount, fabric_damagingEntity, fabric_breakCallback);
|
||||
}
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
@Inject(method = "damage(ILnet/minecraft/entity/LivingEntity;Ljava/util/function/Consumer;)V", at = @At("RETURN"))
|
||||
private <T extends LivingEntity> void clearDamager(int amount, T entity, Consumer<T> breakCallback, CallbackInfo ci) {
|
||||
this.fabric_damagingEntity = null;
|
||||
this.fabric_breakCallback = null;
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
"package": "net.fabricmc.fabric.mixin.item",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"mixins": [
|
||||
"ItemStackMixin",
|
||||
"ItemMixin",
|
||||
"MobEntityMixin"
|
||||
],
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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.test.item;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.PickaxeItem;
|
||||
import net.minecraft.item.ToolMaterials;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.item.v1.CustomDamageHandler;
|
||||
import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
|
||||
|
||||
public class CustomDamageTest implements ModInitializer {
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
Registry.register(Registry.ITEM, new Identifier("fabric-item-api-v1-testmod", "weird_pickaxe"), new WeirdPick());
|
||||
}
|
||||
|
||||
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()) {
|
||||
return amount;
|
||||
} else {
|
||||
CompoundTag tag = stack.getOrCreateTag();
|
||||
tag.putInt("weird", tag.getInt("weird") + 1);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
public static class WeirdPick extends PickaxeItem {
|
||||
protected WeirdPick() {
|
||||
super(ToolMaterials.GOLD, 1, -2.8F, new FabricItemSettings().customDamage(WEIRD_DAMAGE_HANDLER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Text getName(ItemStack stack) {
|
||||
int v = stack.getOrCreateTag().getInt("weird");
|
||||
return super.getName(stack).shallowCopy().append(" (Weird Value: " + v + ")");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:item/handheld",
|
||||
"textures": {
|
||||
"layer0": "minecraft:item/golden_pickaxe"
|
||||
}
|
||||
}
|
|
@ -14,6 +14,9 @@
|
|||
],
|
||||
"client": [
|
||||
"net.fabricmc.fabric.test.item.client.TooltipTests"
|
||||
],
|
||||
"main": [
|
||||
"net.fabricmc.fabric.test.item.CustomDamageTest"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue