From 46f0dde817f09acf56759fbb5b081ffd7c9d0d95 Mon Sep 17 00:00:00 2001 From: CraftBukkit/Spigot Date: Mon, 3 Jan 2022 18:07:01 +0100 Subject: [PATCH] SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Only cancel knockback if the damage event was canceled By: DerFrZocker --- .../net/minecraft/world/entity/Entity.patch | 2 +- .../minecraft/world/entity/EntityLiving.patch | 47 +++++++++--------- .../world/entity/player/EntityHuman.patch | 49 ++++++++----------- .../net/minecraft/world/level/Explosion.patch | 47 +++++++++++++----- .../craftbukkit/event/CraftEventFactory.java | 12 +++++ 5 files changed, 91 insertions(+), 66 deletions(-) diff --git a/paper-server/nms-patches/net/minecraft/world/entity/Entity.patch b/paper-server/nms-patches/net/minecraft/world/entity/Entity.patch index 07ea2feb72..8f7a15da33 100644 --- a/paper-server/nms-patches/net/minecraft/world/entity/Entity.patch +++ b/paper-server/nms-patches/net/minecraft/world/entity/Entity.patch @@ -69,7 +69,7 @@ + public boolean valid; + public boolean generation; + public org.bukkit.projectiles.ProjectileSource projectileSource; // For projectiles only -+ public boolean forceExplosionKnockback; // SPIGOT-949 ++ public boolean lastDamageCancelled; // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Keep track if the event was canceled + public boolean persistentInvisibility = false; + public BlockPosition lastLavaContact; + diff --git a/paper-server/nms-patches/net/minecraft/world/entity/EntityLiving.patch b/paper-server/nms-patches/net/minecraft/world/entity/EntityLiving.patch index 88102a2ada..09e91c5625 100644 --- a/paper-server/nms-patches/net/minecraft/world/entity/EntityLiving.patch +++ b/paper-server/nms-patches/net/minecraft/world/entity/EntityLiving.patch @@ -388,14 +388,13 @@ this.hurtCurrentlyUsedShield(f); f2 = f; f = 0.0F; -@@ -1090,27 +1299,47 @@ +@@ -1090,27 +1299,46 @@ this.animationSpeed = 1.5F; boolean flag1 = true; - if ((float) this.invulnerableTime > 10.0F) { + if ((float) this.invulnerableTime > (float) this.invulnerableDuration / 2.0F) { // CraftBukkit - restore use of maxNoDamageTicks if (f <= this.lastHurt) { -+ this.forceExplosionKnockback = true; // CraftBukkit - SPIGOT-949 - for vanilla consistency, cooldown does not prevent explosion knockback return false; } @@ -441,7 +440,7 @@ this.hurtDir = 0.0F; Entity entity1 = damagesource.getEntity(); -@@ -1233,19 +1462,29 @@ +@@ -1233,19 +1461,29 @@ EnumHand[] aenumhand = EnumHand.values(); int i = aenumhand.length; @@ -475,7 +474,7 @@ EntityPlayer entityplayer = (EntityPlayer) this; entityplayer.awardStat(StatisticList.ITEM_USED.get(Items.TOTEM_OF_UNDYING)); -@@ -1253,14 +1492,16 @@ +@@ -1253,14 +1491,16 @@ } this.setHealth(1.0F); @@ -497,7 +496,7 @@ } } -@@ -1365,14 +1606,22 @@ +@@ -1365,14 +1605,22 @@ IBlockData iblockdata = Blocks.WITHER_ROSE.defaultBlockState(); if (this.level.getBlockState(blockposition).isAir() && iblockdata.canSurvive(this.level, blockposition)) { @@ -522,7 +521,7 @@ this.level.addFreshEntity(entityitem); } } -@@ -1392,21 +1641,40 @@ +@@ -1392,21 +1640,40 @@ boolean flag = this.lastHurtByPlayerTime > 0; @@ -566,7 +565,7 @@ } -@@ -1526,9 +1794,14 @@ +@@ -1526,9 +1793,14 @@ int i = this.calculateFallDamage(f, f1); if (i > 0) { @@ -582,7 +581,7 @@ return true; } else { return flag; -@@ -1577,7 +1850,7 @@ +@@ -1577,7 +1849,7 @@ protected float getDamageAfterArmorAbsorb(DamageSource damagesource, float f) { if (!damagesource.isBypassArmor()) { @@ -591,7 +590,7 @@ f = CombatMath.getDamageAfterAbsorb(f, (float) this.getArmorValue(), (float) this.getAttributeValue(GenericAttributes.ARMOR_TOUGHNESS)); } -@@ -1590,7 +1863,8 @@ +@@ -1590,7 +1862,8 @@ } else { int i; @@ -601,7 +600,7 @@ i = (this.getEffect(MobEffects.DAMAGE_RESISTANCE).getAmplifier() + 1) * 5; int j = 25 - i; float f1 = f * (float) j; -@@ -1621,29 +1895,172 @@ +@@ -1621,29 +1894,172 @@ } } @@ -784,7 +783,7 @@ } public CombatTracker getCombatTracker() { -@@ -1664,8 +2081,18 @@ +@@ -1664,8 +2080,18 @@ } public final void setArrowCount(int i) { @@ -804,7 +803,7 @@ public final int getStingerCount() { return (Integer) this.entityData.get(EntityLiving.DATA_STINGER_COUNT_ID); -@@ -1961,6 +2388,12 @@ +@@ -1961,6 +2387,12 @@ public abstract ItemStack getItemBySlot(EnumItemSlot enumitemslot); @@ -817,7 +816,7 @@ @Override public abstract void setItemSlot(EnumItemSlot enumitemslot, ItemStack itemstack); -@@ -2204,6 +2637,7 @@ +@@ -2204,6 +2636,7 @@ } if (this.onGround && !this.level.isClientSide) { @@ -825,7 +824,7 @@ this.setSharedFlag(7, false); } } else { -@@ -2734,6 +3168,7 @@ +@@ -2734,6 +3167,7 @@ } if (!this.level.isClientSide) { @@ -833,7 +832,7 @@ this.setSharedFlag(7, flag); } -@@ -2901,14 +3336,21 @@ +@@ -2901,14 +3335,21 @@ @Override public boolean isPickable() { @@ -857,7 +856,7 @@ @Override protected void markHurt() { this.hurtMarked = this.random.nextDouble() >= this.getAttributeValue(GenericAttributes.KNOCKBACK_RESISTANCE); -@@ -3107,7 +3549,25 @@ +@@ -3107,7 +3548,25 @@ } else { if (!this.useItem.isEmpty() && this.isUsingItem()) { this.triggerItemUseEffects(this.useItem, 16); @@ -884,7 +883,7 @@ if (itemstack != this.useItem) { this.setItemInHand(enumhand, itemstack); -@@ -3180,6 +3640,12 @@ +@@ -3180,6 +3639,12 @@ } public boolean randomTeleport(double d0, double d1, double d2, boolean flag) { @@ -897,7 +896,7 @@ double d3 = this.getX(); double d4 = this.getY(); double d5 = this.getZ(); -@@ -3204,16 +3670,41 @@ +@@ -3204,16 +3669,41 @@ } if (flag2) { @@ -942,7 +941,7 @@ } else { if (flag) { world.broadcastEntityEvent(this, (byte) 46); -@@ -3223,7 +3714,7 @@ +@@ -3223,7 +3713,7 @@ ((EntityCreature) this).getNavigation().stop(); } @@ -951,7 +950,7 @@ } } -@@ -3306,7 +3797,7 @@ +@@ -3306,7 +3796,7 @@ } public void stopSleeping() { @@ -960,7 +959,7 @@ World world = this.level; java.util.Objects.requireNonNull(this.level); -@@ -3338,7 +3829,7 @@ +@@ -3338,7 +3828,7 @@ @Nullable public EnumDirection getBedOrientation() { @@ -969,7 +968,7 @@ return blockposition != null ? BlockBed.getBedOrientation(this.level, blockposition) : null; } -@@ -3387,7 +3878,7 @@ +@@ -3387,7 +3877,7 @@ Pair pair = (Pair) iterator.next(); if (!world.isClientSide && pair.getFirst() != null && world.random.nextFloat() < (Float) pair.getSecond()) { @@ -978,7 +977,7 @@ } } } -@@ -3490,8 +3981,10 @@ +@@ -3490,8 +3980,10 @@ this.setDeltaMovement((double) ((float) packetplayoutspawnentityliving.getXd() / 8000.0F), (double) ((float) packetplayoutspawnentityliving.getYd() / 8000.0F), (double) ((float) packetplayoutspawnentityliving.getZd() / 8000.0F)); } @@ -990,7 +989,7 @@ private final SoundEffect small; private final SoundEffect big; -@@ -3507,5 +4000,7 @@ +@@ -3507,5 +3999,7 @@ public SoundEffect big() { return this.big; } diff --git a/paper-server/nms-patches/net/minecraft/world/entity/player/EntityHuman.patch b/paper-server/nms-patches/net/minecraft/world/entity/player/EntityHuman.patch index 3bf2621093..a4a06a246a 100644 --- a/paper-server/nms-patches/net/minecraft/world/entity/player/EntityHuman.patch +++ b/paper-server/nms-patches/net/minecraft/world/entity/player/EntityHuman.patch @@ -110,14 +110,7 @@ return entityitem; } } -@@ -808,16 +857,17 @@ - if (this.isInvulnerableTo(damagesource)) { - return false; - } else if (this.abilities.invulnerable && !damagesource.isBypassInvul()) { -+ this.forceExplosionKnockback = true; // SPIGOT-5258 - Make invulnerable players get knockback from explosions - return false; - } else { - this.noActionTime = 0; +@@ -814,10 +863,10 @@ if (this.isDeadOrDying()) { return false; } else { @@ -130,7 +123,7 @@ } if (this.level.getDifficulty() == EnumDifficulty.EASY) { -@@ -829,7 +879,13 @@ +@@ -829,7 +878,13 @@ } } @@ -145,7 +138,7 @@ } } } -@@ -849,10 +905,29 @@ +@@ -849,10 +904,29 @@ } public boolean canHarmPlayer(EntityHuman entityhuman) { @@ -178,7 +171,7 @@ } @Override -@@ -894,8 +969,13 @@ +@@ -894,8 +968,13 @@ } } @@ -193,7 +186,7 @@ if (!this.isInvulnerableTo(damagesource)) { f = this.getDamageAfterArmorAbsorb(damagesource, f); f = this.getDamageAfterMagicAbsorb(damagesource, f); -@@ -910,7 +990,7 @@ +@@ -910,7 +989,7 @@ } if (f != 0.0F) { @@ -202,7 +195,7 @@ float f3 = this.getHealth(); this.setHealth(this.getHealth() - f); -@@ -921,6 +1001,7 @@ +@@ -921,6 +1000,7 @@ } } @@ -210,7 +203,7 @@ } @Override -@@ -1080,7 +1161,7 @@ +@@ -1080,7 +1160,7 @@ f *= 0.2F + f2 * f2 * 0.8F; f1 *= f2; @@ -219,7 +212,7 @@ if (f > 0.0F || f1 > 0.0F) { boolean flag = f2 > 0.9F; boolean flag1 = false; -@@ -1119,8 +1200,15 @@ +@@ -1119,8 +1199,15 @@ if (entity instanceof EntityLiving) { f3 = ((EntityLiving) entity).getHealth(); if (j > 0 && !entity.isOnFire()) { @@ -237,7 +230,7 @@ } } -@@ -1148,8 +1236,11 @@ +@@ -1148,8 +1235,11 @@ EntityLiving entityliving = (EntityLiving) iterator.next(); if (entityliving != this && entityliving != entity && !this.isAlliedTo((Entity) entityliving) && (!(entityliving instanceof EntityArmorStand) || !((EntityArmorStand) entityliving).isMarker()) && this.distanceToSqr((Entity) entityliving) < 9.0D) { @@ -250,7 +243,7 @@ } } -@@ -1158,9 +1249,26 @@ +@@ -1158,9 +1248,26 @@ } if (entity instanceof EntityPlayer && entity.hurtMarked) { @@ -277,7 +270,7 @@ } if (flag2) { -@@ -1205,7 +1313,14 @@ +@@ -1205,7 +1312,14 @@ this.awardStat(StatisticList.DAMAGE_DEALT, Math.round(f5 * 10.0F)); if (j > 0) { @@ -293,7 +286,7 @@ } if (this.level instanceof WorldServer && f5 > 2.0F) { -@@ -1215,12 +1330,17 @@ +@@ -1215,12 +1329,17 @@ } } @@ -312,7 +305,7 @@ } } -@@ -1293,6 +1413,12 @@ +@@ -1293,6 +1412,12 @@ public void updateTutorialInventoryAction(ItemStack itemstack, ItemStack itemstack1, ClickAction clickaction) {} public Either startSleepInBed(BlockPosition blockposition) { @@ -325,7 +318,7 @@ this.startSleeping(blockposition); this.sleepCounter = 0; return Either.right(Unit.INSTANCE); -@@ -1377,9 +1503,9 @@ +@@ -1377,9 +1502,9 @@ super.jumpFromGround(); this.awardStat(StatisticList.JUMP); if (this.isSprinting()) { @@ -337,7 +330,7 @@ } } -@@ -1413,7 +1539,11 @@ +@@ -1413,7 +1538,11 @@ this.setDeltaMovement(vec3d2.x, d3 * 0.6D, vec3d2.z); this.flyingSpeed = f; this.resetFallDistance(); @@ -350,7 +343,7 @@ } else { super.travel(vec3d); } -@@ -1448,19 +1578,19 @@ +@@ -1448,19 +1577,19 @@ i = Math.round((float) Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2) * 100.0F); if (i > 0) { this.awardStat(StatisticList.SWIM_ONE_CM, i); @@ -373,7 +366,7 @@ } } else if (this.onClimbable()) { if (d1 > 0.0D) { -@@ -1471,13 +1601,13 @@ +@@ -1471,13 +1600,13 @@ if (i > 0) { if (this.isSprinting()) { this.awardStat(StatisticList.SPRINT_ONE_CM, i); @@ -390,7 +383,7 @@ } } } else if (this.isFallFlying()) { -@@ -1543,12 +1673,24 @@ +@@ -1543,12 +1672,24 @@ } public void startFallFlying() { @@ -416,7 +409,7 @@ } @Override -@@ -1638,10 +1780,21 @@ +@@ -1638,10 +1779,21 @@ return this.experienceLevel >= 30 ? 112 + (this.experienceLevel - 30) * 9 : (this.experienceLevel >= 15 ? 37 + (this.experienceLevel - 15) * 5 : 7 + this.experienceLevel * 2); } @@ -439,7 +432,7 @@ } } -@@ -1718,15 +1871,22 @@ +@@ -1718,15 +1870,22 @@ @Override public void setItemSlot(EnumItemSlot enumitemslot, ItemStack itemstack) { @@ -465,7 +458,7 @@ this.inventory.armor.set(enumitemslot.getIndex(), itemstack); } -@@ -1767,26 +1927,31 @@ +@@ -1767,26 +1926,31 @@ protected void removeEntitiesOnShoulder() { if (this.timeEntitySatOnShoulder + 20L < this.level.getGameTime()) { diff --git a/paper-server/nms-patches/net/minecraft/world/level/Explosion.patch b/paper-server/nms-patches/net/minecraft/world/level/Explosion.patch index eabf743829..e70ca8f633 100644 --- a/paper-server/nms-patches/net/minecraft/world/level/Explosion.patch +++ b/paper-server/nms-patches/net/minecraft/world/level/Explosion.patch @@ -1,11 +1,12 @@ --- a/net/minecraft/world/level/Explosion.java +++ b/net/minecraft/world/level/Explosion.java -@@ -42,6 +42,14 @@ +@@ -42,6 +42,15 @@ import net.minecraft.world.phys.MovingObjectPosition; import net.minecraft.world.phys.Vec3D; +// CraftBukkit start -+import net.minecraft.world.entity.item.EntityFallingBlock; ++import net.minecraft.world.entity.boss.EntityComplexPart; ++import net.minecraft.world.entity.boss.enderdragon.EntityEnderDragon; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.Location; @@ -15,7 +16,7 @@ public class Explosion { private static final ExplosionDamageCalculator EXPLOSION_DAMAGE_CALCULATOR = new ExplosionDamageCalculator(); -@@ -60,6 +68,7 @@ +@@ -60,6 +69,7 @@ private final ExplosionDamageCalculator damageCalculator; private final List toBlow; private final Map hitPlayers; @@ -23,7 +24,7 @@ public Explosion(World world, @Nullable Entity entity, double d0, double d1, double d2, float f) { this(world, entity, d0, d1, d2, f, false, Explosion.Effect.DESTROY); -@@ -84,7 +93,7 @@ +@@ -84,7 +94,7 @@ this.hitPlayers = Maps.newHashMap(); this.level = world; this.source = entity; @@ -32,7 +33,7 @@ this.x = d0; this.y = d1; this.z = d2; -@@ -134,6 +143,11 @@ +@@ -134,6 +144,11 @@ } public void explode() { @@ -44,24 +45,44 @@ this.level.gameEvent(this.source, GameEvent.EXPLODE, new BlockPosition(this.x, this.y, this.z)); Set set = Sets.newHashSet(); boolean flag = true; -@@ -217,7 +231,15 @@ +@@ -217,7 +232,35 @@ double d12 = (double) getSeenPercent(vec3d, entity); double d13 = (1.0D - d7) * d12; - entity.hurt(this.getDamageSource(), (float) ((int) ((d13 * d13 + d13) / 2.0D * 7.0D * (double) f2 + 1.0D))); + // CraftBukkit start + CraftEventFactory.entityDamage = source; -+ entity.forceExplosionKnockback = false; -+ boolean wasDamaged = entity.hurt(this.getDamageSource(), (float) ((int) ((d13 * d13 + d13) / 2.0D * 7.0D * (double) f2 + 1.0D))); ++ entity.lastDamageCancelled = false; ++ ++ // Special case ender dragon only give knockback if no damage is cancelled ++ // Thinks to note: ++ // - Setting a velocity to a ComplexEntityPart is ignored (and therefore not needed) ++ // - Damaging ComplexEntityPart while forward the damage to EntityEnderDragon ++ // - Damaging EntityEnderDragon does nothing ++ // - EntityEnderDragon hitbock always covers the other parts and is therefore always present ++ if (entity instanceof EntityComplexPart) { ++ continue; ++ } ++ ++ if (entity instanceof EntityEnderDragon) { ++ for (EntityComplexPart entityComplexPart : ((EntityEnderDragon) entity).subEntities) { ++ if (list.contains(entityComplexPart)) { ++ entityComplexPart.hurt(this.getDamageSource(), (float) ((int) ((d13 * d13 + d13) / 2.0D * 7.0D * (double) f2 + 1.0D))); ++ } ++ } ++ } else { ++ entity.hurt(this.getDamageSource(), (float) ((int) ((d13 * d13 + d13) / 2.0D * 7.0D * (double) f2 + 1.0D))); ++ } ++ + CraftEventFactory.entityDamage = null; -+ if (!wasDamaged && !(entity instanceof EntityTNTPrimed || entity instanceof EntityFallingBlock) && !entity.forceExplosionKnockback) { ++ if (entity.lastDamageCancelled) { // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Skip entity if damage event was cancelled + continue; + } + // CraftBukkit end double d14 = d13; if (entity instanceof EntityLiving) { -@@ -259,6 +281,51 @@ +@@ -259,6 +302,51 @@ Collections.shuffle(this.toBlow, this.level.random); Iterator iterator = this.toBlow.iterator(); @@ -113,7 +134,7 @@ while (iterator.hasNext()) { BlockPosition blockposition = (BlockPosition) iterator.next(); -@@ -273,8 +340,8 @@ +@@ -273,8 +361,8 @@ TileEntity tileentity = iblockdata.hasBlockEntity() ? this.level.getBlockEntity(blockposition) : null; LootTableInfo.Builder loottableinfo_builder = (new LootTableInfo.Builder((WorldServer) this.level)).withRandom(this.level.random).withParameter(LootContextParameters.ORIGIN, Vec3D.atCenterOf(blockposition)).withParameter(LootContextParameters.TOOL, ItemStack.EMPTY).withOptionalParameter(LootContextParameters.BLOCK_ENTITY, tileentity).withOptionalParameter(LootContextParameters.THIS_ENTITY, this.source); @@ -124,7 +145,7 @@ } iblockdata.getDrops(loottableinfo_builder).forEach((itemstack) -> { -@@ -304,7 +371,11 @@ +@@ -304,7 +392,11 @@ BlockPosition blockposition2 = (BlockPosition) iterator1.next(); if (this.random.nextInt(3) == 0 && this.level.getBlockState(blockposition2).isAir() && this.level.getBlockState(blockposition2.below()).isSolidRender(this.level, blockposition2.below())) { @@ -137,7 +158,7 @@ } } } -@@ -312,6 +383,7 @@ +@@ -312,6 +404,7 @@ } private static void addBlockDrops(ObjectArrayList> objectarraylist, ItemStack itemstack, BlockPosition blockposition) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index 4c651b8e26..5ab51104e6 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -860,6 +860,8 @@ public class CraftEventFactory { if (!event.isCancelled()) { event.getEntity().setLastDamageCause(event); + } else { + entity.lastDamageCancelled = true; // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Keep track if the event was canceled } return event; } else if (source instanceof EntityDamageSource) { @@ -884,6 +886,8 @@ public class CraftEventFactory { callEvent(event); if (!event.isCancelled()) { event.getEntity().setLastDamageCause(event); + } else { + entity.lastDamageCancelled = true; // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Keep track if the event was canceled } return event; } else if (source == DamageSource.LAVA) { @@ -892,6 +896,8 @@ public class CraftEventFactory { callEvent(event); if (!event.isCancelled()) { event.getEntity().setLastDamageCause(event); + } else { + entity.lastDamageCancelled = true; // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Keep track if the event was canceled } return event; } else if (blockDamage != null) { @@ -913,6 +919,8 @@ public class CraftEventFactory { callEvent(event); if (!event.isCancelled()) { event.getEntity().setLastDamageCause(event); + } else { + entity.lastDamageCancelled = true; // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Keep track if the event was canceled } return event; } else if (entityDamage != null) { @@ -937,6 +945,8 @@ public class CraftEventFactory { callEvent(event); if (!event.isCancelled()) { event.getEntity().setLastDamageCause(event); + } else { + entity.lastDamageCancelled = true; // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Keep track if the event was canceled } return event; } @@ -997,6 +1007,8 @@ public class CraftEventFactory { if (!event.isCancelled()) { event.getEntity().setLastDamageCause(event); + } else { + damagee.lastDamageCancelled = true; // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Keep track if the event was canceled } return event;