From 7b1556211636e0cc5534d948045862750818d6fe Mon Sep 17 00:00:00 2001 From: CraftBukkit/Spigot Date: Sat, 27 Jan 2024 14:53:41 +1100 Subject: [PATCH] SPIGOT-5553, #1336: Add EntityKnockbackEvent By: Jishuna --- .../world/entity/EntityInsentient.patch | 10 +- .../minecraft/world/entity/EntityLiving.patch | 138 ++++++++++++------ .../world/entity/player/EntityHuman.patch | 75 ++++++---- .../net/minecraft/world/level/Explosion.patch | 21 ++- .../craftbukkit/event/CraftEventFactory.java | 16 ++ 5 files changed, 179 insertions(+), 81 deletions(-) diff --git a/paper-server/nms-patches/net/minecraft/world/entity/EntityInsentient.patch b/paper-server/nms-patches/net/minecraft/world/entity/EntityInsentient.patch index 0287040351..7f93eabcd2 100644 --- a/paper-server/nms-patches/net/minecraft/world/entity/EntityInsentient.patch +++ b/paper-server/nms-patches/net/minecraft/world/entity/EntityInsentient.patch @@ -303,7 +303,7 @@ this.leashInfoTag = null; } } -@@ -1501,7 +1619,14 @@ +@@ -1501,14 +1619,21 @@ int i = EnchantmentManager.getFireAspect(this); if (i > 0) { @@ -319,6 +319,14 @@ } boolean flag = entity.hurt(this.damageSources().mobAttack(this), f); + + if (flag) { + if (f1 > 0.0F && entity instanceof EntityLiving) { +- ((EntityLiving) entity).knockback((double) (f1 * 0.5F), (double) MathHelper.sin(this.getYRot() * 0.017453292F), (double) (-MathHelper.cos(this.getYRot() * 0.017453292F))); ++ ((EntityLiving) entity).knockback((double) (f1 * 0.5F), (double) MathHelper.sin(this.getYRot() * 0.017453292F), (double) (-MathHelper.cos(this.getYRot())) * 0.017453292F, this, org.bukkit.event.entity.EntityKnockbackEvent.KnockbackCause.ENTITY_ATTACK); // CraftBukkit + this.setDeltaMovement(this.getDeltaMovement().multiply(0.6D, 1.0D, 0.6D)); + } + @@ -1576,6 +1701,7 @@ @Override protected void removeAfterChangingDimensions() { 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 b7f4542c90..7df5f72e55 100644 --- a/paper-server/nms-patches/net/minecraft/world/entity/EntityLiving.patch +++ b/paper-server/nms-patches/net/minecraft/world/entity/EntityLiving.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/EntityLiving.java +++ b/net/minecraft/world/entity/EntityLiving.java -@@ -119,6 +119,30 @@ +@@ -119,6 +119,31 @@ import net.minecraft.world.scores.ScoreboardTeam; import org.slf4j.Logger; @@ -21,6 +21,7 @@ +import org.bukkit.event.entity.ArrowBodyCountChangeEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDamageEvent.DamageModifier; ++import org.bukkit.event.entity.EntityKnockbackEvent; +import org.bukkit.event.entity.EntityPotionEffectEvent; +import org.bukkit.event.entity.EntityRegainHealthEvent; +import org.bukkit.event.entity.EntityResurrectEvent; @@ -31,7 +32,7 @@ public abstract class EntityLiving extends Entity implements Attackable { private static final Logger LOGGER = LogUtils.getLogger(); -@@ -225,7 +249,21 @@ +@@ -225,7 +250,21 @@ private float swimAmount; private float swimAmountO; protected BehaviorController brain; @@ -54,7 +55,7 @@ protected EntityLiving(EntityTypes entitytypes, World world) { super(entitytypes, world); -@@ -238,7 +276,9 @@ +@@ -238,7 +277,9 @@ this.useItem = ItemStack.EMPTY; this.lastClimbablePos = Optional.empty(); this.attributes = new AttributeMapBase(AttributeDefaults.getSupplier(entitytypes)); @@ -65,7 +66,7 @@ this.blocksBuilding = true; this.rotA = (float) ((Math.random() + 1.0D) * 0.009999999776482582D); this.reapplyPosition(); -@@ -317,7 +357,13 @@ +@@ -317,7 +358,13 @@ double d7 = Math.min((double) (0.2F + f / 15.0F), 2.5D); int i = (int) (150.0D * d7); @@ -80,7 +81,7 @@ } super.checkFallDamage(d0, flag, iblockdata, blockposition); -@@ -672,13 +718,19 @@ +@@ -672,13 +719,19 @@ } public void onEquipItem(EnumItemSlot enumitemslot, ItemStack itemstack, ItemStack itemstack1) { @@ -101,7 +102,7 @@ this.level().playSound((EntityHuman) null, this.getX(), this.getY(), this.getZ(), equipable.getEquipSound(), this.getSoundSource(), 1.0F, 1.0F); } -@@ -752,6 +804,17 @@ +@@ -752,6 +805,17 @@ } } @@ -119,7 +120,7 @@ if (nbttagcompound.contains("Health", 99)) { this.setHealth(nbttagcompound.getFloat("Health")); } -@@ -789,9 +852,32 @@ +@@ -789,9 +853,32 @@ } @@ -152,7 +153,7 @@ try { while (iterator.hasNext()) { MobEffectList mobeffectlist = (MobEffectList) iterator.next(); -@@ -801,6 +887,12 @@ +@@ -801,6 +888,12 @@ this.onEffectUpdated(mobeffect, true, (Entity) null); })) { if (!this.level().isClientSide) { @@ -165,7 +166,7 @@ iterator.remove(); this.onEffectRemoved(mobeffect); } -@@ -811,6 +903,17 @@ +@@ -811,6 +904,17 @@ } catch (ConcurrentModificationException concurrentmodificationexception) { ; } @@ -183,7 +184,7 @@ if (this.effectsDirty) { if (!this.level().isClientSide) { -@@ -937,7 +1040,13 @@ +@@ -937,7 +1041,13 @@ this.entityData.set(EntityLiving.DATA_EFFECT_COLOR_ID, 0); } @@ -197,7 +198,7 @@ if (this.level().isClientSide) { return false; } else { -@@ -946,7 +1055,14 @@ +@@ -946,7 +1056,14 @@ boolean flag; for (flag = false; iterator.hasNext(); flag = true) { @@ -213,7 +214,7 @@ iterator.remove(); } -@@ -975,19 +1091,49 @@ +@@ -975,19 +1092,49 @@ return this.addEffect(mobeffect, (Entity) null); } @@ -264,7 +265,7 @@ flag = true; } -@@ -1025,13 +1171,39 @@ +@@ -1025,13 +1172,39 @@ return this.getMobType() == EnumMonsterType.UNDEAD; } @@ -305,7 +306,7 @@ if (mobeffect != null) { this.onEffectRemoved(mobeffect); -@@ -1129,20 +1301,55 @@ +@@ -1129,20 +1302,55 @@ } @@ -362,7 +363,7 @@ this.entityData.set(EntityLiving.DATA_HEALTH_ID, MathHelper.clamp(f, 0.0F, this.getMaxHealth())); } -@@ -1156,7 +1363,7 @@ +@@ -1156,7 +1364,7 @@ return false; } else if (this.level().isClientSide) { return false; @@ -371,7 +372,7 @@ return false; } else if (damagesource.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; -@@ -1167,10 +1374,11 @@ +@@ -1167,10 +1375,11 @@ this.noActionTime = 0; float f1 = f; @@ -385,7 +386,7 @@ this.hurtCurrentlyUsedShield(f); f2 = f; f = 0.0F; -@@ -1194,23 +1402,33 @@ +@@ -1194,23 +1403,33 @@ this.walkAnimation.setSpeed(1.5F); boolean flag1 = true; @@ -424,7 +425,25 @@ this.hurtHelmet(damagesource, f); f *= 0.75F; } -@@ -1328,19 +1546,32 @@ +@@ -1269,7 +1488,7 @@ + d0 = (Math.random() - Math.random()) * 0.01D; + } + +- this.knockback(0.4000000059604645D, d0, d1); ++ this.knockback(0.4000000059604645D, d0, d1, entity1, entity1 == null ? EntityKnockbackEvent.KnockbackCause.DAMAGE : EntityKnockbackEvent.KnockbackCause.ENTITY_ATTACK); // CraftBukkit + if (!flag) { + this.indicateDamage(d0, d1); + } +@@ -1317,7 +1536,7 @@ + } + + protected void blockedByShield(EntityLiving entityliving) { +- entityliving.knockback(0.5D, entityliving.getX() - this.getX(), entityliving.getZ() - this.getZ()); ++ entityliving.knockback(0.5D, entityliving.getX() - this.getX(), entityliving.getZ() - this.getZ(), null, EntityKnockbackEvent.KnockbackCause.SHIELD_BLOCK); // CraftBukkit + } + + private boolean checkTotemDeathProtection(DamageSource damagesource) { +@@ -1328,19 +1547,32 @@ EnumHand[] aenumhand = EnumHand.values(); int i = aenumhand.length; @@ -461,7 +480,7 @@ EntityPlayer entityplayer = (EntityPlayer) this; entityplayer.awardStat(StatisticList.ITEM_USED.get(Items.TOTEM_OF_UNDYING)); -@@ -1349,14 +1580,16 @@ +@@ -1349,14 +1581,16 @@ } this.setHealth(1.0F); @@ -483,7 +502,7 @@ } } -@@ -1463,14 +1696,22 @@ +@@ -1463,14 +1697,22 @@ IBlockData iblockdata = Blocks.WITHER_ROSE.defaultBlockState(); if (this.level().getBlockState(blockposition).isAir() && iblockdata.canSurvive(this.level(), blockposition)) { @@ -508,7 +527,7 @@ this.level().addFreshEntity(entityitem); } } -@@ -1490,21 +1731,40 @@ +@@ -1490,21 +1732,40 @@ boolean flag = this.lastHurtByPlayerTime > 0; @@ -538,7 +557,7 @@ + return i; + } else { + return 0; -+ } + } + } + // CraftBukkit end + @@ -547,12 +566,41 @@ + if (true && !(this instanceof net.minecraft.world.entity.boss.enderdragon.EntityEnderDragon)) { // CraftBukkit - SPIGOT-2420: Special case ender dragon will drop the xp over time + EntityExperienceOrb.award((WorldServer) this.level(), this.position(), this.expToDrop); + this.expToDrop = 0; - } ++ } + // CraftBukkit end } -@@ -1596,6 +1856,28 @@ +@@ -1533,13 +1794,25 @@ + } + + public void knockback(double d0, double d1, double d2) { ++ // CraftBukkit start - EntityKnockbackEvent ++ knockback(d0, d1, d2, null, EntityKnockbackEvent.KnockbackCause.UNKNOWN); ++ } ++ ++ public void knockback(double d0, double d1, double d2, Entity attacker, EntityKnockbackEvent.KnockbackCause cause) { + d0 *= 1.0D - this.getAttributeValue(GenericAttributes.KNOCKBACK_RESISTANCE); +- if (d0 > 0.0D) { +- this.hasImpulse = true; ++ if (true || d0 > 0.0D) { // CraftBukkit - Call event even when force is 0 ++ //this.hasImpulse = true; // CraftBukkit - Move down + Vec3D vec3d = this.getDeltaMovement(); + Vec3D vec3d1 = (new Vec3D(d1, 0.0D, d2)).normalize().scale(d0); + +- this.setDeltaMovement(vec3d.x / 2.0D - vec3d1.x, this.onGround() ? Math.min(0.4D, vec3d.y / 2.0D + d0) : vec3d.y, vec3d.z / 2.0D - vec3d1.z); ++ EntityKnockbackEvent event = CraftEventFactory.callEntityKnockbackEvent((org.bukkit.craftbukkit.entity.CraftLivingEntity) this.getBukkitEntity(), attacker, cause, d0, vec3d1, vec3d.x / 2.0D - vec3d1.x, this.onGround() ? Math.min(0.4D, vec3d.y / 2.0D + d0) : vec3d.y, vec3d.z / 2.0D - vec3d1.z); ++ if (event.isCancelled()) { ++ return; ++ } ++ ++ this.hasImpulse = true; ++ this.setDeltaMovement(event.getFinalKnockback().getX(), event.getFinalKnockback().getY(), event.getFinalKnockback().getZ()); ++ // CraftBukkit end + } + } + +@@ -1596,6 +1869,28 @@ return itemstack.getEatingSound(); } @@ -581,7 +629,7 @@ public Optional getLastClimbablePos() { return this.lastClimbablePos; } -@@ -1642,9 +1924,14 @@ +@@ -1642,9 +1937,14 @@ int i = this.calculateFallDamage(f, f1); if (i > 0) { @@ -597,7 +645,7 @@ return true; } else { return flag; -@@ -1696,7 +1983,7 @@ +@@ -1696,7 +1996,7 @@ protected float getDamageAfterArmorAbsorb(DamageSource damagesource, float f) { if (!damagesource.is(DamageTypeTags.BYPASSES_ARMOR)) { @@ -606,7 +654,7 @@ f = CombatMath.getDamageAfterAbsorb(f, (float) this.getArmorValue(), (float) this.getAttributeValue(GenericAttributes.ARMOR_TOUGHNESS)); } -@@ -1709,7 +1996,8 @@ +@@ -1709,7 +2009,8 @@ } else { int i; @@ -616,7 +664,7 @@ i = (this.getEffect(MobEffects.DAMAGE_RESISTANCE).getAmplifier() + 1) * 5; int j = 25 - i; float f1 = f * (float) j; -@@ -1742,16 +2030,125 @@ +@@ -1742,16 +2043,125 @@ } } @@ -654,7 +702,7 @@ + }; + float blockingModifier = blocking.apply((double) f).floatValue(); + f += blockingModifier; - ++ + Function armor = new Function() { + @Override + public Double apply(Double f) { @@ -743,14 +791,14 @@ + absorptionModifier = (float) -event.getDamage(DamageModifier.ABSORPTION); + this.setAbsorptionAmount(Math.max(this.getAbsorptionAmount() - absorptionModifier, 0.0F)); + float f2 = absorptionModifier; -+ + + if (f2 > 0.0F && f2 < 3.4028235E37F && this instanceof EntityHuman) { + ((EntityHuman) this).awardStat(StatisticList.DAMAGE_ABSORBED, Math.round(f2 * 10.0F)); + } if (f2 > 0.0F && f2 < 3.4028235E37F) { Entity entity = damagesource.getEntity(); -@@ -1762,13 +2159,47 @@ +@@ -1762,13 +2172,47 @@ } } @@ -800,7 +848,7 @@ } public CombatTracker getCombatTracker() { -@@ -1793,8 +2224,18 @@ +@@ -1793,8 +2237,18 @@ } public final void setArrowCount(int i) { @@ -820,7 +868,7 @@ public final int getStingerCount() { return (Integer) this.entityData.get(EntityLiving.DATA_STINGER_COUNT_ID); -@@ -2036,6 +2477,12 @@ +@@ -2036,6 +2490,12 @@ public abstract ItemStack getItemBySlot(EnumItemSlot enumitemslot); @@ -833,7 +881,7 @@ @Override public abstract void setItemSlot(EnumItemSlot enumitemslot, ItemStack itemstack); -@@ -2270,6 +2717,7 @@ +@@ -2270,6 +2730,7 @@ } if (this.onGround() && !this.level().isClientSide) { @@ -841,7 +889,7 @@ this.setSharedFlag(7, false); } } else { -@@ -2440,7 +2888,7 @@ +@@ -2440,7 +2901,7 @@ } } @@ -850,7 +898,7 @@ if (this.tickCount % 20 == 0) { this.getCombatTracker().recheckStatus(); } -@@ -2537,7 +2985,7 @@ +@@ -2537,7 +2998,7 @@ this.refreshDirtyAttributes(); } @@ -859,7 +907,7 @@ Map map = this.collectEquipmentChanges(); if (map != null) { -@@ -2839,6 +3287,7 @@ +@@ -2839,6 +3300,7 @@ } if (!this.level().isClientSide) { @@ -867,7 +915,7 @@ this.setSharedFlag(7, flag); } -@@ -3029,13 +3478,20 @@ +@@ -3029,13 +3491,20 @@ @Override public boolean isPickable() { @@ -890,7 +938,7 @@ @Override public float getYHeadRot() { -@@ -3231,7 +3687,26 @@ +@@ -3231,7 +3700,26 @@ } else { if (!this.useItem.isEmpty() && this.isUsingItem()) { this.triggerItemUseEffects(this.useItem, 16); @@ -918,7 +966,7 @@ if (itemstack != this.useItem) { this.setItemInHand(enumhand, itemstack); -@@ -3309,6 +3784,12 @@ +@@ -3309,6 +3797,12 @@ } public boolean randomTeleport(double d0, double d1, double d2, boolean flag) { @@ -931,7 +979,7 @@ double d3 = this.getX(); double d4 = this.getY(); double d5 = this.getZ(); -@@ -3333,16 +3814,41 @@ +@@ -3333,16 +3827,41 @@ } if (flag2) { @@ -976,7 +1024,7 @@ } else { if (flag) { world.broadcastEntityEvent(this, (byte) 46); -@@ -3354,7 +3860,7 @@ +@@ -3354,7 +3873,7 @@ entitycreature.getNavigation().stop(); } @@ -985,7 +1033,7 @@ } } -@@ -3443,7 +3949,7 @@ +@@ -3443,7 +3962,7 @@ } public void stopSleeping() { @@ -994,7 +1042,7 @@ World world = this.level(); java.util.Objects.requireNonNull(world); -@@ -3477,7 +3983,7 @@ +@@ -3477,7 +3996,7 @@ @Nullable public EnumDirection getBedOrientation() { @@ -1003,7 +1051,7 @@ return blockposition != null ? BlockBed.getBedOrientation(this.level(), blockposition) : null; } -@@ -3525,7 +4031,7 @@ +@@ -3525,7 +4044,7 @@ Pair pair = (Pair) iterator.next(); if (!world.isClientSide && pair.getFirst() != null && world.random.nextFloat() < (Float) pair.getSecond()) { 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 2371941fe2..c5be567df5 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 @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/player/EntityHuman.java +++ b/net/minecraft/world/entity/player/EntityHuman.java -@@ -112,6 +112,20 @@ +@@ -112,6 +112,21 @@ import net.minecraft.world.scores.ScoreboardTeam; import org.slf4j.Logger; @@ -14,6 +14,7 @@ +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.EntityCombustByEntityEvent; +import org.bukkit.event.entity.EntityExhaustionEvent; ++import org.bukkit.event.entity.EntityKnockbackEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerVelocityEvent; +// CraftBukkit end @@ -21,7 +22,7 @@ public abstract class EntityHuman extends EntityLiving { private static final Logger LOGGER = LogUtils.getLogger(); -@@ -127,7 +141,8 @@ +@@ -127,7 +142,8 @@ public static final float SWIMMING_BB_HEIGHT = 0.6F; public static final float DEFAULT_EYE_HEIGHT = 1.62F; public static final EntitySize STANDING_DIMENSIONS = EntitySize.scalable(0.6F, 1.8F); @@ -31,7 +32,7 @@ private static final DataWatcherObject DATA_PLAYER_ABSORPTION_ID = DataWatcher.defineId(EntityHuman.class, DataWatcherRegistry.FLOAT); private static final DataWatcherObject DATA_SCORE_ID = DataWatcher.defineId(EntityHuman.class, DataWatcherRegistry.INT); protected static final DataWatcherObject DATA_PLAYER_MODE_CUSTOMISATION = DataWatcher.defineId(EntityHuman.class, DataWatcherRegistry.BYTE); -@@ -136,10 +151,10 @@ +@@ -136,10 +152,10 @@ protected static final DataWatcherObject DATA_SHOULDER_RIGHT = DataWatcher.defineId(EntityHuman.class, DataWatcherRegistry.COMPOUND_TAG); private long timeEntitySatOnShoulder; private final PlayerInventory inventory = new PlayerInventory(this); @@ -44,7 +45,7 @@ protected int jumpTriggerTime; public float oBob; public float bob; -@@ -168,6 +183,16 @@ +@@ -168,6 +184,16 @@ public EntityFishingHook fishing; protected float hurtDir; @@ -61,7 +62,7 @@ public EntityHuman(World world, BlockPosition blockposition, float f, GameProfile gameprofile) { super(EntityTypes.PLAYER, world); this.lastItemInMainHand = ItemStack.EMPTY; -@@ -312,7 +337,7 @@ +@@ -312,7 +338,7 @@ ItemStack itemstack = this.getItemBySlot(EnumItemSlot.HEAD); if (itemstack.is(Items.TURTLE_HELMET) && !this.isEyeInFluid(TagsFluid.WATER)) { @@ -70,7 +71,7 @@ } } -@@ -482,8 +507,14 @@ +@@ -482,8 +508,14 @@ public void rideTick() { if (!this.level().isClientSide && this.wantsToStopRiding() && this.isPassenger()) { this.stopRiding(); @@ -87,7 +88,7 @@ super.rideTick(); this.oBob = this.bob; this.bob = 0.0F; -@@ -505,7 +536,8 @@ +@@ -505,7 +537,8 @@ if (this.level().getDifficulty() == EnumDifficulty.PEACEFUL && this.level().getGameRules().getBoolean(GameRules.RULE_NATURAL_REGENERATION)) { if (this.getHealth() < this.getMaxHealth() && this.tickCount % 20 == 0) { @@ -97,7 +98,7 @@ } if (this.foodData.needsFood() && this.tickCount % 10 == 0) { -@@ -665,6 +697,13 @@ +@@ -665,6 +698,13 @@ @Nullable public EntityItem drop(ItemStack itemstack, boolean flag, boolean flag1) { @@ -111,7 +112,7 @@ if (itemstack.isEmpty()) { return null; } else { -@@ -699,6 +738,33 @@ +@@ -699,6 +739,33 @@ entityitem.setDeltaMovement((double) (-f3 * f2 * 0.3F) + Math.cos((double) f5) * (double) f6, (double) (-f1 * 0.3F + 0.1F + (this.random.nextFloat() - this.random.nextFloat()) * 0.1F), (double) (f4 * f2 * 0.3F) + Math.sin((double) f5) * (double) f6); } @@ -145,7 +146,7 @@ return entityitem; } } -@@ -789,7 +855,7 @@ +@@ -789,7 +856,7 @@ } if (nbttagcompound.contains("LastDeathLocation", 10)) { @@ -154,7 +155,7 @@ Logger logger = EntityHuman.LOGGER; Objects.requireNonNull(logger); -@@ -822,7 +888,7 @@ +@@ -822,7 +889,7 @@ } this.getLastDeathLocation().flatMap((globalpos) -> { @@ -163,7 +164,7 @@ Logger logger = EntityHuman.LOGGER; Objects.requireNonNull(logger); -@@ -849,12 +915,12 @@ +@@ -849,12 +916,12 @@ return false; } else { if (!this.level().isClientSide) { @@ -178,7 +179,7 @@ } if (this.level().getDifficulty() == EnumDifficulty.EASY) { -@@ -866,7 +932,13 @@ +@@ -866,7 +933,13 @@ } } @@ -193,7 +194,7 @@ } } } -@@ -886,10 +958,29 @@ +@@ -886,10 +959,29 @@ } public boolean canHarmPlayer(EntityHuman entityhuman) { @@ -226,7 +227,7 @@ } @Override -@@ -931,8 +1022,13 @@ +@@ -931,8 +1023,13 @@ } } @@ -241,7 +242,7 @@ if (!this.isInvulnerableTo(damagesource)) { f = this.getDamageAfterArmorAbsorb(damagesource, f); f = this.getDamageAfterMagicAbsorb(damagesource, f); -@@ -947,7 +1043,7 @@ +@@ -947,7 +1044,7 @@ } if (f != 0.0F) { @@ -250,7 +251,7 @@ this.getCombatTracker().recordDamage(damagesource, f); this.setHealth(this.getHealth() - f); if (f < 3.4028235E37F) { -@@ -957,6 +1053,7 @@ +@@ -957,6 +1054,7 @@ this.gameEvent(GameEvent.ENTITY_DAMAGE); } } @@ -258,7 +259,7 @@ } @Override -@@ -1121,7 +1218,7 @@ +@@ -1121,7 +1219,7 @@ f *= 0.2F + f2 * f2 * 0.8F; f1 *= f2; @@ -267,7 +268,7 @@ if (f > 0.0F || f1 > 0.0F) { boolean flag = f2 > 0.9F; boolean flag1 = false; -@@ -1160,8 +1257,15 @@ +@@ -1160,8 +1258,15 @@ if (entity instanceof EntityLiving) { f3 = ((EntityLiving) entity).getHealth(); if (j > 0 && !entity.isOnFire()) { @@ -285,20 +286,30 @@ } } -@@ -1189,8 +1293,11 @@ +@@ -1171,7 +1276,7 @@ + if (flag5) { + if (i > 0) { + if (entity instanceof EntityLiving) { +- ((EntityLiving) entity).knockback((double) ((float) i * 0.5F), (double) MathHelper.sin(this.getYRot() * 0.017453292F), (double) (-MathHelper.cos(this.getYRot() * 0.017453292F))); ++ ((EntityLiving) entity).knockback((double) ((float) i * 0.5F), (double) MathHelper.sin(this.getYRot() * 0.017453292F), (double) (-MathHelper.cos(this.getYRot() * 0.017453292F)), this, EntityKnockbackEvent.KnockbackCause.ENTITY_ATTACK); // CraftBukkit + } else { + entity.push((double) (-MathHelper.sin(this.getYRot() * 0.017453292F) * (float) i * 0.5F), 0.1D, (double) (MathHelper.cos(this.getYRot() * 0.017453292F) * (float) i * 0.5F)); + } +@@ -1189,8 +1294,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) { +- entityliving.knockback(0.4000000059604645D, (double) MathHelper.sin(this.getYRot() * 0.017453292F), (double) (-MathHelper.cos(this.getYRot() * 0.017453292F))); +- entityliving.hurt(this.damageSources().playerAttack(this), f4); + // CraftBukkit start - Only apply knockback if the damage hits + if (entityliving.hurt(this.damageSources().playerAttack(this).sweep(), f4)) { - entityliving.knockback(0.4000000059604645D, (double) MathHelper.sin(this.getYRot() * 0.017453292F), (double) (-MathHelper.cos(this.getYRot() * 0.017453292F))); -- entityliving.hurt(this.damageSources().playerAttack(this), f4); ++ entityliving.knockback(0.4000000059604645D, (double) MathHelper.sin(this.getYRot() * 0.017453292F), (double) (-MathHelper.cos(this.getYRot() * 0.017453292F)), this, EntityKnockbackEvent.KnockbackCause.SWEEP_ATTACK); // CraftBukkit + } + // CraftBukkit end } } -@@ -1199,9 +1306,26 @@ +@@ -1199,9 +1307,26 @@ } if (entity instanceof EntityPlayer && entity.hurtMarked) { @@ -325,7 +336,7 @@ } if (flag2) { -@@ -1246,7 +1370,14 @@ +@@ -1246,7 +1371,14 @@ this.awardStat(StatisticList.DAMAGE_DEALT, Math.round(f5 * 10.0F)); if (j > 0) { @@ -341,7 +352,7 @@ } if (this.level() instanceof WorldServer && f5 > 2.0F) { -@@ -1256,12 +1387,17 @@ +@@ -1256,12 +1388,17 @@ } } @@ -360,7 +371,7 @@ } } -@@ -1338,6 +1474,12 @@ +@@ -1338,6 +1475,12 @@ } public Either startSleepInBed(BlockPosition blockposition) { @@ -373,7 +384,7 @@ this.startSleeping(blockposition); this.sleepCounter = 0; return Either.right(Unit.INSTANCE); -@@ -1425,9 +1567,9 @@ +@@ -1425,9 +1568,9 @@ super.jumpFromGround(); this.awardStat(StatisticList.JUMP); if (this.isSprinting()) { @@ -385,7 +396,7 @@ } } -@@ -1454,7 +1596,11 @@ +@@ -1454,7 +1597,11 @@ this.setDeltaMovement(vec3d2.x, d0 * 0.6D, vec3d2.z); this.resetFallDistance(); @@ -398,7 +409,7 @@ } else { super.travel(vec3d); } -@@ -1507,12 +1653,24 @@ +@@ -1507,12 +1654,24 @@ } public void startFallFlying() { @@ -424,7 +435,7 @@ } @Override -@@ -1626,10 +1784,21 @@ +@@ -1626,10 +1785,21 @@ return this.experienceLevel >= 30 ? 112 + (this.experienceLevel - 30) * 9 : (this.experienceLevel >= 15 ? 37 + (this.experienceLevel - 15) * 5 : 7 + this.experienceLevel * 2); } @@ -447,7 +458,7 @@ } } -@@ -1715,13 +1884,20 @@ +@@ -1715,13 +1885,20 @@ @Override public void setItemSlot(EnumItemSlot enumitemslot, ItemStack itemstack) { @@ -471,7 +482,7 @@ } } -@@ -1760,26 +1936,31 @@ +@@ -1760,26 +1937,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 68abd58e3d..7df84f4d69 100644 --- a/paper-server/nms-patches/net/minecraft/world/level/Explosion.patch +++ b/paper-server/nms-patches/net/minecraft/world/level/Explosion.patch @@ -96,7 +96,22 @@ } double d12 = (1.0D - d7) * (double) getSeenPercent(vec3d, entity); -@@ -287,9 +337,63 @@ +@@ -247,6 +297,14 @@ + d10 *= d13; + Vec3D vec3d1 = new Vec3D(d8, d9, d10); + ++ // CraftBukkit start - Call EntityKnockbackEvent ++ if (entity instanceof EntityLiving) { ++ Vec3D result = entity.getDeltaMovement().add(vec3d1); ++ org.bukkit.event.entity.EntityKnockbackEvent event = CraftEventFactory.callEntityKnockbackEvent((org.bukkit.craftbukkit.entity.CraftLivingEntity) entity.getBukkitEntity(), source, org.bukkit.event.entity.EntityKnockbackEvent.KnockbackCause.EXPLOSION, d13, vec3d1, result.x, result.y, result.z); ++ ++ vec3d1 = (event.isCancelled()) ? Vec3D.ZERO : new Vec3D(event.getFinalKnockback().getX(), event.getFinalKnockback().getY(), event.getFinalKnockback().getZ()); ++ } ++ // CraftBukkit end + entity.setDeltaMovement(entity.getDeltaMovement().add(vec3d1)); + if (entity instanceof EntityHuman) { + EntityHuman entityhuman = (EntityHuman) entity; +@@ -287,9 +345,63 @@ SystemUtils.shuffle(this.toBlow, this.level.random); ObjectListIterator objectlistiterator = this.toBlow.iterator(); @@ -160,7 +175,7 @@ this.level.getBlockState(blockposition).onExplosionHit(this.level, blockposition, this, (itemstack, blockposition1) -> { addOrAppendStack(list, itemstack, blockposition1); -@@ -314,7 +418,11 @@ +@@ -314,7 +426,11 @@ BlockPosition blockposition1 = (BlockPosition) objectlistiterator1.next(); if (this.random.nextInt(3) == 0 && this.level.getBlockState(blockposition1).isAir() && this.level.getBlockState(blockposition1.below()).isSolidRender(this.level, blockposition1.below())) { @@ -173,7 +188,7 @@ } } } -@@ -322,6 +430,7 @@ +@@ -322,6 +438,7 @@ } private static void addOrAppendStack(List> list, 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 c2e73cc702..c1c8e423ae 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 @@ -177,6 +177,8 @@ import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.event.entity.EntityEnterLoveModeEvent; import org.bukkit.event.entity.EntityExhaustionEvent; import org.bukkit.event.entity.EntityInteractEvent; +import org.bukkit.event.entity.EntityKnockbackByEntityEvent; +import org.bukkit.event.entity.EntityKnockbackEvent; import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.event.entity.EntityPlaceEvent; import org.bukkit.event.entity.EntityPotionEffectEvent; @@ -1884,4 +1886,18 @@ public class CraftEventFactory { Bukkit.getPluginManager().callEvent(event); return event; } + + public static EntityKnockbackEvent callEntityKnockbackEvent(CraftLivingEntity entity, Entity attacker, EntityKnockbackEvent.KnockbackCause cause, double force, Vec3D raw, double x, double y, double z) { + Vector bukkitRaw = new Vector(-raw.x, raw.y, -raw.z); // Due to how the knockback calculation works, we need to invert x and z. + + EntityKnockbackEvent event; + if (attacker != null) { + event = new EntityKnockbackByEntityEvent(entity, attacker.getBukkitEntity(), cause, force, new Vector(-raw.x, raw.y, -raw.z), new Vector(x, y, z)); + } else { + event = new EntityKnockbackEvent(entity, cause, force, new Vector(-raw.x, raw.y, -raw.z), new Vector(x, y, z)); + } + + Bukkit.getPluginManager().callEvent(event); + return event; + } }