From 2c35d0449503c8b9e2f1c0c6d6788e74b71eb220 Mon Sep 17 00:00:00 2001 From: Brennan Ward Date: Thu, 20 Jan 2022 16:43:22 -0500 Subject: [PATCH] Add ShieldBlockEvent (#8261) --- .../world/entity/LivingEntity.java.patch | 23 ++++ .../net/minecraftforge/common/ForgeHooks.java | 10 +- .../event/entity/living/ShieldBlockEvent.java | 101 ++++++++++++++++++ .../debug/item/ShieldBlockTest.java | 52 +++++++++ src/test/resources/META-INF/mods.toml | 2 + 5 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/minecraftforge/event/entity/living/ShieldBlockEvent.java create mode 100644 src/test/java/net/minecraftforge/debug/item/ShieldBlockTest.java diff --git a/patches/minecraft/net/minecraft/world/entity/LivingEntity.java.patch b/patches/minecraft/net/minecraft/world/entity/LivingEntity.java.patch index 139e3ebb6c..45641c4a44 100644 --- a/patches/minecraft/net/minecraft/world/entity/LivingEntity.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/LivingEntity.java.patch @@ -123,6 +123,29 @@ if (this.m_6673_(p_21016_)) { return false; } else if (this.f_19853_.f_46443_) { +@@ -998,9 +_,11 @@ + boolean flag = false; + float f1 = 0.0F; + if (p_21017_ > 0.0F && this.m_21275_(p_21016_)) { +- this.m_7909_(p_21017_); +- f1 = p_21017_; +- p_21017_ = 0.0F; ++ net.minecraftforge.event.entity.living.ShieldBlockEvent ev = net.minecraftforge.common.ForgeHooks.onShieldBlock(this, p_21016_, p_21017_); ++ if(!ev.isCanceled()) { ++ if(ev.shieldTakesDamage()) this.m_7909_(p_21017_); ++ f1 = ev.getBlockedDamage(); ++ p_21017_ -= ev.getBlockedDamage(); + if (!p_21016_.m_19360_()) { + Entity entity = p_21016_.m_7640_(); + if (entity instanceof LivingEntity) { +@@ -1010,6 +_,7 @@ + + flag = true; + } ++ } + + this.f_20924_ = 1.5F; + boolean flag1 = true; @@ -1044,11 +_,11 @@ if (entity1 instanceof Player) { this.f_20889_ = 100; diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index 32fa24e675..59ddd6cf5e 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -153,6 +153,7 @@ import net.minecraftforge.event.entity.living.LivingHurtEvent; import net.minecraftforge.event.entity.living.LivingKnockBackEvent; import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent; import net.minecraftforge.event.entity.living.LootingLevelEvent; +import net.minecraftforge.event.entity.living.ShieldBlockEvent; import net.minecraftforge.event.entity.player.AdvancementEvent; import net.minecraftforge.event.entity.player.AnvilRepairEvent; import net.minecraftforge.event.entity.player.AttackEntityEvent; @@ -1257,7 +1258,14 @@ public class ForgeHooks { MinecraftForge.EVENT_BUS.post(new EntityEvent.EnteringSection(entity, packedOldPos, packedNewPos)); } - + + public static ShieldBlockEvent onShieldBlock(LivingEntity blocker, DamageSource source, float blocked) + { + ShieldBlockEvent e = new ShieldBlockEvent(blocker, source, blocked); + MinecraftForge.EVENT_BUS.post(e); + return e; + } + /** * Called when dimension jsons are parsed. * Creates a copy of the worldgen settings and its dimension registry, diff --git a/src/main/java/net/minecraftforge/event/entity/living/ShieldBlockEvent.java b/src/main/java/net/minecraftforge/event/entity/living/ShieldBlockEvent.java new file mode 100644 index 0000000000..6f6b0f9e01 --- /dev/null +++ b/src/main/java/net/minecraftforge/event/entity/living/ShieldBlockEvent.java @@ -0,0 +1,101 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2021. + * + * This library 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 version 2.1 + * of the License. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.event.entity.living; + +import net.minecraft.util.Mth; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.LivingEntity; +import net.minecraftforge.eventbus.api.Cancelable; + +/** + * The ShieldBlockEvent is fired when an entity successfully blocks with a shield.
+ * Cancelling this event will have the same impact as if the shield was not eligible to block.
+ * The damage blocked cannot be set lower than zero or greater than the original value.
+ * Note: The shield item stack "should" be available from {@link LivingEntity#getUseItem()} + * at least for players. + */ +@Cancelable +public class ShieldBlockEvent extends LivingEvent +{ + private final DamageSource source; + private final float originalBlocked; + private float dmgBlocked; + private boolean shieldTakesDamage = true; + + public ShieldBlockEvent(LivingEntity blocker, DamageSource source, float blocked) + { + super(blocker); + this.source = source; + this.originalBlocked = blocked; + this.dmgBlocked = blocked; + } + + /** + * @return The damage source. + */ + public DamageSource getDamageSource() + { + return this.source; + } + + /** + * @return The original amount of damage blocked, which is the same as the original + * incoming damage value. + */ + public float getOriginalBlockedDamage() + { + return this.originalBlocked; + } + + /** + * @return The current amount of damage blocked, as a result of this event. + */ + public float getBlockedDamage() + { + return this.dmgBlocked; + } + + /** + * Controls if {@link LivingEntity#hurtCurrentlyUsedShield} is called. + * @return If the shield item will take durability damage or not. + */ + public boolean shieldTakesDamage() + { + return this.shieldTakesDamage; + } + + /** + * Set how much damage is blocked by this action.
+ * Note that initially the blocked amount is the entire attack.
+ */ + public void setBlockedDamage(float blocked) + { + this.dmgBlocked = Mth.clamp(blocked, 0, this.originalBlocked); + } + + /** + * Set if the shield will take durability damage or not. + */ + public void setShieldTakesDamage(boolean damage) + { + this.shieldTakesDamage = damage; + } + +} diff --git a/src/test/java/net/minecraftforge/debug/item/ShieldBlockTest.java b/src/test/java/net/minecraftforge/debug/item/ShieldBlockTest.java new file mode 100644 index 0000000000..a11fd2a5ca --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/item/ShieldBlockTest.java @@ -0,0 +1,52 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2021. + * + * This library 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 version 2.1 + * of the License. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.debug.item; + +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.AbstractArrow; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraftforge.event.entity.living.ShieldBlockEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +/** + * The ShieldBlockTest is the test mod for the ShieldBlockEvent. + * If successful, this handler will trigger when an arrow is blocked by a player. + * The event will give the arrow to the player, and make the player receive half of the damage (instead of zero damage). + * Note this just gives them a normal arrow, retrieving the true arrow requires some reflection. + */ +@Mod(ShieldBlockTest.MOD_ID) +@Mod.EventBusSubscriber +public class ShieldBlockTest +{ + static final String MOD_ID = "shield_block_event"; + + @SubscribeEvent + public static void shieldBlock(ShieldBlockEvent event) + { + if (event.getDamageSource().getDirectEntity() instanceof AbstractArrow arrow && event.getEntityLiving() instanceof Player player) + { + player.getInventory().add(new ItemStack(Items.ARROW)); + event.setBlockedDamage(event.getOriginalBlockedDamage() / 2); + arrow.discard(); + } + } +} diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml index d305624ab0..53f90826ae 100644 --- a/src/test/resources/META-INF/mods.toml +++ b/src/test/resources/META-INF/mods.toml @@ -178,6 +178,8 @@ license="LGPL v2.1" modId="duplicate_optional_tag_test" [[mods]] modId="custom_particle_type_test" +[[mods]] + modId="shield_block_event" [[mods]] modId="renderable_test" [[mods]]