SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Only cancel knockback if the damage event was canceled

By: DerFrZocker <derrieple@gmail.com>
This commit is contained in:
CraftBukkit/Spigot 2022-01-03 18:07:01 +01:00
parent cc34358a3e
commit 46f0dde817
5 changed files with 91 additions and 66 deletions

View file

@ -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;
+

View file

@ -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<MobEffect, Float> 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;
}

View file

@ -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<EntityHuman.EnumBedResult, Unit> 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()) {

View file

@ -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<BlockPosition> toBlow;
private final Map<EntityHuman, Vec3D> 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<BlockPosition> 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<Pair<ItemStack, BlockPosition>> objectarraylist, ItemStack itemstack, BlockPosition blockposition) {

View file

@ -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;