diff --git a/patches/minecraft/net/minecraft/entity/EntityLivingBase.java.patch b/patches/minecraft/net/minecraft/entity/EntityLivingBase.java.patch index 7d5caa9c76..14d681529c 100644 --- a/patches/minecraft/net/minecraft/entity/EntityLivingBase.java.patch +++ b/patches/minecraft/net/minecraft/entity/EntityLivingBase.java.patch @@ -177,7 +177,7 @@ this.func_184185_a(soundtype.func_185842_g(), soundtype.func_185843_a() * 0.5F, soundtype.func_185847_b() * 0.75F); } } -@@ -1380,6 +1395,8 @@ +@@ -1380,17 +1395,20 @@ { if (!this.func_180431_b(p_70665_1_)) { @@ -186,7 +186,10 @@ p_70665_2_ = this.func_70655_b(p_70665_1_, p_70665_2_); p_70665_2_ = this.func_70672_c(p_70665_1_, p_70665_2_); float f = p_70665_2_; -@@ -1389,8 +1406,8 @@ + p_70665_2_ = Math.max(p_70665_2_ - this.func_110139_bj(), 0.0F); + this.func_110149_m(this.func_110139_bj() - (f - p_70665_2_)); ++ p_70665_2_ = net.minecraftforge.common.ForgeHooks.onLivingDamage(this, p_70665_1_, p_70665_2_); + if (p_70665_2_ != 0.0F) { float f1 = this.func_110143_aJ(); @@ -196,7 +199,7 @@ this.func_110149_m(this.func_110139_bj() - p_70665_2_); } } -@@ -1447,6 +1464,11 @@ +@@ -1447,6 +1465,11 @@ public void func_184609_a(EnumHand p_184609_1_) { @@ -208,7 +211,7 @@ if (!this.field_82175_bq || this.field_110158_av >= this.func_82166_i() / 2 || this.field_110158_av < 0) { this.field_110158_av = -1; -@@ -1694,7 +1716,7 @@ +@@ -1694,7 +1717,7 @@ if (!this.field_70170_p.func_184143_b(axisalignedbb1)) { @@ -217,7 +220,7 @@ { this.func_70634_a(d11, this.field_70163_u + 1.0D, d12); return; -@@ -1702,14 +1724,14 @@ +@@ -1702,14 +1725,14 @@ BlockPos blockpos = new BlockPos(d11, this.field_70163_u - 1.0D, d12); @@ -234,7 +237,7 @@ { d1 = d11; d13 = this.field_70163_u + 2.0D; -@@ -1781,6 +1803,7 @@ +@@ -1781,6 +1804,7 @@ } this.field_70160_al = true; @@ -242,7 +245,7 @@ } protected void func_70629_bd() -@@ -1874,7 +1897,8 @@ +@@ -1874,7 +1898,8 @@ if (this.field_70122_E) { @@ -252,7 +255,7 @@ } float f7 = 0.16277136F / (f6 * f6 * f6); -@@ -1894,7 +1918,8 @@ +@@ -1894,7 +1919,8 @@ if (this.field_70122_E) { @@ -262,7 +265,7 @@ } if (this.func_70617_f_()) -@@ -2054,6 +2079,7 @@ +@@ -2054,6 +2080,7 @@ public void func_70071_h_() { @@ -270,7 +273,7 @@ super.func_70071_h_(); this.func_184608_ct(); -@@ -2096,7 +2122,9 @@ +@@ -2096,7 +2123,9 @@ if (!ItemStack.func_77989_b(itemstack1, itemstack)) { @@ -280,7 +283,7 @@ if (!itemstack.func_190926_b()) { -@@ -2575,6 +2603,40 @@ +@@ -2575,6 +2604,40 @@ this.field_70752_e = true; } @@ -321,7 +324,7 @@ public abstract EnumHandSide func_184591_cq(); public boolean func_184587_cr() -@@ -2595,12 +2657,19 @@ +@@ -2595,12 +2658,19 @@ if (itemstack == this.field_184627_bm) { @@ -342,7 +345,7 @@ { this.func_71036_o(); } -@@ -2618,8 +2687,10 @@ +@@ -2618,8 +2688,10 @@ if (!itemstack.func_190926_b() && !this.func_184587_cr()) { @@ -354,7 +357,7 @@ if (!this.field_70170_p.field_72995_K) { -@@ -2700,7 +2771,9 @@ +@@ -2700,7 +2772,9 @@ if (!this.field_184627_bm.func_190926_b() && this.func_184587_cr()) { this.func_184584_a(this.field_184627_bm, 16); @@ -365,7 +368,7 @@ this.func_184602_cy(); } } -@@ -2724,7 +2797,8 @@ +@@ -2724,7 +2798,8 @@ { if (!this.field_184627_bm.func_190926_b()) { @@ -375,7 +378,7 @@ } this.func_184602_cy(); -@@ -2852,6 +2926,31 @@ +@@ -2852,6 +2927,31 @@ return true; } diff --git a/patches/minecraft/net/minecraft/entity/player/EntityPlayer.java.patch b/patches/minecraft/net/minecraft/entity/player/EntityPlayer.java.patch index 7abbbab2cc..9f62c6b2be 100644 --- a/patches/minecraft/net/minecraft/entity/player/EntityPlayer.java.patch +++ b/patches/minecraft/net/minecraft/entity/player/EntityPlayer.java.patch @@ -233,7 +233,7 @@ if (enumhand == EnumHand.MAIN_HAND) { -@@ -1045,7 +1117,10 @@ +@@ -1045,11 +1117,15 @@ { if (!this.func_180431_b(p_70665_1_)) { @@ -245,7 +245,12 @@ p_70665_2_ = this.func_70672_c(p_70665_1_, p_70665_2_); float f = p_70665_2_; p_70665_2_ = Math.max(p_70665_2_ - this.func_110139_bj(), 0.0F); -@@ -1115,6 +1190,8 @@ + this.func_110149_m(this.func_110139_bj() - (f - p_70665_2_)); ++ p_70665_2_ = net.minecraftforge.common.ForgeHooks.onLivingDamage(this, p_70665_1_, p_70665_2_); + + if (p_70665_2_ != 0.0F) + { +@@ -1115,6 +1191,8 @@ } else { @@ -254,7 +259,7 @@ ItemStack itemstack = this.func_184586_b(p_190775_2_); ItemStack itemstack1 = itemstack.func_190926_b() ? ItemStack.field_190927_a : itemstack.func_77946_l(); -@@ -1124,7 +1201,10 @@ +@@ -1124,7 +1202,10 @@ { itemstack.func_190920_e(itemstack1.func_190916_E()); } @@ -266,7 +271,7 @@ return EnumActionResult.SUCCESS; } else -@@ -1140,6 +1220,7 @@ +@@ -1140,6 +1221,7 @@ { if (itemstack.func_190926_b() && !this.field_71075_bZ.field_75098_d) { @@ -274,7 +279,7 @@ this.func_184611_a(p_190775_2_, ItemStack.field_190927_a); } -@@ -1165,6 +1246,7 @@ +@@ -1165,6 +1247,7 @@ public void func_71059_n(Entity p_71059_1_) { @@ -282,7 +287,7 @@ if (p_71059_1_.func_70075_an()) { if (!p_71059_1_.func_85031_j(this)) -@@ -1203,9 +1285,11 @@ +@@ -1203,9 +1286,11 @@ boolean flag2 = flag && this.field_70143_R > 0.0F && !this.field_70122_E && !this.func_70617_f_() && !this.func_70090_H() && !this.func_70644_a(MobEffects.field_76440_q) && !this.func_184218_aH() && p_71059_1_ instanceof EntityLivingBase; flag2 = flag2 && !this.func_70051_ag(); @@ -295,7 +300,7 @@ } f = f + f1; -@@ -1332,10 +1416,12 @@ +@@ -1332,10 +1417,12 @@ if (!itemstack1.func_190926_b() && entity instanceof EntityLivingBase) { @@ -308,7 +313,7 @@ this.func_184611_a(EnumHand.MAIN_HAND, ItemStack.field_190927_a); } } -@@ -1384,7 +1470,7 @@ +@@ -1384,7 +1471,7 @@ if (this.field_70146_Z.nextFloat() < f) { @@ -317,7 +322,7 @@ this.func_184602_cy(); this.field_70170_p.func_72960_a(this, (byte)30); } -@@ -1442,6 +1528,8 @@ +@@ -1442,6 +1529,8 @@ public EntityPlayer.SleepResult func_180469_a(BlockPos p_180469_1_) { @@ -326,7 +331,7 @@ EnumFacing enumfacing = (EnumFacing)this.field_70170_p.func_180495_p(p_180469_1_).func_177229_b(BlockHorizontal.field_185512_D); if (!this.field_70170_p.field_72995_K) -@@ -1484,8 +1572,9 @@ +@@ -1484,8 +1573,9 @@ this.func_192030_dh(); this.func_70105_a(0.2F, 0.2F); @@ -338,7 +343,7 @@ float f1 = 0.5F + (float)enumfacing.func_82601_c() * 0.4F; float f = 0.5F + (float)enumfacing.func_82599_e() * 0.4F; this.func_175139_a(enumfacing); -@@ -1532,13 +1621,14 @@ +@@ -1532,13 +1622,14 @@ public void func_70999_a(boolean p_70999_1_, boolean p_70999_2_, boolean p_70999_3_) { @@ -356,7 +361,7 @@ if (blockpos == null) { -@@ -1547,6 +1637,10 @@ +@@ -1547,6 +1638,10 @@ this.func_70107_b((double)((float)blockpos.func_177958_n() + 0.5F), (double)((float)blockpos.func_177956_o() + 0.1F), (double)((float)blockpos.func_177952_p() + 0.5F)); } @@ -367,7 +372,7 @@ this.field_71083_bS = false; -@@ -1565,15 +1659,16 @@ +@@ -1565,15 +1660,16 @@ private boolean func_175143_p() { @@ -387,7 +392,7 @@ { if (!p_180467_2_) { -@@ -1588,16 +1683,17 @@ +@@ -1588,16 +1684,17 @@ } else { @@ -408,7 +413,7 @@ switch (enumfacing) { -@@ -1637,16 +1733,24 @@ +@@ -1637,16 +1734,24 @@ public BlockPos func_180470_cg() { @@ -435,7 +440,7 @@ if (p_180473_1_ != null) { this.field_71077_c = p_180473_1_; -@@ -1839,6 +1943,10 @@ +@@ -1839,6 +1944,10 @@ super.func_180430_e(p_180430_1_, p_180430_2_); } @@ -446,7 +451,7 @@ } protected void func_71061_d_() -@@ -2176,7 +2284,10 @@ +@@ -2176,7 +2285,10 @@ public ITextComponent func_145748_c_() { @@ -458,7 +463,7 @@ itextcomponent.func_150256_b().func_150241_a(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/msg " + this.func_70005_c_() + " ")); itextcomponent.func_150256_b().func_150209_a(this.func_174823_aP()); itextcomponent.func_150256_b().func_179989_a(this.func_70005_c_()); -@@ -2185,7 +2296,7 @@ +@@ -2185,7 +2297,7 @@ public float func_70047_e() { @@ -467,7 +472,7 @@ if (this.func_70608_bn()) { -@@ -2421,6 +2532,168 @@ +@@ -2421,6 +2533,168 @@ return this.field_71075_bZ.field_75098_d && this.func_70003_b(2, ""); } diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index 1ca656a10d..3b09e21a7b 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -113,6 +113,7 @@ import net.minecraftforge.event.ServerChatEvent; import net.minecraftforge.event.entity.EntityTravelToDimensionEvent; import net.minecraftforge.event.entity.item.ItemTossEvent; import net.minecraftforge.event.entity.living.LivingAttackEvent; +import net.minecraftforge.event.entity.living.LivingDamageEvent; import net.minecraftforge.event.entity.living.LivingDeathEvent; import net.minecraftforge.event.entity.living.LivingDropsEvent; import net.minecraftforge.event.entity.living.LivingEvent.LivingJumpEvent; @@ -564,6 +565,12 @@ public class ForgeHooks return (MinecraftForge.EVENT_BUS.post(event) ? 0 : event.getAmount()); } + public static float onLivingDamage(EntityLivingBase entity, DamageSource src, float amount) + { + LivingDamageEvent event = new LivingDamageEvent(entity, src, amount); + return (MinecraftForge.EVENT_BUS.post(event) ? 0 : event.getAmount()); + } + public static boolean onLivingDeath(EntityLivingBase entity, DamageSource src) { return MinecraftForge.EVENT_BUS.post(new LivingDeathEvent(entity, src)); diff --git a/src/main/java/net/minecraftforge/event/entity/living/LivingDamageEvent.java b/src/main/java/net/minecraftforge/event/entity/living/LivingDamageEvent.java new file mode 100644 index 0000000000..780f4edad3 --- /dev/null +++ b/src/main/java/net/minecraftforge/event/entity/living/LivingDamageEvent.java @@ -0,0 +1,64 @@ +/* + * Minecraft Forge + * Copyright (c) 2017. + * + * 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.entity.player.EntityPlayer; +import net.minecraftforge.common.ForgeHooks; +import net.minecraftforge.fml.common.eventhandler.Cancelable; +import net.minecraft.util.DamageSource; +import net.minecraft.entity.EntityLivingBase; + +/** + * LivingDamageEvent is fired just before damage is applied to entity.
+ * At this point armor, potion and absorption modifiers have already been applied to damage - this is FINAL value.
+ * Also note that appropriate resources (like armor durability and absorption extra hearths) have already been consumed.
+ * This event is fired whenever an Entity is damaged in + * {@link EntityLivingBase#damageEntity(DamageSource, float)} and + * {@link EntityPlayer#damageEntity(DamageSource, float)}.
+ *
+ * This event is fired via the {@link ForgeHooks#onLivingDamage(EntityLivingBase, DamageSource, float)}.
+ *
+ * {@link #source} contains the DamageSource that caused this Entity to be hurt.
+ * {@link #amount} contains the final amount of damage that will be dealt to entity.
+ *
+ * This event is {@link Cancelable}.
+ * If this event is canceled, the Entity is not hurt. Used resources WILL NOT be restored.
+ *
+ * This event does not have a result. {@link HasResult}
+ * @see LivingHurtEvent + **/ +@Cancelable +public class LivingDamageEvent extends LivingEvent +{ + private final DamageSource source; + private float amount; + public LivingDamageEvent(EntityLivingBase entity, DamageSource source, float amount) + { + super(entity); + this.source = source; + this.amount = amount; + } + + public DamageSource getSource() { return source; } + + public float getAmount() { return amount; } + + public void setAmount(float amount) { this.amount = amount; } +} diff --git a/src/main/java/net/minecraftforge/event/entity/living/LivingHurtEvent.java b/src/main/java/net/minecraftforge/event/entity/living/LivingHurtEvent.java index a3c0a84e0d..11c4a2a4a7 100644 --- a/src/main/java/net/minecraftforge/event/entity/living/LivingHurtEvent.java +++ b/src/main/java/net/minecraftforge/event/entity/living/LivingHurtEvent.java @@ -43,6 +43,7 @@ import net.minecraft.entity.EntityLivingBase; * This event does not have a result. {@link HasResult}
*
* This event is fired on the {@link MinecraftForge#EVENT_BUS}. + * @see LivingDamageEvent **/ @Cancelable public class LivingHurtEvent extends LivingEvent diff --git a/src/test/java/net/minecraftforge/debug/LivingDamageEventTest.java b/src/test/java/net/minecraftforge/debug/LivingDamageEventTest.java new file mode 100644 index 0000000000..8ac95e0d2d --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/LivingDamageEventTest.java @@ -0,0 +1,152 @@ +package net.minecraftforge.debug; + +import com.google.common.collect.ImmutableMap; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import javax.annotation.Nullable; +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.WrongUsageException; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.DamageSource; +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.event.entity.living.LivingDamageEvent; +import net.minecraftforge.event.entity.living.LivingHurtEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.fml.common.Mod.EventHandler; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import net.minecraftforge.fml.common.event.FMLServerStartingEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import org.apache.logging.log4j.Logger; + +@Mod(modid = LivingDamageEventTest.MODID, name = "ForgeDebugLivingDamage", version = "1.0", acceptableRemoteVersions = "*") +public class LivingDamageEventTest +{ + + private static Logger logger; + + public static final String MODID = "forgedebuglivingdamage"; + + private static final Map DAMAGE_SOURCES = ImmutableMap. builder() + .put("fire", DamageSource.IN_FIRE) + .put("lightning_bolt", DamageSource.LIGHTNING_BOLT) + .put("on_fire", DamageSource.ON_FIRE) + .put("lava", DamageSource.LAVA) + .put("hot_floor", DamageSource.HOT_FLOOR) + .put("in_wall", DamageSource.IN_WALL) + .put("cramming", DamageSource.CRAMMING) + .put("drown", DamageSource.DROWN) + .put("starve", DamageSource.STARVE) + .put("cactus", DamageSource.CACTUS) + .put("fall", DamageSource.FALL) + .put("fly_into_wall", DamageSource.FLY_INTO_WALL) + .put("out_of_world", DamageSource.OUT_OF_WORLD) + .put("generic", DamageSource.GENERIC) + .put("magic", DamageSource.MAGIC) + .put("wither", DamageSource.WITHER) + .put("anvil", DamageSource.ANVIL) + .put("falling_block", DamageSource.FALLING_BLOCK) + .put("dragon_breath", DamageSource.DRAGON_BREATH) + .put("fireworks", DamageSource.FIREWORKS) + .build(); + + private static class CommandDamage extends CommandBase + { + + private static final String USAGE = "damage "; + + @Override + public String getName() + { + return "damage"; + } + + @Override + public String getUsage(ICommandSender sender) + { + return USAGE; + } + + @Override + public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException + { + if (args.length < 3) + { + throw new WrongUsageException(USAGE); + } + + EntityLivingBase target = getEntity(server, sender, args[0], EntityLivingBase.class); + DamageSource damageSource = DAMAGE_SOURCES.get(args[1].toLowerCase(Locale.ROOT)); + if (target == null || damageSource == null) + { + throw new WrongUsageException(USAGE); + } + + float amount; + try + { + amount = Float.parseFloat(args[2]); + } catch (NumberFormatException e) + { + throw new WrongUsageException(USAGE); + } + + target.attackEntityFrom(damageSource, amount); + } + + @Override + public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos) + { + if (args.length == 1) + { + return getListOfStringsMatchingLastWord(args, server.getOnlinePlayerNames()); + } else if (args.length == 2) + { + return getListOfStringsMatchingLastWord(args, DAMAGE_SOURCES.keySet()); + } + + return Collections.emptyList(); + } + + @Override + public boolean isUsernameIndex(String[] args, int index) + { + return index == 0; + } + } + + @EventHandler + public void preInit(FMLPreInitializationEvent event) + { + logger = event.getModLog(); + } + + @EventHandler + void serverStarting(FMLServerStartingEvent evt) + { + evt.registerServerCommand(new CommandDamage()); + } + + @EventBusSubscriber + public static class TestEventHandler + { + + @SubscribeEvent + public static void livingHurtPre(LivingHurtEvent evt) + { + logger.info("Entity {} damage from {} (pre-reduction): {}", evt.getEntity(), evt.getSource().getDamageType(), evt.getAmount()); + } + + @SubscribeEvent + public static void livingHurtPost(LivingDamageEvent evt) + { + logger.info("Entity {} damage from {} (post-reduction): {}", evt.getEntity(), evt.getSource().getDamageType(), evt.getAmount()); + } + + } +}