From dbd7da6885a6a5287ab3fb2ee0a9e3ab8dbfa4e6 Mon Sep 17 00:00:00 2001 From: Jonathing Date: Mon, 27 Jan 2025 22:12:47 -0500 Subject: [PATCH] Fix issue with shields not disabling correctly (#10320) --- .../minecraft/world/item/AxeItem.java.patch | 7 +- .../extensions/IForgeGameTestHelper.java | 22 ++++++ .../common/extensions/IForgeItem.java | 2 +- .../gameplay/item/ShieldDisablingTest.java | 71 +++++++++++++++++++ 4 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 src/test/java/net/minecraftforge/debug/gameplay/item/ShieldDisablingTest.java diff --git a/patches/minecraft/net/minecraft/world/item/AxeItem.java.patch b/patches/minecraft/net/minecraft/world/item/AxeItem.java.patch index d3a9bed7b2..4cfd53e9e2 100644 --- a/patches/minecraft/net/minecraft/world/item/AxeItem.java.patch +++ b/patches/minecraft/net/minecraft/world/item/AxeItem.java.patch @@ -10,7 +10,7 @@ if (optional.isEmpty()) { return InteractionResult.PASS; } else { -@@ -79,9 +_,20 @@ +@@ -79,9 +_,25 @@ } } @@ -29,5 +29,10 @@ + @Override + public boolean canPerformAction(ItemStack stack, net.minecraftforge.common.ToolAction toolAction) { + return net.minecraftforge.common.ToolActions.DEFAULT_AXE_ACTIONS.contains(toolAction); ++ } ++ ++ @Override ++ public boolean canDisableShield(ItemStack stack, ItemStack shield, net.minecraft.world.entity.LivingEntity entity, net.minecraft.world.entity.LivingEntity attacker) { ++ return true; } } diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeGameTestHelper.java b/src/main/java/net/minecraftforge/common/extensions/IForgeGameTestHelper.java index 688493825f..e4d7e6080c 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeGameTestHelper.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeGameTestHelper.java @@ -9,6 +9,8 @@ import java.util.UUID; import java.util.function.Consumer; import java.util.function.Supplier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.GameType; import org.jetbrains.annotations.Nullable; import com.mojang.authlib.GameProfile; @@ -59,6 +61,26 @@ public interface IForgeGameTestHelper { throw new GameTestAssertException(message.get()); } + // Backported from 1.20.6 + default Player makeMockPlayer(final GameType p_333981_) { + return new Player(this.self().getLevel(), BlockPos.ZERO, 0.0F, new GameProfile(UUID.randomUUID(), "test-mock-player")) { + @Override + public boolean isSpectator() { + return p_333981_ == GameType.SPECTATOR; + } + + @Override + public boolean isCreative() { + return p_333981_.isCreative(); + } + + @Override + public boolean isLocalPlayer() { + return true; + } + }; + } + default ServerPlayer makeMockServerPlayer() { var level = self().getLevel(); var cookie = CommonListenerCookie.createInitial(new GameProfile(UUID.randomUUID(), "test-mock-player")); diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeItem.java b/src/main/java/net/minecraftforge/common/extensions/IForgeItem.java index 3d38e22362..bfe63233e3 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeItem.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeItem.java @@ -644,7 +644,7 @@ public interface IForgeItem { * @return True if this ItemStack can disable the shield in question. */ default boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { - return this instanceof AxeItem; + return attacker.canDisableShield(); } /** diff --git a/src/test/java/net/minecraftforge/debug/gameplay/item/ShieldDisablingTest.java b/src/test/java/net/minecraftforge/debug/gameplay/item/ShieldDisablingTest.java new file mode 100644 index 0000000000..3efde936b9 --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/gameplay/item/ShieldDisablingTest.java @@ -0,0 +1,71 @@ +package net.minecraftforge.debug.gameplay.item; + +import net.minecraft.Util; +import net.minecraft.commands.arguments.EntityAnchorArgument; +import net.minecraft.core.BlockPos; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.GameType; +import net.minecraftforge.event.entity.living.LivingEntityUseItemEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.gametest.GameTestHolder; +import net.minecraftforge.test.BaseTestMod; + +import java.util.function.Function; + +@Mod(ShieldDisablingTest.MOD_ID) +@GameTestHolder("forge." + ShieldDisablingTest.MOD_ID) +public final class ShieldDisablingTest extends BaseTestMod { + public static final String MOD_ID = "shield_disabling"; + + public ShieldDisablingTest() { } + + @GameTest(template = "forge:empty3x3x3") + public static void player_shield_disabled_by_axe(GameTestHelper helper) { + player_shield_disabled_common(helper, h -> Util.make( + h.spawnWithNoFreeWill(EntityType.HUSK, new BlockPos(2, 0, 2)), + enemy -> enemy.setItemInHand(InteractionHand.MAIN_HAND, new ItemStack(Items.IRON_AXE)) + )); + } + + @GameTest(template = "forge:empty3x3x3") + public static void player_shield_disabled_by_warden(GameTestHelper helper) { + player_shield_disabled_common(helper, h -> h.spawnWithNoFreeWill(EntityType.WARDEN, new BlockPos(2, 0, 2))); + } + + private static void player_shield_disabled_common(GameTestHelper helper, Function enemyGetter) { + helper.makeFloor(); + + // setup player + var player = helper.makeMockPlayer(GameType.SURVIVAL); + helper.addEventListener(event -> { + // Artificially pass 5 seconds from start of the shield + // This is because the first 5 ticks, the player is still vulnerable + if (event.getEntity() == player) { + event.setDuration(event.getDuration() - 100); + } + }); + + // start using shield + var shield = Items.SHIELD.getDefaultInstance(); + player.setItemInHand(InteractionHand.MAIN_HAND, shield); + player.startUsingItem(InteractionHand.MAIN_HAND); + + // setup enemy + var enemy = enemyGetter.apply(helper); + player.lookAt(EntityAnchorArgument.Anchor.EYES, enemy.position()); + + // hit the player + player.hurt(enemy.damageSources().mobAttack(enemy), 5.0F); + + // shield on cooldown? + helper.assertTrue(player.getCooldowns().isOnCooldown(shield.getItem()), "shield should be on cooldown"); + helper.succeed(); + } +}