Re-introduce IForgeItem.damageItem when an item takes damage, Fixes #10344 (#10372)

This commit is contained in:
Jonathing authored and GitHub committed 2025-02-12 17:29:44 -08:00
1 parent 960fce505c
commit 056360b050
7 files changed
+368 -9

No files matched your search

@@ -5,6 +5,8 @@
package net.minecraftforge.common.extensions;
import java.util.Arrays;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -12,6 +14,8 @@ import java.util.function.Supplier;
import net.minecraft.ChatFormatting;
import net.minecraft.Util;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import org.jetbrains.annotations.Nullable;
import com.mojang.authlib.GameProfile;
@@ -74,6 +78,46 @@ public interface IForgeGameTestHelper {
throw new GameTestAssertException(message.get());
}
default <N> void assertValueEqual(N expected, N actual, String name, String message) {
this.assertValueEqual(expected, actual, name, () -> message);
}
default <N> void assertValueEqual(N expected, N actual, String name, Supplier<String> message) {
if (!Objects.equals(expected, actual))
throw new GameTestAssertException("%s -- Expected %s to be %s, but was %s".formatted(message.get(), name, expected, actual));
}
default <N> void assertValueEqual(N[] expected, N[] actual, String name, String message) {
this.assertValueEqual(expected, actual, name, () -> message);
}
default <N> void assertValueEqual(N[] expected, N[] actual, String name, Supplier<String> message) {
if (!Objects.deepEquals(expected, actual))
throw new GameTestAssertException("%s -- Expected %s to be %s, but was %s".formatted(message.get(), name, Arrays.toString(expected), Arrays.toString(actual)));
}
default <N> void assertValueNotEqual(N expected, N actual, String name, String message) {
this.assertValueNotEqual(expected, actual, name, () -> message);
}
default <N> void assertValueNotEqual(N expected, N actual, String name, Supplier<String> message) {
if (Objects.equals(expected, actual))
throw new GameTestAssertException("%s -- Expected %s to NOT be %s, but was".formatted(message.get(), name, expected));
}
default <N> void assertValueNotEqual(N[] expected, N[] actual, String name, String message) {
this.assertValueNotEqual(expected, actual, name, () -> message);
}
default <N> void assertValueNotEqual(N[] expected, N[] actual, String name, Supplier<String> message) {
if (!Objects.deepEquals(expected, actual))
throw new GameTestAssertException("%s -- Expected %s to NOT be %s, but was".formatted(message.get(), name, Arrays.toString(expected)));
}
default <E> Registry<E> registryLookup(ResourceKey<? extends Registry<? extends E>> registryKey) {
return this.self().getLevel().registryAccess().lookupOrThrow(registryKey);
}
default ServerPlayer makeMockServerPlayer() {
var level = self().getLevel();
var cookie = CommonListenerCookie.createInitial(new GameProfile(UUID.randomUUID(), "test-mock-player"), false);
@@ -181,19 +225,49 @@ public interface IForgeGameTestHelper {
}
public void assertUnset() {
if (this.value != null)
throw new GameTestAssertException("Expected " + name + " to be null, but was " + this.value);
this.assertUnset((Supplier<String>) null);
}
public void assertUnset(String message) {
this.assertUnset(message != null ? () -> message : null);
}
public void assertUnset(Supplier<String> message) {
if (this.value != null) {
String s = message != null ? message.get() + " -- " : "";
throw new GameTestAssertException(s + "Expected " + name + " to be null, but was " + this.value);
}
}
public void assertSet() {
if (this.value == null)
throw new GameTestAssertException("Flag " + name + " was never set");
this.assertSet((Supplier<String>) null);
}
public void assertSet(String message) {
this.assertSet(message != null ? () -> message : null);
}
public void assertSet(Supplier<String> message) {
if (this.value == null) {
String s = message != null ? message.get() + " -- " : "";
throw new GameTestAssertException(s + "Flag " + name + " was never set");
}
}
public void assertEquals(T expected) {
assertSet();
if (expected != null && !expected.equals(this.value))
throw new GameTestAssertException("Expected " + name + " to be " + expected + ", but was " + this.value);
this.assertEquals(expected, (Supplier<String>) null);
}
public void assertEquals(T expected, String message) {
this.assertEquals(expected, message != null ? () -> message : null);
}
public void assertEquals(T expected, Supplier<String> message) {
assertSet(message);
if (expected != null && !expected.equals(this.value)) {
String s = message != null ? message.get() + " -- " : "";
throw new GameTestAssertException(s + "Expected " + name + " to be " + expected + ", but was " + this.value);
}
}
}
@@ -244,9 +318,29 @@ public interface IForgeGameTestHelper {
return this.value == null ? -1 : this.value.longValue();
}
public void assertEquals(int expected) {
super.assertEquals((long) expected);
}
public void assertEquals(long expected) {
super.assertEquals(expected);
}
public void assertEquals(int expected, String message) {
super.assertEquals((long) expected, message);
}
public void assertEquals(long expected, String message) {
super.assertEquals(expected, message);
}
public void assertEquals(int expected, Supplier<String> message) {
super.assertEquals((long) expected, message);
}
public void assertEquals(long expected, Supplier<String> message) {
super.assertEquals(expected, message);
}
}
public static class BoolFlag extends Flag<Boolean> {
@@ -265,5 +359,13 @@ public interface IForgeGameTestHelper {
public void assertEquals(boolean expected) {
super.assertEquals(expected);
}
public void assertEquals(boolean expected, String message) {
super.assertEquals(expected, message);
}
public void assertEquals(boolean expected, Supplier<String> message) {
super.assertEquals(expected, message);
}
}
}
@@ -7,6 +7,8 @@ package net.minecraftforge.common.extensions;
import java.util.function.Consumer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.item.*;
@@ -481,6 +483,28 @@ public interface IForgeItem {
*/
default void onHorseArmorTick(ItemStack stack, Level level, Mob horse) { }
/**
* Called when this item is to be damaged, such as use a tool being used or a shield blocking damage. The damage
* parameter has not yet been processed, so enchantments are not taken into account.
*
* @param stack The processed amount of damage the item will take
* @param damage The amount of damage the item will take before processing
* @param level The level where the damage is taking place
* @param player The player holding the item
* @param canBreak If the item can break from this damage instance ({@code true} if this is called from
* {@link ItemStack#hurtAndBreak(int, ServerLevel, ServerPlayer, Consumer)}, {@code false} if from
* {@link ItemStack#hurtWithoutBreaking(int, Player)})
* @param onBroken The callback for when an item is broken (use this if you plan on cancelling damage that will
* break an item)
* @return The amount of damage the item should take, after processing
*
* @apiNote If the item stack is not {@linkplain ItemStack#isDamageableItem() damageable} or the player
* {@linkplain Player#hasInfiniteMaterials() has infinite materials}, this method will not be called.
*/
default int damageItem(ItemStack stack, int damage, ServerLevel level, @Nullable ServerPlayer player, boolean canBreak, Consumer<Item> onBroken) {
return damage;
}
/**
* Called when an item entity for this stack is destroyed. Note: The {@link ItemStack} can be retrieved from the item entity.
*
@@ -5,6 +5,8 @@
package net.minecraftforge.common.extensions;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.player.Inventory;
@@ -32,6 +34,8 @@ import net.minecraftforge.common.ToolActions;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Consumer;
/*
* Extension added to ItemStack that bounces to ItemSack sensitive Item methods. Typically this is just for convince.
*/
@@ -377,6 +381,28 @@ public interface IForgeItemStack {
return self().getItem().getSweepHitBox(self(), player, target);
}
/**
* Called when this item is to be damaged, such as use a tool being used or a shield blocking damage. The damage
* parameter has not yet been processed, so enchantments are not taken into account.
*
* @param damage The amount of damage the item will take before processing
* @param level The level where the damage is taking place
* @param player The player holding the item
* @param canBreak If the item can break from this damage instance ({@code true} if this is called from
* {@link ItemStack#hurtAndBreak(int, ServerLevel, ServerPlayer, Consumer)}, {@code false} if from
* {@link ItemStack#hurtWithoutBreaking(int, Player)})
* @param onBroken The callback for when an item is broken (use this if you plan on cancelling damage that will
* break an item)
* @return The amount of damage the item should take
*
* @apiNote If the item stack is not {@linkplain ItemStack#isDamageableItem() damageable} or the player
* {@linkplain Player#hasInfiniteMaterials() has infinite materials}, this method will not be called.
* @see IForgeItem#damageItem(ItemStack, int, ServerLevel, ServerPlayer, boolean, Consumer)
*/
default int damageItem(int damage, ServerLevel level, @Nullable ServerPlayer player, boolean canBreak, Consumer<Item> onBroken) {
return self().getItem().damageItem(self(), damage, level, player, canBreak, onBroken);
}
/**
* Called when an item entity for this stack is destroyed. Note: The {@link ItemStack} can be retrieved from the item entity.
*