diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/AbstractArrow.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/AbstractArrow.java.patch new file mode 100644 index 0000000000..e6732700cf --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/AbstractArrow.java.patch @@ -0,0 +1,224 @@ +--- a/net/minecraft/world/entity/projectile/AbstractArrow.java ++++ b/net/minecraft/world/entity/projectile/AbstractArrow.java +@@ -33,6 +_,7 @@ + import net.minecraft.world.entity.OminousItemSpawner; + import net.minecraft.world.entity.SlotAccess; + import net.minecraft.world.entity.ai.attributes.Attributes; ++import net.minecraft.world.entity.item.ItemEntity; + import net.minecraft.world.entity.player.Player; + import net.minecraft.world.item.Item; + import net.minecraft.world.item.ItemStack; +@@ -74,6 +_,16 @@ + @Nullable + private ItemStack firedFromWeapon = null; + ++ // Spigot Start ++ @Override ++ public void inactiveTick() { ++ if (this.isInGround()) { ++ this.life += 1; ++ } ++ super.inactiveTick(); ++ } ++ // Spigot End ++ + protected AbstractArrow(EntityType entityType, Level level) { + super(entityType, level); + } +@@ -87,7 +_,13 @@ + ItemStack pickupItemStack, + @Nullable ItemStack firedFromWeapon + ) { ++ // CraftBukkit start - handle the owner before the rest of things ++ this(entityType, x, y, z, level, pickupItemStack, firedFromWeapon, null); ++ } ++ protected AbstractArrow(EntityType entityType, double x, double y, double z, Level level, ItemStack pickupItemStack, @Nullable ItemStack firedFromWeapon, @Nullable LivingEntity ownerEntity) { + this(entityType, level); ++ this.setOwner(ownerEntity); ++ // CraftBukkit end + this.pickupItemStack = pickupItemStack.copy(); + this.setCustomName(pickupItemStack.get(DataComponents.CUSTOM_NAME)); + Unit unit = pickupItemStack.remove(DataComponents.INTANGIBLE_PROJECTILE); +@@ -112,8 +_,8 @@ + protected AbstractArrow( + EntityType entityType, LivingEntity owner, Level level, ItemStack pickupItemStack, @Nullable ItemStack firedFromWeapon + ) { +- this(entityType, owner.getX(), owner.getEyeY() - 0.1F, owner.getZ(), level, pickupItemStack, firedFromWeapon); +- this.setOwner(owner); ++ this(entityType, owner.getX(), owner.getEyeY() - 0.1F, owner.getZ(), level, pickupItemStack, firedFromWeapon, owner); // CraftBukkit ++ // this.setOwner(owner); // SPIGOT-7744 - Moved to the above constructor + } + + public void setSoundEvent(SoundEvent soundEvent) { +@@ -209,6 +_,7 @@ + this.applyEffectsFromBlocks(); + } + } else { ++ if (this.tickCount > 200) this.tickDespawn(); // Paper - tick despawnCounter regardless after 10 seconds + this.inGroundTime = 0; + Vec3 vec31 = this.position(); + if (this.isInWater()) { +@@ -275,12 +_,12 @@ + + if (entityHitResult == null) { + if (this.isAlive() && hitResult.getType() != HitResult.Type.MISS) { +- this.hitTargetOrDeflectSelf(hitResult); ++ this.preHitTargetOrDeflectSelf(hitResult); // CraftBukkit - projectile hit event + this.hasImpulse = true; + } + break; + } else if (this.isAlive() && !this.noPhysics) { +- ProjectileDeflection projectileDeflection = this.hitTargetOrDeflectSelf(entityHitResult); ++ ProjectileDeflection projectileDeflection = this.preHitTargetOrDeflectSelf(entityHitResult); // CraftBukkit - projectile hit event + this.hasImpulse = true; + if (this.getPierceLevel() > 0 && projectileDeflection == ProjectileDeflection.NONE) { + continue; +@@ -313,6 +_,19 @@ + } + } + ++ // Paper start - Fix cancelling ProjectileHitEvent for piercing arrows ++ @Override ++ public ProjectileDeflection preHitTargetOrDeflectSelf(HitResult hitResult) { ++ if (hitResult instanceof EntityHitResult entityHitResult && this.hitCancelled && this.getPierceLevel() > 0) { ++ if (this.piercingIgnoreEntityIds == null) { ++ this.piercingIgnoreEntityIds = new IntOpenHashSet(5); ++ } ++ this.piercingIgnoreEntityIds.add(entityHitResult.getEntity().getId()); ++ } ++ return super.preHitTargetOrDeflectSelf(hitResult); ++ } ++ // Paper end - Fix cancelling ProjectileHitEvent for piercing arrows ++ + @Override + protected double getDefaultGravity() { + return 0.05; +@@ -347,8 +_,8 @@ + + protected void tickDespawn() { + this.life++; +- if (this.life >= 1200) { +- this.discard(); ++ if (this.life >= (this.pickup == Pickup.CREATIVE_ONLY ? this.level().paperConfig().entities.spawning.creativeArrowDespawnRate.value() : (this.pickup == Pickup.DISALLOWED ? this.level().paperConfig().entities.spawning.nonPlayerArrowDespawnRate.value() : ((this instanceof ThrownTrident) ? this.level().spigotConfig.tridentDespawnRate : this.level().spigotConfig.arrowDespawnRate)))) { // Spigot // Paper - Configurable non-player arrow despawn rate; TODO: Extract this to init? ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause + } + } + +@@ -375,9 +_,9 @@ + } + + @Override +- public void push(double x, double y, double z) { ++ public void push(double x, double y, double z, @Nullable Entity pushingEntity) { // Paper - add push source entity param + if (!this.isInGround()) { +- super.push(x, y, z); ++ super.push(x, y, z, pushingEntity); // Paper - add push source entity param + } + } + +@@ -404,7 +_,7 @@ + } + + if (this.piercingIgnoreEntityIds.size() >= this.getPierceLevel() + 1) { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + return; + } + +@@ -420,10 +_,17 @@ + livingEntity.setLastHurtMob(entity); + } + ++ if (this.isCritArrow()) damageSource = damageSource.critical(); // Paper - add critical damage API + boolean flag = entity.getType() == EntityType.ENDERMAN; + int remainingFireTicks = entity.getRemainingFireTicks(); + if (this.isOnFire() && !flag) { +- entity.igniteForSeconds(5.0F); ++ // CraftBukkit start ++ org.bukkit.event.entity.EntityCombustByEntityEvent combustEvent = new org.bukkit.event.entity.EntityCombustByEntityEvent(this.getBukkitEntity(), entity.getBukkitEntity(), 5.0F); ++ org.bukkit.Bukkit.getPluginManager().callEvent(combustEvent); ++ if (!combustEvent.isCancelled()) { ++ entity.igniteForSeconds(combustEvent.getDuration(), false); ++ } ++ // CraftBukkit end + } + + if (entity.hurtOrSimulate(damageSource, ceil)) { +@@ -461,7 +_,7 @@ + + this.playSound(this.soundEvent, 1.0F, 1.2F / (this.random.nextFloat() * 0.2F + 0.9F)); + if (this.getPierceLevel() <= 0) { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + } + } else { + entity.setRemainingFireTicks(remainingFireTicks); +@@ -472,7 +_,7 @@ + this.spawnAtLocation(serverLevel2, this.getPickupItem(), 0.1F); + } + +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + } + } + } +@@ -485,7 +_,7 @@ + double max = Math.max(0.0, 1.0 - entity.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE)); + Vec3 vec3 = this.getDeltaMovement().multiply(1.0, 0.0, 1.0).normalize().scale(d * 0.6 * max); + if (vec3.lengthSqr() > 0.0) { +- entity.push(vec3.x, 0.1, vec3.z); ++ entity.push(vec3.x, 0.1, vec3.z, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent + } + } + } +@@ -597,7 +_,7 @@ + this.setPierceLevel(compound.getByte("PierceLevel")); + if (compound.contains("SoundEvent", 8)) { + this.soundEvent = BuiltInRegistries.SOUND_EVENT +- .getOptional(ResourceLocation.parse(compound.getString("SoundEvent"))) ++ .getOptional(ResourceLocation.tryParse(compound.getString("SoundEvent"))) // Paper - Validate resource location + .orElse(this.getDefaultHitGroundSoundEvent()); + } + +@@ -616,7 +_,14 @@ + + @Override + public void setOwner(@Nullable Entity entity) { ++ // Paper start - Fix PickupStatus getting reset ++ this.setOwner(entity, true); ++ } ++ ++ public void setOwner(@Nullable Entity entity, boolean resetPickup) { ++ // Paper end - Fix PickupStatus getting reset + super.setOwner(entity); ++ if (!resetPickup) return; // Paper - Fix PickupStatus getting reset + + this.pickup = switch (entity) { + case Player player when this.pickup == AbstractArrow.Pickup.DISALLOWED -> AbstractArrow.Pickup.ALLOWED; +@@ -628,9 +_,24 @@ + @Override + public void playerTouch(Player entity) { + if (!this.level().isClientSide && (this.isInGround() || this.isNoPhysics()) && this.shakeTime <= 0) { +- if (this.tryPickup(entity)) { ++ // CraftBukkit start ++ ItemStack itemstack = this.getPickupItem(); ++ if (this.pickup == Pickup.ALLOWED && !itemstack.isEmpty() && entity.getInventory().canHold(itemstack) > 0) { ++ ItemEntity item = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemstack); ++ org.bukkit.event.player.PlayerPickupArrowEvent event = new org.bukkit.event.player.PlayerPickupArrowEvent((org.bukkit.entity.Player) entity.getBukkitEntity(), new org.bukkit.craftbukkit.entity.CraftItem(this.level().getCraftServer(), item), (org.bukkit.entity.AbstractArrow) this.getBukkitEntity()); ++ // event.setCancelled(!entityhuman.canPickUpLoot); TODO ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return; ++ } ++ itemstack = item.getItem(); ++ } ++ ++ if ((this.pickup == AbstractArrow.Pickup.ALLOWED && entity.getInventory().add(itemstack)) || (this.pickup == AbstractArrow.Pickup.CREATIVE_ONLY && entity.getAbilities().instabuild)) { ++ // CraftBukkit end + entity.take(this, 1); +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause + } + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java.patch new file mode 100644 index 0000000000..75c739c6ba --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java.patch @@ -0,0 +1,26 @@ +--- a/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java ++++ b/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java +@@ -19,6 +_,8 @@ + public static final double INITAL_ACCELERATION_POWER = 0.1; + public static final double DEFLECTION_SCALE = 0.5; + public double accelerationPower = 0.1; ++ public float bukkitYield = 1; // CraftBukkit ++ public boolean isIncendiary = true; // CraftBukkit + + protected AbstractHurtingProjectile(EntityType entityType, Level level) { + super(entityType, level); +@@ -83,12 +_,12 @@ + } + + if (hitResultOnMoveVector.getType() != HitResult.Type.MISS && this.isAlive()) { +- this.hitTargetOrDeflectSelf(hitResultOnMoveVector); ++ this.preHitTargetOrDeflectSelf(hitResultOnMoveVector); + } + + this.createParticleTrail(); + } else { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause + } + } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/Arrow.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Arrow.java.patch new file mode 100644 index 0000000000..f23f9c6a7e --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Arrow.java.patch @@ -0,0 +1,17 @@ +--- a/net/minecraft/world/entity/projectile/Arrow.java ++++ b/net/minecraft/world/entity/projectile/Arrow.java +@@ -121,12 +_,13 @@ + mobEffectInstance.isVisible() + ), + effectSource ++ , org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ARROW // CraftBukkit + ); + } + } + + for (MobEffectInstance mobEffectInstance : potionContents.customEffects()) { +- living.addEffect(mobEffectInstance, effectSource); ++ living.addEffect(mobEffectInstance, effectSource, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ARROW); // CraftBukkit + } + } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/DragonFireball.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/DragonFireball.java.patch new file mode 100644 index 0000000000..b04695ec1e --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/DragonFireball.java.patch @@ -0,0 +1,16 @@ +--- a/net/minecraft/world/entity/projectile/DragonFireball.java ++++ b/net/minecraft/world/entity/projectile/DragonFireball.java +@@ -52,9 +_,11 @@ + } + } + ++ if (new com.destroystokyo.paper.event.entity.EnderDragonFireballHitEvent((org.bukkit.entity.DragonFireball) this.getBukkitEntity(), entitiesOfClass.stream().map(LivingEntity::getBukkitLivingEntity).collect(java.util.stream.Collectors.toList()), (org.bukkit.entity.AreaEffectCloud) areaEffectCloud.getBukkitEntity()).callEvent()) { // Paper - EnderDragon Events + this.level().levelEvent(2006, this.blockPosition(), this.isSilent() ? -1 : 1); +- this.level().addFreshEntity(areaEffectCloud); +- this.discard(); ++ this.level().addFreshEntity(areaEffectCloud, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EXPLOSION); // Paper - use correct spawn reason ++ } else areaEffectCloud.discard(null); // Paper - EnderDragon Events ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + } + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/EvokerFangs.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/EvokerFangs.java.patch new file mode 100644 index 0000000000..e980aa3858 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/EvokerFangs.java.patch @@ -0,0 +1,20 @@ +--- a/net/minecraft/world/entity/projectile/EvokerFangs.java ++++ b/net/minecraft/world/entity/projectile/EvokerFangs.java +@@ -109,7 +_,7 @@ + } + + if (--this.lifeTicks < 0) { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause + } + } + } +@@ -118,7 +_,7 @@ + LivingEntity owner = this.getOwner(); + if (target.isAlive() && !target.isInvulnerable() && target != owner) { + if (owner == null) { +- target.hurt(this.damageSources().magic(), 6.0F); ++ target.hurt(this.damageSources().magic().customEventDamager(this), 6.0F); // CraftBukkit // Paper - fix DamageSource API + } else { + if (owner.isAlliedTo(target)) { + return; diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/EyeOfEnder.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/EyeOfEnder.java.patch similarity index 53% rename from paper-server/patches/unapplied/net/minecraft/world/entity/projectile/EyeOfEnder.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/projectile/EyeOfEnder.java.patch index 67aa21fe00..450c900de3 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/EyeOfEnder.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/EyeOfEnder.java.patch @@ -1,16 +1,6 @@ --- a/net/minecraft/world/entity/projectile/EyeOfEnder.java +++ b/net/minecraft/world/entity/projectile/EyeOfEnder.java -@@ -17,6 +17,9 @@ - import net.minecraft.world.item.Items; - import net.minecraft.world.level.Level; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class EyeOfEnder extends Entity implements ItemSupplier { - -@@ -73,6 +76,11 @@ +@@ -70,6 +_,11 @@ } public void signalTo(BlockPos pos) { @@ -19,10 +9,10 @@ + } + public void signalTo(BlockPos pos, boolean update) { + // Paper end - Change EnderEye target without changing other things - double d0 = (double) pos.getX(); - int i = pos.getY(); - double d1 = (double) pos.getZ(); -@@ -90,8 +98,10 @@ + double d = pos.getX(); + int y = pos.getY(); + double d1 = pos.getZ(); +@@ -86,8 +_,10 @@ this.tz = d1; } @@ -33,24 +23,24 @@ } @Override -@@ -153,7 +163,7 @@ - ++this.life; +@@ -161,7 +_,7 @@ + this.life++; if (this.life > 80 && !this.level().isClientSide) { this.playSound(SoundEvents.ENDER_EYE_DEATH, 1.0F, 1.0F); - this.discard(); -+ this.discard(this.surviveAfterDeath ? EntityRemoveEvent.Cause.DROP : EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause ++ this.discard(this.surviveAfterDeath ? org.bukkit.event.entity.EntityRemoveEvent.Cause.DROP : org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause if (this.surviveAfterDeath) { this.level().addFreshEntity(new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), this.getItem())); } else { -@@ -174,7 +184,12 @@ +@@ -181,7 +_,12 @@ @Override - public void readAdditionalSaveData(CompoundTag nbt) { - if (nbt.contains("Item", 10)) { -- this.setItem((ItemStack) ItemStack.parse(this.registryAccess(), nbt.getCompound("Item")).orElse(this.getDefaultItem())); + public void readAdditionalSaveData(CompoundTag compound) { + if (compound.contains("Item", 10)) { +- this.setItem(ItemStack.parse(this.registryAccess(), compound.getCompound("Item")).orElse(this.getDefaultItem())); + // CraftBukkit start - SPIGOT-6103 summon, see also SPIGOT-5474 -+ ItemStack itemstack = (ItemStack) ItemStack.parse(this.registryAccess(), nbt.getCompound("Item")).orElse(this.getDefaultItem()); -+ if (!itemstack.isEmpty()) { -+ this.setItem(itemstack); ++ ItemStack itemStack = ItemStack.parse(this.registryAccess(), compound.getCompound("Item")).orElse(this.getDefaultItem()); ++ if (!itemStack.isEmpty()) { ++ this.setItem(itemStack); + } + // CraftBukkit end } else { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/Fireball.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Fireball.java.patch new file mode 100644 index 0000000000..96bac378a8 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Fireball.java.patch @@ -0,0 +1,16 @@ +--- a/net/minecraft/world/entity/projectile/Fireball.java ++++ b/net/minecraft/world/entity/projectile/Fireball.java +@@ -60,7 +_,12 @@ + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + if (compound.contains("Item", 10)) { +- this.setItem(ItemStack.parse(this.registryAccess(), compound.getCompound("Item")).orElse(this.getDefaultItem())); ++ // CraftBukkit start - SPIGOT-5474 probably came from bugged earlier versions ++ final ItemStack itemStack = ItemStack.parse(this.registryAccess(), compound.getCompound("Item")).orElse(this.getDefaultItem()); ++ if (!itemStack.isEmpty()) { ++ this.setItem(itemStack); ++ } ++ // CraftBukkit end + } else { + this.setItem(this.getDefaultItem()); + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch new file mode 100644 index 0000000000..fb50fc5183 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch @@ -0,0 +1,117 @@ +--- a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java ++++ b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java +@@ -43,6 +_,7 @@ + public int lifetime; + @Nullable + public LivingEntity attachedToEntity; ++ @Nullable public java.util.UUID spawningEntity; // Paper + + public FireworkRocketEntity(EntityType entityType, Level level) { + super(entityType, level); +@@ -84,6 +_,26 @@ + this.setOwner(shooter); + } + ++ // Spigot Start - copied from tick ++ @Override ++ public void inactiveTick() { ++ this.life += 1; ++ ++ if (this.life > this.lifetime) { ++ Level world = this.level(); ++ ++ if (world instanceof ServerLevel serverLevel) { ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) { ++ this.explode(serverLevel); ++ } ++ // CraftBukkit end ++ } ++ } ++ super.inactiveTick(); ++ } ++ // Spigot End ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(DATA_ID_FIREWORKS_ITEM, getDefaultItem()); +@@ -158,7 +_,7 @@ + } + + if (!this.noPhysics && this.isAlive() && hitResultOnMoveVector.getType() != HitResult.Type.MISS) { +- this.hitTargetOrDeflectSelf(hitResultOnMoveVector); ++ this.preHitTargetOrDeflectSelf(hitResultOnMoveVector); // CraftBukkit - projectile hit event + this.hasImpulse = true; + } + +@@ -182,7 +_,11 @@ + } + + if (this.life > this.lifetime && this.level() instanceof ServerLevel serverLevel) { +- this.explode(serverLevel); ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) { ++ this.explode(serverLevel); ++ } ++ // CraftBukkit end + } + } + +@@ -190,14 +_,18 @@ + level.broadcastEntityEvent(this, (byte)17); + this.gameEvent(GameEvent.EXPLODE, this.getOwner()); + this.dealExplosionDamage(level); +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause + } + + @Override + protected void onHitEntity(EntityHitResult result) { + super.onHitEntity(result); + if (this.level() instanceof ServerLevel serverLevel) { +- this.explode(serverLevel); ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) { ++ this.explode(serverLevel); ++ } ++ // CraftBukkit end + } + } + +@@ -206,7 +_,11 @@ + BlockPos blockPos = new BlockPos(result.getBlockPos()); + this.level().getBlockState(blockPos).entityInside(this.level(), blockPos, this); + if (this.level() instanceof ServerLevel serverLevel && this.hasExplosion()) { +- this.explode(serverLevel); ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) { ++ this.explode(serverLevel); ++ } ++ // CraftBukkit end + } + + super.onHitBlock(result); +@@ -278,6 +_,11 @@ + compound.putInt("LifeTime", this.lifetime); + compound.put("FireworksItem", this.getItem().save(this.registryAccess())); + compound.putBoolean("ShotAtAngle", this.entityData.get(DATA_SHOT_AT_ANGLE)); ++ // Paper start ++ if (this.spawningEntity != null) { ++ compound.putUUID("SpawningEntity", this.spawningEntity); ++ } ++ // Paper end + } + + @Override +@@ -298,6 +_,11 @@ + if (compound.contains("ShotAtAngle")) { + this.entityData.set(DATA_SHOT_AT_ANGLE, compound.getBoolean("ShotAtAngle")); + } ++ // Paper start ++ if (compound.hasUUID("SpawningEntity")) { ++ this.spawningEntity = compound.getUUID("SpawningEntity"); ++ } ++ // Paper end + } + + private List getExplosions() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/FishingHook.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/FishingHook.java.patch new file mode 100644 index 0000000000..68d1d7f9e5 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/FishingHook.java.patch @@ -0,0 +1,281 @@ +--- a/net/minecraft/world/entity/projectile/FishingHook.java ++++ b/net/minecraft/world/entity/projectile/FishingHook.java +@@ -66,10 +_,26 @@ + private final int luck; + private final int lureSpeed; + ++ // CraftBukkit start - Extra variables to enable modification of fishing wait time, values are minecraft defaults ++ public int minWaitTime = 100; ++ public int maxWaitTime = 600; ++ public int minLureTime = 20; ++ public int maxLureTime = 80; ++ public float minLureAngle = 0.0F; ++ public float maxLureAngle = 360.0F; ++ public boolean applyLure = true; ++ public boolean rainInfluenced = true; ++ public boolean skyInfluenced = true; ++ // CraftBukkit end ++ + private FishingHook(EntityType entityType, Level level, int luck, int lureSpeed) { + super(entityType, level); + this.luck = Math.max(0, luck); + this.lureSpeed = Math.max(0, lureSpeed); ++ // Paper start - Configurable fishing time ranges ++ this.minWaitTime = level.paperConfig().fishingTimeRange.minimum; ++ this.maxWaitTime = level.paperConfig().fishingTimeRange.maximum; ++ // Paper end - Configurable fishing time ranges + } + + public FishingHook(EntityType entityType, Level level) { +@@ -147,12 +_,12 @@ + super.tick(); + Player playerOwner = this.getPlayerOwner(); + if (playerOwner == null) { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause + } else if (this.level().isClientSide || !this.shouldStopFishing(playerOwner)) { + if (this.onGround()) { + this.life++; + if (this.life >= 1200) { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause + return; + } + } else { +@@ -251,14 +_,14 @@ + if (!player.isRemoved() && player.isAlive() && (isFishingRod || isFishingRod1) && !(this.distanceToSqr(player) > 1024.0)) { + return false; + } else { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause + return true; + } + } + + private void checkCollision() { + HitResult hitResultOnMoveVector = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); +- this.hitTargetOrDeflectSelf(hitResultOnMoveVector); ++ this.preHitTargetOrDeflectSelf(hitResultOnMoveVector); + } + + @Override +@@ -289,11 +_,11 @@ + ServerLevel serverLevel = (ServerLevel)this.level(); + int i = 1; + BlockPos blockPos = pos.above(); +- if (this.random.nextFloat() < 0.25F && this.level().isRainingAt(blockPos)) { ++ if (this.rainInfluenced && this.random.nextFloat() < 0.25F && this.level().isRainingAt(blockPos)) { // CraftBukkit + i++; + } + +- if (this.random.nextFloat() < 0.5F && !this.level().canSeeSky(blockPos)) { ++ if (this.skyInfluenced && this.random.nextFloat() < 0.5F && !this.level().canSeeSky(blockPos)) { // CraftBukkit + i--; + } + +@@ -303,6 +_,10 @@ + this.timeUntilLured = 0; + this.timeUntilHooked = 0; + this.getEntityData().set(DATA_BITING, false); ++ // CraftBukkit start ++ org.bukkit.event.player.PlayerFishEvent playerFishEvent = new org.bukkit.event.player.PlayerFishEvent((org.bukkit.entity.Player) this.getPlayerOwner().getBukkitEntity(), null, (org.bukkit.entity.FishHook) this.getBukkitEntity(), org.bukkit.event.player.PlayerFishEvent.State.FAILED_ATTEMPT); ++ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); ++ // CraftBukkit end + } + } else if (this.timeUntilHooked > 0) { + this.timeUntilHooked -= i; +@@ -326,6 +_,13 @@ + serverLevel.sendParticles(ParticleTypes.FISHING, d, d1, d2, 0, -f2, 0.01, f1, 1.0); + } + } else { ++ // CraftBukkit start ++ org.bukkit.event.player.PlayerFishEvent playerFishEvent = new org.bukkit.event.player.PlayerFishEvent((org.bukkit.entity.Player) this.getPlayerOwner().getBukkitEntity(), null, (org.bukkit.entity.FishHook) this.getBukkitEntity(), org.bukkit.event.player.PlayerFishEvent.State.BITE); ++ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); ++ if (playerFishEvent.isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + this.playSound(SoundEvents.FISHING_BOBBER_SPLASH, 0.25F, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.4F); + double d3 = this.getY() + 0.5; + serverLevel.sendParticles( +@@ -377,14 +_,33 @@ + } + + if (this.timeUntilLured <= 0) { +- this.fishAngle = Mth.nextFloat(this.random, 0.0F, 360.0F); +- this.timeUntilHooked = Mth.nextInt(this.random, 20, 80); ++ // CraftBukkit start - logic to modify fishing wait time, lure time, and lure angle ++ this.fishAngle = Mth.nextFloat(this.random, this.minLureAngle, this.maxLureAngle); ++ this.timeUntilHooked = Mth.nextInt(this.random, this.minLureTime, this.maxLureTime); ++ // CraftBukkit end ++ // Paper start - Add missing fishing event state ++ if (this.getPlayerOwner() != null) { ++ org.bukkit.event.player.PlayerFishEvent playerFishEvent = new org.bukkit.event.player.PlayerFishEvent((org.bukkit.entity.Player) this.getPlayerOwner().getBukkitEntity(), null, (org.bukkit.entity.FishHook) this.getBukkitEntity(), org.bukkit.event.player.PlayerFishEvent.State.LURED); ++ if (!playerFishEvent.callEvent()) { ++ this.timeUntilHooked = 0; ++ return; ++ } ++ } ++ // Paper end - Add missing fishing event state + } + } else { +- this.timeUntilLured = Mth.nextInt(this.random, 100, 600); +- this.timeUntilLured = this.timeUntilLured - this.lureSpeed; ++ // CraftBukkit start - logic to modify fishing wait time ++ this.resetTimeUntilLured(); // Paper - more projectile api - extract time until lured reset logic ++ // CraftBukkit end + } + } ++ ++ // Paper start - more projectile api - extract time until lured reset logic ++ public void resetTimeUntilLured() { ++ this.timeUntilLured = Mth.nextInt(this.random, this.minWaitTime, this.maxWaitTime); ++ this.timeUntilLured -= (this.applyLure) ? (this.lureSpeed >= this.maxWaitTime ? this.timeUntilLured - 1 : this.lureSpeed ) : 0; // Paper - Fix Lure infinite loop ++ } ++ // Paper end - more projectile api - extract time until lured reset logic + + public boolean calculateOpenWater(BlockPos pos) { + FishingHook.OpenWaterType openWaterType = FishingHook.OpenWaterType.INVALID; +@@ -443,15 +_,34 @@ + public void readAdditionalSaveData(CompoundTag compound) { + } + ++ ++ // Paper start - Add hand parameter to PlayerFishEvent ++ @Deprecated ++ @io.papermc.paper.annotation.DoNotUse + public int retrieve(ItemStack stack) { ++ return this.retrieve(net.minecraft.world.InteractionHand.MAIN_HAND, stack); ++ } ++ ++ public int retrieve(net.minecraft.world.InteractionHand hand, ItemStack stack) { ++ // Paper end - Add hand parameter to PlayerFishEvent + Player playerOwner = this.getPlayerOwner(); + if (!this.level().isClientSide && playerOwner != null && !this.shouldStopFishing(playerOwner)) { + int i = 0; + if (this.hookedIn != null) { ++ // CraftBukkit start ++ org.bukkit.event.player.PlayerFishEvent playerFishEvent = new org.bukkit.event.player.PlayerFishEvent((org.bukkit.entity.Player) playerOwner.getBukkitEntity(), this.hookedIn.getBukkitEntity(), (org.bukkit.entity.FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), org.bukkit.event.player.PlayerFishEvent.State.CAUGHT_ENTITY); // Paper - Add hand parameter to PlayerFishEvent ++ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); ++ ++ if (playerFishEvent.isCancelled()) { ++ return 0; ++ } ++ if (this.hookedIn != null) { // Paper - re-check to see if there is a hooked entity ++ // CraftBukkit end + this.pullEntity(this.hookedIn); + CriteriaTriggers.FISHING_ROD_HOOKED.trigger((ServerPlayer)playerOwner, stack, this, Collections.emptyList()); + this.level().broadcastEntityEvent(this, (byte)31); + i = this.hookedIn instanceof ItemEntity ? 3 : 5; ++ } // Paper - re-check to see if there is a hooked entity + } else if (this.nibble > 0) { + LootParams lootParams = new LootParams.Builder((ServerLevel)this.level()) + .withParameter(LootContextParams.ORIGIN, this.position()) +@@ -464,19 +_,43 @@ + CriteriaTriggers.FISHING_ROD_HOOKED.trigger((ServerPlayer)playerOwner, stack, this, randomItems); + + for (ItemStack itemStack : randomItems) { +- ItemEntity itemEntity = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemStack); ++ // Paper start - new ItemEntity would throw if for whatever reason (mostly shitty datapacks) the itemStack turns out to be empty ++ // if the item stack is empty we instead just have our itemEntity as null ++ ItemEntity itemEntity = null; ++ if (!itemStack.isEmpty()) { ++ itemEntity = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemStack); ++ } ++ // Paper end ++ // CraftBukkit start ++ org.bukkit.event.player.PlayerFishEvent playerFishEvent = new org.bukkit.event.player.PlayerFishEvent((org.bukkit.entity.Player) playerOwner.getBukkitEntity(), itemEntity != null ? itemEntity.getBukkitEntity() : null, (org.bukkit.entity.FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), org.bukkit.event.player.PlayerFishEvent.State.CAUGHT_FISH); // Paper - itemEntity may be null // Paper - Add hand parameter to PlayerFishEvent ++ playerFishEvent.setExpToDrop(this.random.nextInt(6) + 1); ++ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); ++ ++ if (playerFishEvent.isCancelled()) { ++ return 0; ++ } ++ // CraftBukkit end + double d = playerOwner.getX() - this.getX(); + double d1 = playerOwner.getY() - this.getY(); + double d2 = playerOwner.getZ() - this.getZ(); + double d3 = 0.1; +- itemEntity.setDeltaMovement(d * 0.1, d1 * 0.1 + Math.sqrt(Math.sqrt(d * d + d1 * d1 + d2 * d2)) * 0.08, d2 * 0.1); +- this.level().addFreshEntity(itemEntity); +- playerOwner.level() +- .addFreshEntity( +- new ExperienceOrb( +- playerOwner.level(), playerOwner.getX(), playerOwner.getY() + 0.5, playerOwner.getZ() + 0.5, this.random.nextInt(6) + 1 +- ) +- ); ++ // Paper start - entity item can be null, so we need to check against this ++ if (itemEntity != null) { ++ itemEntity.setDeltaMovement(d * 0.1, d1 * 0.1 + Math.sqrt(Math.sqrt(d * d + d1 * d1 + d2 * d2)) * 0.08, d2 * 0.1); ++ this.level().addFreshEntity(itemEntity); ++ } ++ // Paper end ++ // CraftBukkit start - this.random.nextInt(6) + 1 -> playerFishEvent.getExpToDrop() ++ if (playerFishEvent.getExpToDrop() > 0) { ++ playerOwner.level() ++ .addFreshEntity( ++ new ExperienceOrb( ++ playerOwner.level(), playerOwner.getX(), playerOwner.getY() + 0.5, playerOwner.getZ() + 0.5, playerFishEvent.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.FISHING, this.getPlayerOwner(), this // Paper ++ ) ++ ); ++ } ++ // CraftBukkit end ++ + if (itemStack.is(ItemTags.FISHES)) { + playerOwner.awardStat(Stats.FISH_CAUGHT, 1); + } +@@ -486,10 +_,27 @@ + } + + if (this.onGround()) { ++ // CraftBukkit start ++ org.bukkit.event.player.PlayerFishEvent playerFishEvent = new org.bukkit.event.player.PlayerFishEvent((org.bukkit.entity.Player) playerOwner.getBukkitEntity(), null, (org.bukkit.entity.FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), org.bukkit.event.player.PlayerFishEvent.State.IN_GROUND); // Paper - Add hand parameter to PlayerFishEvent ++ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); ++ ++ if (playerFishEvent.isCancelled()) { ++ return 0; ++ } ++ // CraftBukkit end + i = 2; + } ++ // CraftBukkit start ++ if (i == 0) { ++ org.bukkit.event.player.PlayerFishEvent playerFishEvent = new org.bukkit.event.player.PlayerFishEvent((org.bukkit.entity.Player) playerOwner.getBukkitEntity(), null, (org.bukkit.entity.FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), org.bukkit.event.player.PlayerFishEvent.State.REEL_IN); // Paper - Add hand parameter to PlayerFishEvent ++ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); ++ if (playerFishEvent.isCancelled()) { ++ return 0; ++ } ++ } ++ // CraftBukkit end + +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause + return i; + } else { + return 0; +@@ -520,8 +_,15 @@ + + @Override + public void remove(Entity.RemovalReason reason) { ++ // CraftBukkit start - add Bukkit remove cause ++ this.remove(reason, null); ++ } ++ ++ @Override ++ public void remove(Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.Cause cause) { ++ // CraftBukkit end + this.updateOwnerInfo(null); +- super.remove(reason); ++ super.remove(reason, cause); // CraftBukkit - add Bukkit remove cause + } + + @Override +@@ -570,7 +_,7 @@ + if (this.getPlayerOwner() == null) { + int data = packet.getData(); + LOGGER.error("Failed to recreate fishing hook on client. {} (id: {}) is not a valid owner.", this.level().getEntity(data), data); +- this.discard(); ++ this.discard(null); // CraftBukkit - add Bukkit remove cause + } + } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/LargeFireball.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/LargeFireball.java.patch new file mode 100644 index 0000000000..d484e6d4eb --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/LargeFireball.java.patch @@ -0,0 +1,45 @@ +--- a/net/minecraft/world/entity/projectile/LargeFireball.java ++++ b/net/minecraft/world/entity/projectile/LargeFireball.java +@@ -18,11 +_,13 @@ + + public LargeFireball(EntityType entityType, Level level) { + super(entityType, level); ++ this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit + } + + public LargeFireball(Level level, LivingEntity owner, Vec3 movement, int explosionPower) { + super(EntityType.FIREBALL, owner, movement, level); + this.explosionPower = explosionPower; ++ this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit + } + + @Override +@@ -30,8 +_,16 @@ + super.onHit(result); + if (this.level() instanceof ServerLevel serverLevel) { + boolean _boolean = serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); +- this.level().explode(this, this.getX(), this.getY(), this.getZ(), this.explosionPower, _boolean, Level.ExplosionInteraction.MOB); +- this.discard(); ++ // CraftBukkit start - fire ExplosionPrimeEvent ++ org.bukkit.event.entity.ExplosionPrimeEvent event = new org.bukkit.event.entity.ExplosionPrimeEvent((org.bukkit.entity.Explosive) this.getBukkitEntity()); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ // give 'this' instead of (Entity) null so we know what causes the damage ++ this.level().explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); ++ } ++ // CraftBukkit end ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + } + } + +@@ -57,7 +_,8 @@ + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + if (compound.contains("ExplosionPower", 99)) { +- this.explosionPower = compound.getByte("ExplosionPower"); ++ // CraftBukkit - set bukkitYield when setting explosionpower ++ this.bukkitYield = this.explosionPower = compound.getByte("ExplosionPower"); + } + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/LlamaSpit.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/LlamaSpit.java.patch new file mode 100644 index 0000000000..1e27f667a5 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/LlamaSpit.java.patch @@ -0,0 +1,31 @@ +--- a/net/minecraft/world/entity/projectile/LlamaSpit.java ++++ b/net/minecraft/world/entity/projectile/LlamaSpit.java +@@ -43,16 +_,16 @@ + super.tick(); + Vec3 deltaMovement = this.getDeltaMovement(); + HitResult hitResultOnMoveVector = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); +- this.hitTargetOrDeflectSelf(hitResultOnMoveVector); ++ this.preHitTargetOrDeflectSelf(hitResultOnMoveVector); // CraftBukkit - projectile hit event + double d = this.getX() + deltaMovement.x; + double d1 = this.getY() + deltaMovement.y; + double d2 = this.getZ() + deltaMovement.z; + this.updateRotation(); + float f = 0.99F; + if (this.level().getBlockStates(this.getBoundingBox()).noneMatch(BlockBehaviour.BlockStateBase::isAir)) { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause + } else if (this.isInWaterOrBubble()) { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause + } else { + this.setDeltaMovement(deltaMovement.scale(0.99F)); + this.applyGravity(); +@@ -76,7 +_,7 @@ + protected void onHitBlock(BlockHitResult result) { + super.onHitBlock(result); + if (!this.level().isClientSide) { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + } + } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch new file mode 100644 index 0000000000..637335db7b --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch @@ -0,0 +1,230 @@ +--- a/net/minecraft/world/entity/projectile/Projectile.java ++++ b/net/minecraft/world/entity/projectile/Projectile.java +@@ -43,6 +_,7 @@ + public boolean hasBeenShot; + @Nullable + private Entity lastDeflectedBy; ++ protected boolean hitCancelled = false; // CraftBukkit + + Projectile(EntityType entityType, Level level) { + super(entityType, level); +@@ -53,15 +_,36 @@ + this.ownerUUID = owner.getUUID(); + this.cachedOwner = owner; + } +- } ++ // Paper start - Refresh ProjectileSource for projectiles ++ else { ++ this.ownerUUID = null; ++ this.cachedOwner = null; ++ this.projectileSource = null; ++ } ++ // Paper end - Refresh ProjectileSource for projectiles ++ this.refreshProjectileSource(false); // Paper ++ } ++ ++ // Paper start - Refresh ProjectileSource for projectiles ++ public void refreshProjectileSource(boolean fillCache) { ++ if (fillCache) { ++ this.getOwner(); ++ } ++ if (this.cachedOwner != null && !this.cachedOwner.isRemoved() && this.projectileSource == null && this.cachedOwner.getBukkitEntity() instanceof org.bukkit.projectiles.ProjectileSource projSource) { ++ this.projectileSource = projSource; ++ } ++ } ++ // Paper end - Refresh ProjectileSource for projectiles + + @Nullable + @Override + public Entity getOwner() { + if (this.cachedOwner != null && !this.cachedOwner.isRemoved()) { ++ this.refreshProjectileSource(false); // Paper - Refresh ProjectileSource for projectiles + return this.cachedOwner; + } else if (this.ownerUUID != null) { + this.cachedOwner = this.findOwner(this.ownerUUID); ++ this.refreshProjectileSource(false); // Paper - Refresh ProjectileSource for projectiles + return this.cachedOwner; + } else { + return null; +@@ -98,6 +_,7 @@ + protected void readAdditionalSaveData(CompoundTag compound) { + if (compound.hasUUID("Owner")) { + this.setOwnerThroughUUID(compound.getUUID("Owner")); ++ if (this instanceof ThrownEnderpearl && this.level().paperConfig().fixes.disableUnloadedChunkEnderpearlExploit && this.level().paperConfig().misc.legacyEnderPearlBehavior) { this.ownerUUID = null; } // Paper - Reset pearls when they stop being ticked; Don't store shooter name for pearls to block enderpearl travel exploit + } + + this.leftOwner = compound.getBoolean("LeftOwner"); +@@ -175,13 +_,22 @@ + float f2 = Mth.cos(y * (float) (Math.PI / 180.0)) * Mth.cos(x * (float) (Math.PI / 180.0)); + this.shoot(f, f1, f2, velocity, inaccuracy); + Vec3 knownMovement = shooter.getKnownMovement(); ++ // Paper start - allow disabling relative velocity ++ if (!shooter.level().paperConfig().misc.disableRelativeProjectileVelocity) { + this.setDeltaMovement(this.getDeltaMovement().add(knownMovement.x, shooter.onGround() ? 0.0 : knownMovement.y, knownMovement.z)); ++ } ++ // Paper end - allow disabling relative velocity + } + + public static T spawnProjectileFromRotation( + Projectile.ProjectileFactory factory, ServerLevel level, ItemStack spawnedFrom, LivingEntity owner, float z, float velocity, float innaccuracy + ) { +- return spawnProjectile( ++ // Paper start - PlayerLaunchProjectileEvent ++ return spawnProjectileFromRotationDelayed(factory, level, spawnedFrom, owner, z, velocity, innaccuracy).spawn(); ++ } ++ public static Delayed spawnProjectileFromRotationDelayed(Projectile.ProjectileFactory factory, ServerLevel level, ItemStack spawnedFrom, LivingEntity owner, float z, float velocity, float innaccuracy) { ++ return spawnProjectileDelayed( ++ // Paper end - PlayerLaunchProjectileEvent + factory.create(level, owner, spawnedFrom), + level, + spawnedFrom, +@@ -200,7 +_,22 @@ + float velocity, + float inaccuracy + ) { +- return spawnProjectile(factory.create(level, owner, spawnedFrom), level, spawnedFrom, projectile -> projectile.shoot(x, y, z, velocity, inaccuracy)); ++ // Paper start - fixes and addition to spawn reason API ++ return Projectile.spawnProjectileUsingShootDelayed(factory, level, spawnedFrom, owner, x, y, z, velocity, inaccuracy).spawn(); ++ } ++ public static Delayed spawnProjectileUsingShootDelayed( ++ Projectile.ProjectileFactory factory, ++ ServerLevel level, ++ ItemStack spawnedFrom, ++ LivingEntity owner, ++ double x, ++ double y, ++ double z, ++ float velocity, ++ float inaccuracy ++ ) { ++ return spawnProjectileDelayed(factory.create(level, owner, spawnedFrom), level, spawnedFrom, projectile -> projectile.shoot(x, y, z, velocity, inaccuracy)); ++ // Paper end - fixes and addition to spawn reason API + } + + public static T spawnProjectileUsingShoot( +@@ -214,11 +_,45 @@ + } + + public static T spawnProjectile(T projectile, ServerLevel level, ItemStack stack, Consumer adapter) { ++ // Paper start - delayed projectile spawning ++ return spawnProjectileDelayed(projectile, level, stack, adapter).spawn(); ++ } ++ public static Delayed spawnProjectileDelayed(T projectile, ServerLevel level, ItemStack stack, Consumer adapter) { ++ // Paper end - delayed projectile spawning + adapter.accept(projectile); +- level.addFreshEntity(projectile); +- projectile.applyOnProjectileSpawned(level, stack); +- return projectile; +- } ++ return new Delayed<>(projectile, level, stack); // Paper - delayed projectile spawning ++ } ++ ++ // Paper start - delayed projectile spawning ++ public record Delayed( ++ T projectile, ++ ServerLevel world, ++ ItemStack projectileStack ++ ) { ++ // Taken from net.minecraft.world.entity.projectile.Projectile.spawnProjectile(T, net.minecraft.server.level.ServerLevel, net.minecraft.world.item.ItemStack, java.util.function.Consumer) ++ public boolean attemptSpawn() { ++ if (!this.world.addFreshEntity(this.projectile)) return false; ++ this.projectile.applyOnProjectileSpawned(this.world, this.projectileStack); ++ return true; ++ } ++ ++ public T spawn() { ++ this.attemptSpawn(); ++ return this.projectile(); ++ } ++ ++ public boolean attemptSpawn(final org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { ++ if (!this.world.addFreshEntity(this.projectile, reason)) return false; ++ this.projectile.applyOnProjectileSpawned(this.world, this.projectileStack); ++ return true; ++ } ++ ++ public T spawn(final org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { ++ this.attemptSpawn(reason); ++ return this.projectile(); ++ } ++ } ++ // Paper end - delayed projectile spawning + + public void applyOnProjectileSpawned(ServerLevel level, ItemStack spawnedFrom) { + EnchantmentHelper.onProjectileSpawned(level, spawnedFrom, this, item -> {}); +@@ -230,6 +_,17 @@ + } + } + ++ // CraftBukkit start - call projectile hit event ++ public ProjectileDeflection preHitTargetOrDeflectSelf(HitResult hitResult) { // Paper - protected -> public ++ org.bukkit.event.entity.ProjectileHitEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callProjectileHitEvent(this, hitResult); ++ this.hitCancelled = event != null && event.isCancelled(); ++ if (hitResult.getType() == HitResult.Type.BLOCK || !this.hitCancelled) { ++ return this.hitTargetOrDeflectSelf(hitResult); ++ } ++ return ProjectileDeflection.NONE; ++ } ++ // CraftBukkit end ++ + protected ProjectileDeflection hitTargetOrDeflectSelf(HitResult hitResult) { + if (hitResult.getType() == HitResult.Type.ENTITY) { + EntityHitResult entityHitResult = (EntityHitResult)hitResult; +@@ -261,7 +_,13 @@ + public boolean deflect(ProjectileDeflection deflection, @Nullable Entity entity, @Nullable Entity owner, boolean deflectedByPlayer) { + deflection.deflect(this, entity, this.random); + if (!this.level().isClientSide) { +- this.setOwner(owner); ++ // Paper start - Fix PickupStatus getting reset ++ if (this instanceof AbstractArrow arrow) { ++ arrow.setOwner(owner, false); ++ } else { ++ this.setOwner(owner); ++ } ++ // Paper end - Fix PickupStatus getting reset + this.onDeflection(entity, deflectedByPlayer); + } + +@@ -297,6 +_,11 @@ + } + + protected void onHitBlock(BlockHitResult result) { ++ // CraftBukkit start - cancellable hit event ++ if (this.hitCancelled) { ++ return; ++ } ++ // CraftBukkit end + BlockState blockState = this.level().getBlockState(result.getBlockPos()); + blockState.onProjectileHit(this.level(), blockState, result, this); + } +@@ -306,6 +_,15 @@ + return false; + } else { + Entity owner = this.getOwner(); ++ // Paper start - Cancel hit for vanished players ++ if (owner instanceof net.minecraft.server.level.ServerPlayer && target instanceof net.minecraft.server.level.ServerPlayer) { ++ org.bukkit.entity.Player collided = (org.bukkit.entity.Player) target.getBukkitEntity(); ++ org.bukkit.entity.Player shooter = (org.bukkit.entity.Player) owner.getBukkitEntity(); ++ if (!shooter.canSee(collided)) { ++ return false; ++ } ++ } ++ // Paper end - Cancel hit for vanished players + return owner == null || this.leftOwner || !owner.isPassengerOfSameVehicle(target); + } + } +@@ -318,13 +_,7 @@ + } + + protected static float lerpRotation(float currentRotation, float targetRotation) { +- while (targetRotation - currentRotation < -180.0F) { +- currentRotation -= 360.0F; +- } +- +- while (targetRotation - currentRotation >= 180.0F) { +- currentRotation += 360.0F; +- } ++ currentRotation += Math.round((targetRotation - currentRotation) / 360.0F) * 360.0F; // Paper - stop large look changes from crashing the server + + return Mth.lerp(0.2F, currentRotation, targetRotation); + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch new file mode 100644 index 0000000000..310b6cb4c4 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch @@ -0,0 +1,91 @@ +--- a/net/minecraft/world/entity/projectile/ShulkerBullet.java ++++ b/net/minecraft/world/entity/projectile/ShulkerBullet.java +@@ -57,7 +_,21 @@ + this.finalTarget = finalTarget; + this.currentMoveDirection = Direction.UP; + this.selectNextMoveDirection(axis); +- } ++ this.projectileSource = shooter.getBukkitLivingEntity(); // CraftBukkit ++ } ++ ++ // CraftBukkit start ++ @Nullable ++ public Entity getTarget() { ++ return this.finalTarget; ++ } ++ ++ public void setTarget(Entity e) { ++ this.finalTarget = e; ++ this.currentMoveDirection = Direction.UP; ++ this.selectNextMoveDirection(Direction.Axis.X); ++ } ++ // CraftBukkit end + + @Override + public SoundSource getSoundSource() { +@@ -187,7 +_,7 @@ + @Override + public void checkDespawn() { + if (this.level().getDifficulty() == Difficulty.PEACEFUL) { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause + } + } + +@@ -233,7 +_,7 @@ + } + + if (hitResult != null && this.isAlive() && hitResult.getType() != HitResult.Type.MISS) { +- this.hitTargetOrDeflectSelf(hitResult); ++ this.preHitTargetOrDeflectSelf(hitResult); // CraftBukkit - projectile hit event + } + + ProjectileUtil.rotateTowardsMovement(this, 0.5F); +@@ -301,7 +_,7 @@ + } + + if (entity instanceof LivingEntity livingEntity1) { +- livingEntity1.addEffect(new MobEffectInstance(MobEffects.LEVITATION, 200), MoreObjects.firstNonNull(owner, this)); ++ livingEntity1.addEffect(new MobEffectInstance(MobEffects.LEVITATION, 200), MoreObjects.firstNonNull(owner, this), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + } + } + } +@@ -314,14 +_,20 @@ + } + + private void destroy() { +- this.discard(); ++ // CraftBukkit start - add Bukkit remove cause ++ this.destroy(null); ++ } ++ ++ private void destroy(org.bukkit.event.entity.EntityRemoveEvent.Cause cause) { ++ this.discard(cause); ++ // CraftBukkit end + this.level().gameEvent(GameEvent.ENTITY_DAMAGE, this.position(), GameEvent.Context.of(this)); + } + + @Override + protected void onHit(HitResult result) { + super.onHit(result); +- this.destroy(); ++ this.destroy(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + } + + @Override +@@ -336,9 +_,14 @@ + + @Override + public boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) { ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount, false)) { ++ return false; ++ } ++ // CraftBukkit end + this.playSound(SoundEvents.SHULKER_BULLET_HURT, 1.0F, 1.0F); + level.sendParticles(ParticleTypes.CRIT, this.getX(), this.getY(), this.getZ(), 15, 0.2, 0.2, 0.2, 0.0); +- this.destroy(); ++ this.destroy(org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause + return true; + } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/SmallFireball.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/SmallFireball.java.patch new file mode 100644 index 0000000000..ceefdcdb81 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/SmallFireball.java.patch @@ -0,0 +1,51 @@ +--- a/net/minecraft/world/entity/projectile/SmallFireball.java ++++ b/net/minecraft/world/entity/projectile/SmallFireball.java +@@ -23,6 +_,11 @@ + + public SmallFireball(Level level, LivingEntity owner, Vec3 movement) { + super(EntityType.SMALL_FIREBALL, owner, movement, level); ++ // CraftBukkit start ++ if (this.getOwner() != null && this.getOwner() instanceof Mob) { ++ this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); ++ } ++ // CraftBukkit end + } + + public SmallFireball(Level level, double x, double y, double z, Vec3 movement) { +@@ -36,7 +_,14 @@ + Entity var7 = result.getEntity(); + Entity owner = this.getOwner(); + int remainingFireTicks = var7.getRemainingFireTicks(); +- var7.igniteForSeconds(5.0F); ++ // CraftBukkit start - Entity damage by entity event + combust event ++ org.bukkit.event.entity.EntityCombustByEntityEvent event = new org.bukkit.event.entity.EntityCombustByEntityEvent(this.getBukkitEntity(), var7.getBukkitEntity(), 5.0F); ++ var7.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ var7.igniteForSeconds(event.getDuration(), false); ++ } ++ // CraftBukkit end + DamageSource damageSource = this.damageSources().fireball(this, owner); + if (!var7.hurtServer(serverLevel, damageSource, 5.0F)) { + var7.setRemainingFireTicks(remainingFireTicks); +@@ -51,9 +_,9 @@ + super.onHitBlock(result); + if (this.level() instanceof ServerLevel serverLevel) { + Entity owner = this.getOwner(); +- if (!(owner instanceof Mob) || serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { ++ if (this.isIncendiary) { // CraftBukkit + BlockPos blockPos = result.getBlockPos().relative(result.getDirection()); +- if (this.level().isEmptyBlock(blockPos)) { ++ if (this.level().isEmptyBlock(blockPos) && !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level(), blockPos, this).isCancelled()) { // CraftBukkit + this.level().setBlockAndUpdate(blockPos, BaseFireBlock.getState(this.level(), blockPos)); + } + } +@@ -64,7 +_,7 @@ + protected void onHit(HitResult result) { + super.onHit(result); + if (!this.level().isClientSide) { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + } + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/Snowball.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Snowball.java.patch new file mode 100644 index 0000000000..5c87f7788c --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Snowball.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/projectile/Snowball.java ++++ b/net/minecraft/world/entity/projectile/Snowball.java +@@ -61,7 +_,7 @@ + super.onHit(result); + if (!this.level().isClientSide) { + this.level().broadcastEntityEvent(this, (byte)3); +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + } + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/SpectralArrow.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/SpectralArrow.java.patch new file mode 100644 index 0000000000..e7c4ff58ef --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/SpectralArrow.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/projectile/SpectralArrow.java ++++ b/net/minecraft/world/entity/projectile/SpectralArrow.java +@@ -38,7 +_,7 @@ + protected void doPostHurtEffects(LivingEntity living) { + super.doPostHurtEffects(living); + MobEffectInstance mobEffectInstance = new MobEffectInstance(MobEffects.GLOWING, this.duration, 0); +- living.addEffect(mobEffectInstance, this.getEffectSource()); ++ living.addEffect(mobEffectInstance, this.getEffectSource(), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ARROW); // CraftBukkit + } + + @Override diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrowableItemProjectile.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrowableItemProjectile.java.patch similarity index 77% rename from paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrowableItemProjectile.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrowableItemProjectile.java.patch index 6471dbc99e..bd84b5d136 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrowableItemProjectile.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrowableItemProjectile.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/projectile/ThrowableItemProjectile.java +++ b/net/minecraft/world/entity/projectile/ThrowableItemProjectile.java -@@ -34,6 +34,12 @@ +@@ -35,6 +_,12 @@ protected abstract Item getDefaultItem(); @@ -12,4 +12,4 @@ + @Override public ItemStack getItem() { - return (ItemStack) this.getEntityData().get(ThrowableItemProjectile.DATA_ITEM_STACK); + return this.getEntityData().get(DATA_ITEM_STACK); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch new file mode 100644 index 0000000000..3a35555ec9 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/projectile/ThrowableProjectile.java ++++ b/net/minecraft/world/entity/projectile/ThrowableProjectile.java +@@ -59,7 +_,7 @@ + this.applyEffectsFromBlocks(); + super.tick(); + if (hitResultOnMoveVector.getType() != HitResult.Type.MISS && this.isAlive()) { +- this.hitTargetOrDeflectSelf(hitResultOnMoveVector); ++ this.preHitTargetOrDeflectSelf(hitResultOnMoveVector); // CraftBukkit - projectile hit event + } + } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownEgg.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownEgg.java.patch new file mode 100644 index 0000000000..4c2c2ef103 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownEgg.java.patch @@ -0,0 +1,63 @@ +--- a/net/minecraft/world/entity/projectile/ThrownEgg.java ++++ b/net/minecraft/world/entity/projectile/ThrownEgg.java +@@ -59,22 +_,56 @@ + protected void onHit(HitResult result) { + super.onHit(result); + if (!this.level().isClientSide) { +- if (this.random.nextInt(8) == 0) { ++ // CraftBukkit start ++ boolean hatching = this.random.nextInt(8) == 0; ++ if (true) { ++ // CraftBukkit end + int i = 1; + if (this.random.nextInt(32) == 0) { + i = 4; + } ++ // CraftBukkit start ++ org.bukkit.entity.EntityType hatchingType = org.bukkit.entity.EntityType.CHICKEN; ++ ++ net.minecraft.world.entity.Entity shooter = this.getOwner(); ++ if (!hatching) { ++ i = 0; ++ } ++ if (shooter instanceof net.minecraft.server.level.ServerPlayer) { ++ org.bukkit.event.player.PlayerEggThrowEvent event = new org.bukkit.event.player.PlayerEggThrowEvent((org.bukkit.entity.Player) shooter.getBukkitEntity(), (org.bukkit.entity.Egg) this.getBukkitEntity(), hatching, (byte) i, hatchingType); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ i = event.getNumHatches(); ++ hatching = event.isHatching(); ++ hatchingType = event.getHatchingType(); ++ // If hatching is set to false, ensure child count is 0 ++ if (!hatching) { ++ i = 0; ++ } ++ } ++ // CraftBukkit end ++ // Paper start - Add ThrownEggHatchEvent ++ com.destroystokyo.paper.event.entity.ThrownEggHatchEvent event = new com.destroystokyo.paper.event.entity.ThrownEggHatchEvent((org.bukkit.entity.Egg) getBukkitEntity(), hatching, (byte) i, hatchingType); ++ event.callEvent(); ++ hatching = event.isHatching(); ++ i = hatching ? event.getNumHatches() : 0; // If hatching is set to false, ensure child count is 0 ++ hatchingType = event.getHatchingType(); ++ // Paper end - Add ThrownEggHatchEvent + + for (int i1 = 0; i1 < i; i1++) { +- Chicken chicken = EntityType.CHICKEN.create(this.level(), EntitySpawnReason.TRIGGERED); ++ net.minecraft.world.entity.Entity chicken = this.level().getWorld().makeEntity(new org.bukkit.Location(this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F), hatchingType.getEntityClass()); // CraftBukkit + if (chicken != null) { +- chicken.setAge(-24000); ++ // CraftBukkit start ++ if (chicken.getBukkitEntity() instanceof org.bukkit.entity.Ageable ageable) { ++ ageable.setBaby(); ++ } ++ // CraftBukkit end + chicken.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F); + if (!chicken.fudgePositionAfterSizeChange(ZERO_SIZED_DIMENSIONS)) { + break; + } + +- this.level().addFreshEntity(chicken); ++ this.level().addFreshEntity(chicken, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EGG); // CraftBukkit + } + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch new file mode 100644 index 0000000000..36963eb6e5 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch @@ -0,0 +1,83 @@ +--- a/net/minecraft/world/entity/projectile/ThrownEnderpearl.java ++++ b/net/minecraft/world/entity/projectile/ThrownEnderpearl.java +@@ -126,11 +_,18 @@ + Vec3 vec3 = this.oldPosition(); + if (owner instanceof ServerPlayer serverPlayer) { + if (serverPlayer.connection.isAcceptingMessages()) { ++ // CraftBukkit start ++ ServerPlayer serverPlayer1 = serverPlayer.teleport(new TeleportTransition(serverLevel, vec3, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.ROTATION, Relative.DELTA), TeleportTransition.DO_NOTHING, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.ENDER_PEARL)); ++ if (serverPlayer1 == null) { ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); ++ return; ++ } ++ // CraftBukkit end + if (this.random.nextFloat() < 0.05F && serverLevel.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { + Endermite endermite = EntityType.ENDERMITE.create(serverLevel, EntitySpawnReason.TRIGGERED); + if (endermite != null) { + endermite.moveTo(owner.getX(), owner.getY(), owner.getZ(), owner.getYRot(), owner.getXRot()); +- serverLevel.addFreshEntity(endermite); ++ serverLevel.addFreshEntity(endermite, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.ENDER_PEARL); + } + } + +@@ -138,15 +_,15 @@ + owner.setPortalCooldown(); + } + +- ServerPlayer serverPlayer1 = serverPlayer.teleport( +- new TeleportTransition( +- serverLevel, vec3, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.ROTATION, Relative.DELTA), TeleportTransition.DO_NOTHING +- ) +- ); ++ // ServerPlayer serverPlayer1 = serverPlayer.teleport( ++ // new TeleportTransition( ++ // serverLevel, vec3, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.ROTATION, Relative.DELTA), TeleportTransition.DO_NOTHING ++ // ) ++ // ); + if (serverPlayer1 != null) { + serverPlayer1.resetFallDistance(); + serverPlayer1.resetCurrentImpulseContext(); +- serverPlayer1.hurtServer(serverPlayer.serverLevel(), this.damageSources().enderPearl(), 5.0F); ++ serverPlayer1.hurtServer(serverPlayer.serverLevel(), this.damageSources().enderPearl().customEventDamager(this), 5.0F); // CraftBukkit // Paper - fix DamageSource API + } + + this.playSound(serverLevel, vec3); +@@ -162,9 +_,9 @@ + this.playSound(serverLevel, vec3); + } + +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + } else { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + } + } + } +@@ -185,7 +_,7 @@ + if (owner instanceof ServerPlayer serverPlayer + && !owner.isAlive() + && serverPlayer.serverLevel().getGameRules().getBoolean(GameRules.RULE_ENDER_PEARLS_VANISH_ON_DEATH)) { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause + } else { + super.tick(); + } +@@ -212,7 +_,7 @@ + public Entity teleport(TeleportTransition teleportTransition) { + Entity entity = super.teleport(teleportTransition); + if (entity != null) { +- entity.placePortalTicket(BlockPos.containing(entity.position())); ++ if (!this.level().paperConfig().misc.legacyEnderPearlBehavior) entity.placePortalTicket(BlockPos.containing(entity.position())); // Paper - Allow using old ender pearl behavior + } + + return entity; +@@ -220,7 +_,7 @@ + + @Override + public boolean canTeleport(Level fromLevel, Level toLevel) { +- return fromLevel.dimension() == Level.END && toLevel.dimension() == Level.OVERWORLD && this.getOwner() instanceof ServerPlayer serverPlayer ++ return fromLevel.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.END && toLevel.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.OVERWORLD && this.getOwner() instanceof ServerPlayer serverPlayer // CraftBukkit + ? super.canTeleport(fromLevel, toLevel) && serverPlayer.seenCredits + : super.canTeleport(fromLevel, toLevel); + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java.patch new file mode 100644 index 0000000000..e560b1ef1e --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java.patch @@ -0,0 +1,23 @@ +--- a/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java ++++ b/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java +@@ -37,10 +_,17 @@ + protected void onHit(HitResult result) { + super.onHit(result); + if (this.level() instanceof ServerLevel) { +- this.level().levelEvent(2002, this.blockPosition(), -13083194); ++ // CraftBukkit - moved to after event + int i = 3 + this.level().random.nextInt(5) + this.level().random.nextInt(5); +- ExperienceOrb.award((ServerLevel)this.level(), this.position(), i); +- this.discard(); ++ // CraftBukkit start ++ org.bukkit.event.entity.ExpBottleEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExpBottleEvent(this, result, i); ++ i = event.getExperience(); ++ if (event.getShowEffect()) { ++ this.level().levelEvent(net.minecraft.world.level.block.LevelEvent.PARTICLES_SPELL_POTION_SPLASH, this.blockPosition(), net.minecraft.world.item.alchemy.PotionContents.BASE_POTION_COLOR); ++ } ++ // CraftBukkit end ++ ExperienceOrb.award((ServerLevel)this.level(), this.position(), i, org.bukkit.entity.ExperienceOrb.SpawnReason.EXP_BOTTLE, this.getOwner(), this); // Paper ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + } + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownPotion.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownPotion.java.patch new file mode 100644 index 0000000000..254faacccd --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownPotion.java.patch @@ -0,0 +1,237 @@ +--- a/net/minecraft/world/entity/projectile/ThrownPotion.java ++++ b/net/minecraft/world/entity/projectile/ThrownPotion.java +@@ -9,6 +_,7 @@ + import net.minecraft.core.Holder; + import net.minecraft.core.component.DataComponents; + import net.minecraft.server.level.ServerLevel; ++import net.minecraft.server.level.ServerPlayer; + import net.minecraft.tags.BlockTags; + import net.minecraft.world.damagesource.DamageSource; + import net.minecraft.world.effect.MobEffect; +@@ -82,51 +_,87 @@ + @Override + protected void onHit(HitResult result) { + super.onHit(result); ++ // Paper start - More projectile API ++ this.splash(result); ++ } ++ public void splash(@Nullable HitResult result) { ++ // Paper end - More projectile API + if (this.level() instanceof ServerLevel serverLevel) { + ItemStack item = this.getItem(); + PotionContents potionContents = item.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); ++ boolean showParticles = true; // Paper - Fix potions splash events + if (potionContents.is(Potions.WATER)) { +- this.applyWater(serverLevel); +- } else if (potionContents.hasEffects()) { ++ showParticles = this.applyWater(serverLevel, result); // Paper - Fix potions splash events ++ } else if (true || potionContents.hasEffects()) { // CraftBukkit - Call event even if no effects to apply + if (this.isLingering()) { +- this.makeAreaOfEffectCloud(potionContents); ++ showParticles = this.makeAreaOfEffectCloud(potionContents, result); // CraftBukkit - Pass MovingObjectPosition // Paper + } else { +- this.applySplash( +- serverLevel, potionContents.getAllEffects(), result.getType() == HitResult.Type.ENTITY ? ((EntityHitResult)result).getEntity() : null ++ showParticles = this.applySplash( ++ serverLevel, potionContents.getAllEffects(), result != null && result.getType() == HitResult.Type.ENTITY ? ((EntityHitResult)result).getEntity() : null, result // CraftBukkit - Pass MovingObjectPosition // Paper - More projectile API + ); + } + } + ++ if (showParticles) { // Paper - Fix potions splash events + int i = potionContents.potion().isPresent() && potionContents.potion().get().value().hasInstantEffects() ? 2007 : 2002; + serverLevel.levelEvent(i, this.blockPosition(), potionContents.getColor()); +- this.discard(); ++ } // Paper - Fix potions splash events ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + } + } + +- private void applyWater(ServerLevel level) { ++ private static final Predicate APPLY_WATER_GET_ENTITIES_PREDICATE = ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE.or(Axolotl.class::isInstance); // Paper - Fix potions splash events ++ ++ private boolean applyWater(ServerLevel level, @Nullable HitResult result) { // Paper - Fix potions splash events + AABB aabb = this.getBoundingBox().inflate(4.0, 2.0, 4.0); + +- for (LivingEntity livingEntity : this.level().getEntitiesOfClass(LivingEntity.class, aabb, WATER_SENSITIVE_OR_ON_FIRE)) { ++ // Paper start - Fix potions splash events ++ java.util.Map affected = new java.util.HashMap<>(); ++ java.util.Set rehydrate = new java.util.HashSet<>(); ++ java.util.Set extinguish = new java.util.HashSet<>(); ++ for (LivingEntity livingEntity : this.level().getEntitiesOfClass(LivingEntity.class, aabb, APPLY_WATER_GET_ENTITIES_PREDICATE)) { ++ if (livingEntity instanceof Axolotl axolotl) { ++ rehydrate.add(((org.bukkit.entity.Axolotl) axolotl.getBukkitEntity())); ++ } ++ // Paper end - Fix potions splash events + double d = this.distanceToSqr(livingEntity); + if (d < 16.0) { + if (livingEntity.isSensitiveToWater()) { +- livingEntity.hurtServer(level, this.damageSources().indirectMagic(this, this.getOwner()), 1.0F); ++ affected.put(livingEntity.getBukkitLivingEntity(), 1.0); ++ // livingEntity.hurtServer(level, this.damageSources().indirectMagic(this, this.getOwner()), 1.0F); + } + + if (livingEntity.isOnFire() && livingEntity.isAlive()) { +- livingEntity.extinguishFire(); ++ extinguish.add(livingEntity.getBukkitLivingEntity()); ++ // livingEntity.extinguishFire(); + } + } + } + +- for (Axolotl axolotl : this.level().getEntitiesOfClass(Axolotl.class, aabb)) { +- axolotl.rehydrate(); ++ io.papermc.paper.event.entity.WaterBottleSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callWaterBottleSplashEvent( ++ this, result, affected, rehydrate, extinguish ++ ); ++ if (!event.isCancelled()) { ++ for (org.bukkit.entity.LivingEntity affectedEntity : event.getToDamage()) { ++ ((org.bukkit.craftbukkit.entity.CraftLivingEntity) affectedEntity).getHandle().hurtServer(level, this.damageSources().indirectMagic(this, this.getOwner()), 1.0F); ++ } ++ for (org.bukkit.entity.LivingEntity toExtinguish : event.getToExtinguish()) { ++ ((org.bukkit.craftbukkit.entity.CraftLivingEntity) toExtinguish).getHandle().extinguishFire(); ++ } ++ for (org.bukkit.entity.LivingEntity toRehydrate : event.getToRehydrate()) { ++ if (((org.bukkit.craftbukkit.entity.CraftLivingEntity) toRehydrate).getHandle() instanceof Axolotl axolotl) { ++ axolotl.rehydrate(); ++ } ++ } ++ // Paper end - Fix potions splash events + } ++ return !event.isCancelled(); // Paper - Fix potions splash events + } + +- private void applySplash(ServerLevel level, Iterable effects, @Nullable Entity entity) { ++ private boolean applySplash(ServerLevel level, Iterable effects, @Nullable Entity entity, @Nullable HitResult result) { // CraftBukkit - Pass MovingObjectPosition // Paper - Fix potions splash events & More projectile API + AABB aabb = this.getBoundingBox().inflate(4.0, 2.0, 4.0); + List entitiesOfClass = level.getEntitiesOfClass(LivingEntity.class, aabb); ++ java.util.Map affected = new java.util.HashMap<>(); // CraftBukkit + if (!entitiesOfClass.isEmpty()) { + Entity effectSource = this.getEffectSource(); + +@@ -135,33 +_,57 @@ + double d = this.distanceToSqr(livingEntity); + if (d < 16.0) { + double d1; ++ // Paper - diff on change, used when calling the splash event for water splash potions + if (livingEntity == entity) { + d1 = 1.0; + } else { + d1 = 1.0 - Math.sqrt(d) / 4.0; + } + +- for (MobEffectInstance mobEffectInstance : effects) { +- Holder effect = mobEffectInstance.getEffect(); +- if (effect.value().isInstantenous()) { +- effect.value().applyInstantenousEffect(level, this, this.getOwner(), livingEntity, mobEffectInstance.getAmplifier(), d1); +- } else { +- int i = mobEffectInstance.mapDuration(i1 -> (int)(d1 * i1 + 0.5)); +- MobEffectInstance mobEffectInstance1 = new MobEffectInstance( +- effect, i, mobEffectInstance.getAmplifier(), mobEffectInstance.isAmbient(), mobEffectInstance.isVisible() +- ); +- if (!mobEffectInstance1.endsWithin(20)) { +- livingEntity.addEffect(mobEffectInstance1, effectSource); +- } +- } +- } +- } +- } +- } +- } ++ affected.put(livingEntity.getBukkitLivingEntity(), d1); ++ } ++ } ++ } ++ } ++ org.bukkit.event.entity.PotionSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPotionSplashEvent(this, result, affected); ++ if (!event.isCancelled() && entitiesOfClass != null && !entitiesOfClass.isEmpty()) { // do not process effects if there are no effects to process ++ Entity effectSource = this.getEffectSource(); ++ for (org.bukkit.entity.LivingEntity victim : event.getAffectedEntities()) { ++ if (!(victim instanceof org.bukkit.craftbukkit.entity.CraftLivingEntity craftLivingEntity)) { ++ continue; ++ } ++ net.minecraft.world.entity.LivingEntity livingEntity = craftLivingEntity.getHandle(); ++ double d1 = event.getIntensity(victim); ++ // CraftBukkit end ++ for (MobEffectInstance mobEffectInstance : effects) { ++ Holder effect = mobEffectInstance.getEffect(); ++ // CraftBukkit start - Abide by PVP settings - for players only! ++ if (!this.level().pvpMode && this.getOwner() instanceof ServerPlayer && livingEntity instanceof ServerPlayer && livingEntity != this.getOwner()) { ++ MobEffect mobEffect = effect.value(); ++ if (mobEffect == net.minecraft.world.effect.MobEffects.MOVEMENT_SLOWDOWN || mobEffect == net.minecraft.world.effect.MobEffects.DIG_SLOWDOWN || mobEffect == net.minecraft.world.effect.MobEffects.HARM || mobEffect == net.minecraft.world.effect.MobEffects.BLINDNESS ++ || mobEffect == net.minecraft.world.effect.MobEffects.HUNGER || mobEffect == net.minecraft.world.effect.MobEffects.WEAKNESS || mobEffect == net.minecraft.world.effect.MobEffects.POISON) { ++ continue; ++ } ++ } ++ // CraftBukkit end ++ if (effect.value().isInstantenous()) { ++ effect.value().applyInstantenousEffect(level, this, this.getOwner(), livingEntity, mobEffectInstance.getAmplifier(), d1); ++ } else { ++ int i = mobEffectInstance.mapDuration(i1 -> (int)(d1 * i1 + 0.5)); ++ MobEffectInstance mobEffectInstance1 = new MobEffectInstance( ++ effect, i, mobEffectInstance.getAmplifier(), mobEffectInstance.isAmbient(), mobEffectInstance.isVisible() ++ ); ++ if (!mobEffectInstance1.endsWithin(20)) { ++ livingEntity.addEffect(mobEffectInstance1, effectSource); ++ } ++ } ++ } ++ } ++ } ++ return !event.isCancelled(); // Paper - Fix potions splash events + } + +- private void makeAreaOfEffectCloud(PotionContents potionContents) { ++ private boolean makeAreaOfEffectCloud(PotionContents potionContents, @Nullable HitResult result) { // CraftBukkit - Pass MovingObjectPosition // Paper - More projectile API + AreaEffectCloud areaEffectCloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ()); + if (this.getOwner() instanceof LivingEntity livingEntity) { + areaEffectCloud.setOwner(livingEntity); +@@ -172,7 +_,16 @@ + areaEffectCloud.setWaitTime(10); + areaEffectCloud.setRadiusPerTick(-areaEffectCloud.getRadius() / areaEffectCloud.getDuration()); + areaEffectCloud.setPotionContents(potionContents); +- this.level().addFreshEntity(areaEffectCloud); ++ boolean noEffects = potionContents.hasEffects(); // Paper - Fix potions splash events ++ // CraftBukkit start ++ org.bukkit.event.entity.LingeringPotionSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callLingeringPotionSplashEvent(this, result, areaEffectCloud); ++ if (!(event.isCancelled() || areaEffectCloud.isRemoved() || (!event.allowsEmptyCreation() && (noEffects && !areaEffectCloud.potionContents.hasEffects())))) { // Paper - don't spawn area effect cloud if the effects were empty and not changed during the event handling ++ this.level().addFreshEntity(areaEffectCloud); ++ } else { ++ areaEffectCloud.discard(null); // CraftBukkit - add Bukkit remove cause ++ } ++ // CraftBukkit end ++ return !event.isCancelled(); // Paper - Fix potions splash events + } + + public boolean isLingering() { +@@ -182,13 +_,25 @@ + private void dowseFire(BlockPos pos) { + BlockState blockState = this.level().getBlockState(pos); + if (blockState.is(BlockTags.FIRE)) { +- this.level().destroyBlock(pos, false, this); ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, pos, blockState.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state ++ this.level().destroyBlock(pos, false, this); ++ } ++ // CraftBukkit end + } else if (AbstractCandleBlock.isLit(blockState)) { +- AbstractCandleBlock.extinguish(null, blockState, this.level(), pos); ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, pos, blockState.setValue(AbstractCandleBlock.LIT, false))) { ++ AbstractCandleBlock.extinguish(null, blockState, this.level(), pos); ++ } ++ // CraftBukkit end + } else if (CampfireBlock.isLitCampfire(blockState)) { +- this.level().levelEvent(null, 1009, pos, 0); +- CampfireBlock.dowse(this.getOwner(), this.level(), pos, blockState); +- this.level().setBlockAndUpdate(pos, blockState.setValue(CampfireBlock.LIT, Boolean.valueOf(false))); ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, pos, blockState.setValue(CampfireBlock.LIT, false))) { ++ this.level().levelEvent(null, 1009, pos, 0); ++ CampfireBlock.dowse(this.getOwner(), this.level(), pos, blockState); ++ this.level().setBlockAndUpdate(pos, blockState.setValue(CampfireBlock.LIT, false)); ++ } ++ // CraftBukkit end + } + } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownTrident.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownTrident.java.patch new file mode 100644 index 0000000000..dad0da0b92 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownTrident.java.patch @@ -0,0 +1,65 @@ +--- a/net/minecraft/world/entity/projectile/ThrownTrident.java ++++ b/net/minecraft/world/entity/projectile/ThrownTrident.java +@@ -32,16 +_,19 @@ + + public ThrownTrident(EntityType entityType, Level level) { + super(entityType, level); ++ this.setBaseDamage(net.minecraft.world.item.TridentItem.BASE_DAMAGE); // Paper - Allow trident custom damage + } + + public ThrownTrident(Level level, LivingEntity shooter, ItemStack pickupItemStack) { + super(EntityType.TRIDENT, shooter, level, pickupItemStack, null); ++ this.setBaseDamage(net.minecraft.world.item.TridentItem.BASE_DAMAGE); // Paper - Allow trident custom damage + this.entityData.set(ID_LOYALTY, this.getLoyaltyFromItem(pickupItemStack)); + this.entityData.set(ID_FOIL, pickupItemStack.hasFoil()); + } + + public ThrownTrident(Level level, double x, double y, double z, ItemStack pickupItemStack) { + super(EntityType.TRIDENT, x, y, z, level, pickupItemStack, pickupItemStack); ++ this.setBaseDamage(net.minecraft.world.item.TridentItem.BASE_DAMAGE); // Paper - Allow trident custom damage + this.entityData.set(ID_LOYALTY, this.getLoyaltyFromItem(pickupItemStack)); + this.entityData.set(ID_FOIL, pickupItemStack.hasFoil()); + } +@@ -67,10 +_,10 @@ + this.spawnAtLocation(serverLevel, this.getPickupItem(), 0.1F); + } + +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause + } else { + if (!(owner instanceof Player) && this.position().distanceTo(owner.getEyePosition()) < owner.getBbWidth() + 1.0) { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause + return; + } + +@@ -99,6 +_,20 @@ + return this.entityData.get(ID_FOIL); + } + ++ // Paper start ++ public void setFoil(boolean foil) { ++ this.entityData.set(ThrownTrident.ID_FOIL, foil); ++ } ++ ++ public int getLoyalty() { ++ return this.entityData.get(ThrownTrident.ID_LOYALTY); ++ } ++ ++ public void setLoyalty(byte loyalty) { ++ this.entityData.set(ThrownTrident.ID_LOYALTY, loyalty); ++ } ++ // Paper end ++ + @Nullable + @Override + protected EntityHitResult findHitEntity(Vec3 startVec, Vec3 endVec) { +@@ -108,7 +_,7 @@ + @Override + protected void onHitEntity(EntityHitResult result) { + Entity entity = result.getEntity(); +- float f = 8.0F; ++ float f = (float) this.getBaseDamage(); // Paper - Allow trident custom damage + Entity owner = this.getOwner(); + DamageSource damageSource = this.damageSources().trident(this, (Entity)(owner == null ? this : owner)); + if (this.level() instanceof ServerLevel serverLevel) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/WitherSkull.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/WitherSkull.java.patch new file mode 100644 index 0000000000..d323b77c2b --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/WitherSkull.java.patch @@ -0,0 +1,43 @@ +--- a/net/minecraft/world/entity/projectile/WitherSkull.java ++++ b/net/minecraft/world/entity/projectile/WitherSkull.java +@@ -65,11 +_,11 @@ + if (var8.isAlive()) { + EnchantmentHelper.doPostAttackEffects(serverLevel, var8, damageSource); + } else { +- livingEntity.heal(5.0F); ++ livingEntity.heal(5.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.WITHER); // CraftBukkit + } + } + } else { +- flag = var8.hurtServer(serverLevel, this.damageSources().magic(), 5.0F); ++ flag = var8.hurtServer(serverLevel, this.damageSources().magic().customEventDamager(this), 5.0F); // Paper - Fire EntityDamageByEntityEvent for unowned wither skulls // Paper - fix DamageSource API + } + + if (flag && var8 instanceof LivingEntity livingEntityx) { +@@ -81,7 +_,7 @@ + } + + if (i > 0) { +- livingEntityx.addEffect(new MobEffectInstance(MobEffects.WITHER, 20 * i, 1), this.getEffectSource()); ++ livingEntityx.addEffect(new MobEffectInstance(MobEffects.WITHER, 20 * i, 1), this.getEffectSource(), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + } + } + } +@@ -91,8 +_,15 @@ + protected void onHit(HitResult result) { + super.onHit(result); + if (!this.level().isClientSide) { +- this.level().explode(this, this.getX(), this.getY(), this.getZ(), 1.0F, false, Level.ExplosionInteraction.MOB); +- this.discard(); ++ // CraftBukkit start ++ org.bukkit.event.entity.ExplosionPrimeEvent event = new org.bukkit.event.entity.ExplosionPrimeEvent(this.getBukkitEntity(), 1.0F, false); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ this.level().explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); ++ } ++ // CraftBukkit end ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + } + } + diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/AbstractArrow.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/AbstractArrow.java.patch deleted file mode 100644 index d2cc2fa1a9..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/AbstractArrow.java.patch +++ /dev/null @@ -1,320 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/AbstractArrow.java -+++ b/net/minecraft/world/entity/projectile/AbstractArrow.java -@@ -36,6 +36,7 @@ - import net.minecraft.world.entity.OminousItemSpawner; - import net.minecraft.world.entity.SlotAccess; - import net.minecraft.world.entity.ai.attributes.Attributes; -+import net.minecraft.world.entity.item.ItemEntity; - import net.minecraft.world.entity.player.Player; - import net.minecraft.world.item.Item; - import net.minecraft.world.item.ItemStack; -@@ -50,6 +51,10 @@ - import net.minecraft.world.phys.HitResult; - import net.minecraft.world.phys.Vec3; - import net.minecraft.world.phys.shapes.VoxelShape; -+import org.bukkit.event.entity.EntityCombustByEntityEvent; -+import org.bukkit.event.entity.EntityRemoveEvent; -+import org.bukkit.event.player.PlayerPickupArrowEvent; -+// CraftBukkit end - - public abstract class AbstractArrow extends Projectile { - -@@ -78,6 +83,18 @@ - @Nullable - public ItemStack firedFromWeapon; - -+ // Spigot Start -+ @Override -+ public void inactiveTick() -+ { -+ if ( this.isInGround() ) -+ { -+ this.life += 1; -+ } -+ super.inactiveTick(); -+ } -+ // Spigot End -+ - protected AbstractArrow(EntityType type, Level world) { - super(type, world); - this.pickup = AbstractArrow.Pickup.DISALLOWED; -@@ -88,23 +105,30 @@ - } - - protected AbstractArrow(EntityType type, double x, double y, double z, Level world, ItemStack stack, @Nullable ItemStack weapon) { -- this(type, world); -- this.pickupItemStack = stack.copy(); -- this.setCustomName((Component) stack.get(DataComponents.CUSTOM_NAME)); -- Unit unit = (Unit) stack.remove(DataComponents.INTANGIBLE_PROJECTILE); -+ // CraftBukkit start - handle the owner before the rest of things -+ this(type, x, y, z, world, stack, weapon, null); -+ } - -+ protected AbstractArrow(EntityType entitytypes, double d0, double d1, double d2, Level world, ItemStack itemstack, @Nullable ItemStack itemstack1, @Nullable LivingEntity ownerEntity) { -+ this(entitytypes, world); -+ this.setOwner(ownerEntity); -+ // CraftBukkit end -+ this.pickupItemStack = itemstack.copy(); -+ this.setCustomName((Component) itemstack.get(DataComponents.CUSTOM_NAME)); -+ Unit unit = (Unit) itemstack.remove(DataComponents.INTANGIBLE_PROJECTILE); -+ - if (unit != null) { - this.pickup = AbstractArrow.Pickup.CREATIVE_ONLY; - } - -- this.setPos(x, y, z); -- if (weapon != null && world instanceof ServerLevel worldserver) { -- if (weapon.isEmpty()) { -+ this.setPos(d0, d1, d2); -+ if (itemstack1 != null && world instanceof ServerLevel worldserver) { -+ if (itemstack1.isEmpty()) { - throw new IllegalArgumentException("Invalid weapon firing an arrow"); - } - -- this.firedFromWeapon = weapon.copy(); -- int i = EnchantmentHelper.getPiercingCount(worldserver, weapon, this.pickupItemStack); -+ this.firedFromWeapon = itemstack1.copy(); -+ int i = EnchantmentHelper.getPiercingCount(worldserver, itemstack1, this.pickupItemStack); - - if (i > 0) { - this.setPierceLevel((byte) i); -@@ -114,8 +138,8 @@ - } - - protected AbstractArrow(EntityType type, LivingEntity owner, Level world, ItemStack stack, @Nullable ItemStack shotFrom) { -- this(type, owner.getX(), owner.getEyeY() - 0.10000000149011612D, owner.getZ(), world, stack, shotFrom); -- this.setOwner(owner); -+ this(type, owner.getX(), owner.getEyeY() - 0.10000000149011612D, owner.getZ(), world, stack, shotFrom, owner); // CraftBukkit -+ // this.setOwner(entityliving); // SPIGOT-7744 - Moved to the above constructor - } - - public void setSoundEvent(SoundEvent sound) { -@@ -220,6 +244,7 @@ - } - - } else { -+ if (tickCount > 200) this.tickDespawn(); // Paper - tick despawnCounter regardless after 10 seconds - this.inGroundTime = 0; - Vec3 vec3d2 = this.position(); - -@@ -282,7 +307,7 @@ - - if (movingobjectpositionentity == null) { - if (this.isAlive() && blockHitResult.getType() != HitResult.Type.MISS) { -- this.hitTargetOrDeflectSelf(blockHitResult); -+ this.preHitTargetOrDeflectSelf(blockHitResult); // CraftBukkit - projectile hit event - this.hasImpulse = true; - } - } else { -@@ -290,7 +315,7 @@ - continue; - } - -- ProjectileDeflection projectiledeflection = this.hitTargetOrDeflectSelf(movingobjectpositionentity); -+ ProjectileDeflection projectiledeflection = this.preHitTargetOrDeflectSelf(movingobjectpositionentity); // CraftBukkit - projectile hit event - - this.hasImpulse = true; - if (this.getPierceLevel() > 0 && projectiledeflection == ProjectileDeflection.NONE) { -@@ -318,7 +343,20 @@ - this.level().addParticle(ParticleTypes.BUBBLE, pos.x - vec3d1.x * 0.25D, pos.y - vec3d1.y * 0.25D, pos.z - vec3d1.z * 0.25D, vec3d1.x, vec3d1.y, vec3d1.z); - } - -+ } -+ -+ // Paper start - Fix cancelling ProjectileHitEvent for piercing arrows -+ @Override -+ public ProjectileDeflection preHitTargetOrDeflectSelf(HitResult hitResult) { -+ if (hitResult instanceof EntityHitResult entityHitResult && this.hitCancelled && this.getPierceLevel() > 0) { -+ if (this.piercingIgnoreEntityIds == null) { -+ this.piercingIgnoreEntityIds = new IntOpenHashSet(5); -+ } -+ this.piercingIgnoreEntityIds.add(entityHitResult.getEntity().getId()); -+ } -+ return super.preHitTargetOrDeflectSelf(hitResult); - } -+ // Paper end - Fix cancelling ProjectileHitEvent for piercing arrows - - @Override - protected double getDefaultGravity() { -@@ -356,8 +394,8 @@ - - protected void tickDespawn() { - ++this.life; -- if (this.life >= 1200) { -- this.discard(); -+ if (this.life >= (pickup == Pickup.CREATIVE_ONLY ? this.level().paperConfig().entities.spawning.creativeArrowDespawnRate.value() : (pickup == Pickup.DISALLOWED ? this.level().paperConfig().entities.spawning.nonPlayerArrowDespawnRate.value() : ((this instanceof ThrownTrident) ? this.level().spigotConfig.tridentDespawnRate : this.level().spigotConfig.arrowDespawnRate)))) { // Spigot // Paper - Configurable non-player arrow despawn rate; TODO: Extract this to init? -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - } - - } -@@ -386,9 +424,9 @@ - } - - @Override -- public void push(double deltaX, double deltaY, double deltaZ) { -+ public void push(double deltaX, double deltaY, double deltaZ, @Nullable Entity pushingEntity) { // Paper - add push source entity param - if (!this.isInGround()) { -- super.push(deltaX, deltaY, deltaZ); -+ super.push(deltaX, deltaY, deltaZ, pushingEntity); // Paper - add push source entity param - } - } - -@@ -423,7 +461,7 @@ - } - - if (this.piercingIgnoreEntityIds.size() >= this.getPierceLevel() + 1) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause - return; - } - -@@ -440,11 +478,18 @@ - entityliving.setLastHurtMob(entity); - } - -+ if (this.isCritArrow()) damagesource = damagesource.critical(); // Paper - add critical damage API - boolean flag = entity.getType() == EntityType.ENDERMAN; - int k = entity.getRemainingFireTicks(); - - if (this.isOnFire() && !flag) { -- entity.igniteForSeconds(5.0F); -+ // CraftBukkit start -+ EntityCombustByEntityEvent combustEvent = new EntityCombustByEntityEvent(this.getBukkitEntity(), entity.getBukkitEntity(), 5.0F); -+ org.bukkit.Bukkit.getPluginManager().callEvent(combustEvent); -+ if (!combustEvent.isCancelled()) { -+ entity.igniteForSeconds(combustEvent.getDuration(), false); -+ } -+ // CraftBukkit end - } - - if (entity.hurtOrSimulate(damagesource, (float) i)) { -@@ -490,7 +535,7 @@ - - this.playSound(this.soundEvent, 1.0F, 1.2F / (this.random.nextFloat() * 0.2F + 0.9F)); - if (this.getPierceLevel() <= 0) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause - } - } else { - entity.setRemainingFireTicks(k); -@@ -506,7 +551,7 @@ - this.spawnAtLocation(worldserver2, this.getPickupItem(), 0.1F); - } - -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause - } - } - } -@@ -538,7 +583,7 @@ - Vec3 vec3d = this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D).normalize().scale(d0 * 0.6D * d1); - - if (vec3d.lengthSqr() > 0.0D) { -- target.push(vec3d.x, 0.1D, vec3d.z); -+ target.push(vec3d.x, 0.1D, vec3d.z, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent - } - } - -@@ -665,7 +710,7 @@ - this.setCritArrow(nbt.getBoolean("crit")); - this.setPierceLevel(nbt.getByte("PierceLevel")); - if (nbt.contains("SoundEvent", 8)) { -- this.soundEvent = (SoundEvent) BuiltInRegistries.SOUND_EVENT.getOptional(ResourceLocation.parse(nbt.getString("SoundEvent"))).orElse(this.getDefaultHitGroundSoundEvent()); -+ this.soundEvent = (SoundEvent) BuiltInRegistries.SOUND_EVENT.getOptional(ResourceLocation.tryParse(nbt.getString("SoundEvent"))).orElse(this.getDefaultHitGroundSoundEvent()); // Paper - Validate resource location - } - - if (nbt.contains("item", 10)) { -@@ -675,7 +720,7 @@ - } - - if (nbt.contains("weapon", 10)) { -- this.firedFromWeapon = (ItemStack) ItemStack.parse(this.registryAccess(), nbt.getCompound("weapon")).orElse((Object) null); -+ this.firedFromWeapon = (ItemStack) ItemStack.parse(this.registryAccess(), nbt.getCompound("weapon")).orElse(null); // CraftBukkit - decompile error - } else { - this.firedFromWeapon = null; - } -@@ -684,38 +729,42 @@ - - @Override - public void setOwner(@Nullable Entity entity) { -+ // Paper start - Fix PickupStatus getting reset -+ this.setOwner(entity, true); -+ } -+ -+ public void setOwner(@Nullable Entity entity, boolean resetPickup) { -+ // Paper end - Fix PickupStatus getting reset - super.setOwner(entity); -+ if (!resetPickup) return; // Paper - Fix PickupStatus getting reset - Entity entity1 = entity; - byte b0 = 0; - -- EntityArrow.PickupStatus entityarrow_pickupstatus; -+ EntityArrow.PickupStatus entityarrow_pickupstatus = this.pickup; // CraftBukkit - decompile error - - label16: -- while(true) { -- //$FF: b0->value -- //0->net/minecraft/world/entity/player/EntityHuman -- //1->net/minecraft/world/entity/OminousItemSpawner -- switch (entity1.typeSwitch(entity1, b0)) { -- case -1: -- default: -- entityarrow_pickupstatus = this.pickup; -- break label16; -- case 0: -- EntityHuman entityhuman = (EntityHuman)entity1; -+ // CraftBukkit start - decompile error -+ while (true) { -+ switch (entity1) { -+ case EntityHuman entityhuman: - - if (this.pickup != EntityArrow.PickupStatus.DISALLOWED) { - b0 = 1; -- break; -+ break label16; - } - - entityarrow_pickupstatus = EntityArrow.PickupStatus.ALLOWED; - break label16; -- case 1: -- OminousItemSpawner ominousitemspawner = (OminousItemSpawner)entity1; -+ case OminousItemSpawner ominousitemspawner: - - entityarrow_pickupstatus = EntityArrow.PickupStatus.DISALLOWED; - break label16; -+ case null: // SPIGOT-7751: Fix crash caused by null owner -+ default: -+ entityarrow_pickupstatus = this.pickup; -+ break label16; - } -+ // CraftBukkit end - } - - this.pickup = entityarrow_pickupstatus; -@@ -724,9 +773,24 @@ - @Override - public void playerTouch(Player player) { - if (!this.level().isClientSide && (this.isInGround() || this.isNoPhysics()) && this.shakeTime <= 0) { -- if (this.tryPickup(player)) { -+ // CraftBukkit start -+ ItemStack itemstack = this.getPickupItem(); -+ if (this.pickup == Pickup.ALLOWED && !itemstack.isEmpty() && player.getInventory().canHold(itemstack) > 0) { -+ ItemEntity item = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemstack); -+ PlayerPickupArrowEvent event = new PlayerPickupArrowEvent((org.bukkit.entity.Player) player.getBukkitEntity(), new org.bukkit.craftbukkit.entity.CraftItem(this.level().getCraftServer(), item), (org.bukkit.entity.AbstractArrow) this.getBukkitEntity()); -+ // event.setCancelled(!entityhuman.canPickUpLoot); TODO -+ this.level().getCraftServer().getPluginManager().callEvent(event); -+ -+ if (event.isCancelled()) { -+ return; -+ } -+ itemstack = item.getItem(); -+ } -+ -+ if ((this.pickup == AbstractArrow.Pickup.ALLOWED && player.getInventory().add(itemstack)) || (this.pickup == AbstractArrow.Pickup.CREATIVE_ONLY && player.getAbilities().instabuild)) { -+ // CraftBukkit end - player.take(this, 1); -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause - } - - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java.patch deleted file mode 100644 index b53dd9f069..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java.patch +++ /dev/null @@ -1,38 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java -+++ b/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java -@@ -14,12 +14,17 @@ - import net.minecraft.world.level.Level; - import net.minecraft.world.phys.HitResult; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public abstract class AbstractHurtingProjectile extends Projectile { - - public static final double INITAL_ACCELERATION_POWER = 0.1D; - public static final double DEFLECTION_SCALE = 0.5D; - public double accelerationPower; -+ public float bukkitYield = 1; // CraftBukkit -+ public boolean isIncendiary = true; // CraftBukkit - - protected AbstractHurtingProjectile(EntityType type, Level world) { - super(type, world); -@@ -69,7 +74,7 @@ - - this.applyInertia(); - if (!this.level().isClientSide && (entity != null && entity.isRemoved() || !this.level().hasChunkAt(this.blockPosition()))) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - } else { - HitResult movingobjectposition = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity, this.getClipType()); - Vec3 vec3d; -@@ -89,7 +94,7 @@ - } - - if (movingobjectposition.getType() != HitResult.Type.MISS && this.isAlive()) { -- this.hitTargetOrDeflectSelf(movingobjectposition); -+ this.preHitTargetOrDeflectSelf(movingobjectposition); // CraftBukkit - projectile hit event - } - - this.createParticleTrail(); diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/Arrow.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/Arrow.java.patch deleted file mode 100644 index c19bed3b4d..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/Arrow.java.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/Arrow.java -+++ b/net/minecraft/world/entity/projectile/Arrow.java -@@ -119,7 +119,7 @@ - mobeffect = (MobEffectInstance) iterator.next(); - target.addEffect(new MobEffectInstance(mobeffect.getEffect(), Math.max(mobeffect.mapDuration((i) -> { - return i / 8; -- }), 1), mobeffect.getAmplifier(), mobeffect.isAmbient(), mobeffect.isVisible()), entity); -+ }), 1), mobeffect.getAmplifier(), mobeffect.isAmbient(), mobeffect.isVisible()), entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ARROW); // CraftBukkit - } - } - -@@ -127,7 +127,7 @@ - - while (iterator.hasNext()) { - mobeffect = (MobEffectInstance) iterator.next(); -- target.addEffect(mobeffect, entity); -+ target.addEffect(mobeffect, entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ARROW); // CraftBukkit - } - - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/DragonFireball.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/DragonFireball.java.patch deleted file mode 100644 index 6278d9b3bb..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/DragonFireball.java.patch +++ /dev/null @@ -1,26 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/DragonFireball.java -+++ b/net/minecraft/world/entity/projectile/DragonFireball.java -@@ -14,6 +14,9 @@ - import net.minecraft.world.phys.EntityHitResult; - import net.minecraft.world.phys.HitResult; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class DragonFireball extends AbstractHurtingProjectile { - -@@ -59,9 +62,11 @@ - } - } - -+ if (new com.destroystokyo.paper.event.entity.EnderDragonFireballHitEvent((org.bukkit.entity.DragonFireball) this.getBukkitEntity(), list.stream().map(LivingEntity::getBukkitLivingEntity).collect(java.util.stream.Collectors.toList()), (org.bukkit.entity.AreaEffectCloud) entityareaeffectcloud.getBukkitEntity()).callEvent()) { // Paper - EnderDragon Events - this.level().levelEvent(2006, this.blockPosition(), this.isSilent() ? -1 : 1); -- this.level().addFreshEntity(entityareaeffectcloud); -- this.discard(); -+ this.level().addFreshEntity(entityareaeffectcloud, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EXPLOSION); // Paper - use correct spawn reason -+ } else entityareaeffectcloud.discard(null); // Paper - EnderDragon Events -+ this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause - } - - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/EvokerFangs.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/EvokerFangs.java.patch deleted file mode 100644 index fc93ad07be..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/EvokerFangs.java.patch +++ /dev/null @@ -1,30 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/EvokerFangs.java -+++ b/net/minecraft/world/entity/projectile/EvokerFangs.java -@@ -16,6 +16,9 @@ - import net.minecraft.world.entity.TraceableEntity; - import net.minecraft.world.item.enchantment.EnchantmentHelper; - import net.minecraft.world.level.Level; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class EvokerFangs extends Entity implements TraceableEntity { - -@@ -121,7 +124,7 @@ - } - - if (--this.lifeTicks < 0) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - } - } - -@@ -132,7 +135,7 @@ - - if (target.isAlive() && !target.isInvulnerable() && target != entityliving1) { - if (entityliving1 == null) { -- target.hurt(this.damageSources().magic(), 6.0F); -+ target.hurt(this.damageSources().magic().customEventDamager(this), 6.0F); // CraftBukkit // Paper - fix DamageSource API - } else { - if (entityliving1.isAlliedTo((Entity) target)) { - return; diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/Fireball.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/Fireball.java.patch deleted file mode 100644 index 6cc358f744..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/Fireball.java.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/Fireball.java -+++ b/net/minecraft/world/entity/projectile/Fireball.java -@@ -61,7 +61,12 @@ - public void readAdditionalSaveData(CompoundTag nbt) { - super.readAdditionalSaveData(nbt); - if (nbt.contains("Item", 10)) { -- this.setItem((ItemStack) ItemStack.parse(this.registryAccess(), nbt.getCompound("Item")).orElse(this.getDefaultItem())); -+ // CraftBukkit start - SPIGOT-5474 probably came from bugged earlier versions -+ ItemStack itemstack = (ItemStack) ItemStack.parse(this.registryAccess(), nbt.getCompound("Item")).orElse(this.getDefaultItem()); -+ if (!itemstack.isEmpty()) { -+ this.setItem(itemstack); -+ } -+ // CraftBukkit end - } else { - this.setItem(this.getDefaultItem()); - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch deleted file mode 100644 index 91715aeb75..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch +++ /dev/null @@ -1,132 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java -+++ b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java -@@ -32,6 +32,9 @@ - import net.minecraft.world.phys.EntityHitResult; - import net.minecraft.world.phys.HitResult; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class FireworkRocketEntity extends Projectile implements ItemSupplier { - -@@ -42,6 +45,7 @@ - public int lifetime; - @Nullable - public LivingEntity attachedToEntity; -+ @Nullable public java.util.UUID spawningEntity; // Paper - - public FireworkRocketEntity(EntityType type, Level world) { - super(type, world); -@@ -84,7 +88,29 @@ - this.setOwner(entity); - } - -+ // Spigot Start - copied from tick - @Override -+ public void inactiveTick() { -+ this.life += 1; -+ -+ if (this.life > this.lifetime) { -+ Level world = this.level(); -+ -+ if (world instanceof ServerLevel) { -+ ServerLevel worldserver = (ServerLevel) world; -+ -+ // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) { -+ this.explode(worldserver); -+ } -+ // CraftBukkit end -+ } -+ } -+ super.inactiveTick(); -+ } -+ // Spigot End -+ -+ @Override - protected void defineSynchedData(SynchedEntityData.Builder builder) { - builder.define(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, FireworkRocketEntity.getDefaultItem()); - builder.define(FireworkRocketEntity.DATA_ATTACHED_TO_TARGET, OptionalInt.empty()); -@@ -152,7 +178,7 @@ - } - - if (!this.noPhysics && this.isAlive() && movingobjectposition.getType() != HitResult.Type.MISS) { -- this.hitTargetOrDeflectSelf(movingobjectposition); -+ this.preHitTargetOrDeflectSelf(movingobjectposition); // CraftBukkit - projectile hit event - this.hasImpulse = true; - } - -@@ -172,7 +198,11 @@ - if (world instanceof ServerLevel) { - ServerLevel worldserver = (ServerLevel) world; - -- this.explode(worldserver); -+ // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) { -+ this.explode(worldserver); -+ } -+ // CraftBukkit end - } - } - -@@ -182,7 +212,7 @@ - world.broadcastEntityEvent(this, (byte) 17); - this.gameEvent(GameEvent.EXPLODE, this.getOwner()); - this.dealExplosionDamage(world); -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause - } - - @Override -@@ -191,7 +221,11 @@ - Level world = this.level(); - - if (world instanceof ServerLevel worldserver) { -- this.explode(worldserver); -+ // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) { -+ this.explode(worldserver); -+ } -+ // CraftBukkit end - } - - } -@@ -205,7 +239,11 @@ - - if (world instanceof ServerLevel worldserver) { - if (this.hasExplosion()) { -- this.explode(worldserver); -+ // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) { -+ this.explode(worldserver); -+ } -+ // CraftBukkit end - } - } - -@@ -287,6 +325,11 @@ - nbt.putInt("LifeTime", this.lifetime); - nbt.put("FireworksItem", this.getItem().save(this.registryAccess())); - nbt.putBoolean("ShotAtAngle", (Boolean) this.entityData.get(FireworkRocketEntity.DATA_SHOT_AT_ANGLE)); -+ // Paper start -+ if (this.spawningEntity != null) { -+ nbt.putUUID("SpawningEntity", this.spawningEntity); -+ } -+ // Paper end - } - - @Override -@@ -303,7 +346,11 @@ - if (nbt.contains("ShotAtAngle")) { - this.entityData.set(FireworkRocketEntity.DATA_SHOT_AT_ANGLE, nbt.getBoolean("ShotAtAngle")); - } -- -+ // Paper start -+ if (nbt.hasUUID("SpawningEntity")) { -+ this.spawningEntity = nbt.getUUID("SpawningEntity"); -+ } -+ // Paper end - } - - private List getExplosions() { diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/FishingHook.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/FishingHook.java.patch deleted file mode 100644 index 27f0995455..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/FishingHook.java.patch +++ /dev/null @@ -1,352 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/FishingHook.java -+++ b/net/minecraft/world/entity/projectile/FishingHook.java -@@ -29,7 +29,6 @@ - import net.minecraft.world.entity.ExperienceOrb; - import net.minecraft.world.entity.MoverType; - import net.minecraft.world.entity.item.ItemEntity; --import net.minecraft.world.entity.player.Player; - import net.minecraft.world.item.ItemStack; - import net.minecraft.world.item.Items; - import net.minecraft.world.level.Level; -@@ -47,6 +46,13 @@ - import net.minecraft.world.phys.Vec3; - import org.slf4j.Logger; - -+// CraftBukkit start -+import org.bukkit.entity.Player; -+import org.bukkit.entity.FishHook; -+import org.bukkit.event.entity.EntityRemoveEvent; -+import org.bukkit.event.player.PlayerFishEvent; -+// CraftBukkit end -+ - public class FishingHook extends Projectile { - - private static final Logger LOGGER = LogUtils.getLogger(); -@@ -68,6 +74,18 @@ - private final int luck; - private final int lureSpeed; - -+ // CraftBukkit start - Extra variables to enable modification of fishing wait time, values are minecraft defaults -+ public int minWaitTime = 100; -+ public int maxWaitTime = 600; -+ public int minLureTime = 20; -+ public int maxLureTime = 80; -+ public float minLureAngle = 0.0F; -+ public float maxLureAngle = 360.0F; -+ public boolean applyLure = true; -+ public boolean rainInfluenced = true; -+ public boolean skyInfluenced = true; -+ // CraftBukkit end -+ - private FishingHook(EntityType type, Level world, int luckBonus, int waitTimeReductionTicks) { - super(type, world); - this.syncronizedRandom = RandomSource.create(); -@@ -75,13 +93,17 @@ - this.currentState = FishingHook.FishHookState.FLYING; - this.luck = Math.max(0, luckBonus); - this.lureSpeed = Math.max(0, waitTimeReductionTicks); -+ // Paper start - Configurable fishing time ranges -+ minWaitTime = world.paperConfig().fishingTimeRange.minimum; -+ maxWaitTime = world.paperConfig().fishingTimeRange.maximum; -+ // Paper end - Configurable fishing time ranges - } - - public FishingHook(EntityType type, Level world) { - this(type, world, 0, 0); - } - -- public FishingHook(Player thrower, Level world, int luckBonus, int waitTimeReductionTicks) { -+ public FishingHook(net.minecraft.world.entity.player.Player thrower, Level world, int luckBonus, int waitTimeReductionTicks) { - this(EntityType.FISHING_BOBBER, world, luckBonus, waitTimeReductionTicks); - this.setOwner(thrower); - float f = thrower.getXRot(); -@@ -149,15 +171,15 @@ - public void tick() { - this.syncronizedRandom.setSeed(this.getUUID().getLeastSignificantBits() ^ this.level().getGameTime()); - super.tick(); -- Player entityhuman = this.getPlayerOwner(); -+ net.minecraft.world.entity.player.Player entityhuman = this.getPlayerOwner(); - - if (entityhuman == null) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - } else if (this.level().isClientSide || !this.shouldStopFishing(entityhuman)) { - if (this.onGround()) { - ++this.life; - if (this.life >= 1200) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - return; - } - } else { -@@ -250,7 +272,7 @@ - } - } - -- private boolean shouldStopFishing(Player player) { -+ private boolean shouldStopFishing(net.minecraft.world.entity.player.Player player) { - ItemStack itemstack = player.getMainHandItem(); - ItemStack itemstack1 = player.getOffhandItem(); - boolean flag = itemstack.is(Items.FISHING_ROD); -@@ -259,7 +281,7 @@ - if (!player.isRemoved() && player.isAlive() && (flag || flag1) && this.distanceToSqr((Entity) player) <= 1024.0D) { - return false; - } else { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - return true; - } - } -@@ -267,7 +289,7 @@ - private void checkCollision() { - HitResult movingobjectposition = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); - -- this.hitTargetOrDeflectSelf(movingobjectposition); -+ this.preHitTargetOrDeflectSelf(movingobjectposition); // CraftBukkit - projectile hit event - } - - @Override -@@ -300,11 +322,11 @@ - int i = 1; - BlockPos blockposition1 = pos.above(); - -- if (this.random.nextFloat() < 0.25F && this.level().isRainingAt(blockposition1)) { -+ if (this.rainInfluenced && this.random.nextFloat() < 0.25F && this.level().isRainingAt(blockposition1)) { // CraftBukkit - ++i; - } - -- if (this.random.nextFloat() < 0.5F && !this.level().canSeeSky(blockposition1)) { -+ if (this.skyInfluenced && this.random.nextFloat() < 0.5F && !this.level().canSeeSky(blockposition1)) { // CraftBukkit - --i; - } - -@@ -314,6 +336,10 @@ - this.timeUntilLured = 0; - this.timeUntilHooked = 0; - this.getEntityData().set(FishingHook.DATA_BITING, false); -+ // CraftBukkit start -+ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.getPlayerOwner().getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.FAILED_ATTEMPT); -+ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); -+ // CraftBukkit end - } - } else { - float f; -@@ -347,6 +373,13 @@ - worldserver.sendParticles(ParticleTypes.FISHING, d0, d1, d2, 0, (double) (-f4), 0.01D, (double) f3, 1.0D); - } - } else { -+ // CraftBukkit start -+ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.getPlayerOwner().getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.BITE); -+ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); -+ if (playerFishEvent.isCancelled()) { -+ return; -+ } -+ // CraftBukkit end - this.playSound(SoundEvents.FISHING_BOBBER_SPLASH, 0.25F, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.4F); - double d3 = this.getY() + 0.5D; - -@@ -379,16 +412,34 @@ - } - - if (this.timeUntilLured <= 0) { -- this.fishAngle = Mth.nextFloat(this.random, 0.0F, 360.0F); -- this.timeUntilHooked = Mth.nextInt(this.random, 20, 80); -+ // CraftBukkit start - logic to modify fishing wait time, lure time, and lure angle -+ this.fishAngle = Mth.nextFloat(this.random, this.minLureAngle, this.maxLureAngle); -+ this.timeUntilHooked = Mth.nextInt(this.random, this.minLureTime, this.maxLureTime); -+ // CraftBukkit end -+ // Paper start - Add missing fishing event state -+ if (this.getPlayerOwner() != null) { -+ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.getPlayerOwner().getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.LURED); -+ if (!playerFishEvent.callEvent()) { -+ this.timeUntilHooked = 0; -+ return; -+ } -+ } -+ // Paper end - Add missing fishing event state - } - } else { -- this.timeUntilLured = Mth.nextInt(this.random, 100, 600); -- this.timeUntilLured -= this.lureSpeed; -+ // CraftBukkit start - logic to modify fishing wait time -+ this.resetTimeUntilLured(); // Paper - more projectile api - extract time until lured reset logic -+ // CraftBukkit end - } - } - - } -+ // Paper start - more projectile api - extract time until lured reset logic -+ public void resetTimeUntilLured() { -+ this.timeUntilLured = Mth.nextInt(this.random, this.minWaitTime, this.maxWaitTime); -+ this.timeUntilLured -= (this.applyLure) ? (this.lureSpeed >= this.maxWaitTime ? this.timeUntilLured - 1 : this.lureSpeed ) : 0; // Paper - Fix Lure infinite loop -+ } -+ // Paper end - more projectile api - extract time until lured reset logic - - public boolean calculateOpenWater(BlockPos pos) { - FishingHook.OpenWaterType entityfishinghook_waterposition = FishingHook.OpenWaterType.INVALID; -@@ -445,17 +496,35 @@ - @Override - public void readAdditionalSaveData(CompoundTag nbt) {} - -+ // Paper start - Add hand parameter to PlayerFishEvent -+ @Deprecated -+ @io.papermc.paper.annotation.DoNotUse - public int retrieve(ItemStack usedItem) { -- Player entityhuman = this.getPlayerOwner(); -+ return this.retrieve(net.minecraft.world.InteractionHand.MAIN_HAND, usedItem); -+ } - -+ public int retrieve(net.minecraft.world.InteractionHand hand, ItemStack usedItem) { -+ // Paper end - Add hand parameter to PlayerFishEvent -+ net.minecraft.world.entity.player.Player entityhuman = this.getPlayerOwner(); -+ - if (!this.level().isClientSide && entityhuman != null && !this.shouldStopFishing(entityhuman)) { - int i = 0; - - if (this.hookedIn != null) { -+ // CraftBukkit start -+ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), this.hookedIn.getBukkitEntity(), (FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), PlayerFishEvent.State.CAUGHT_ENTITY); // Paper - Add hand parameter to PlayerFishEvent -+ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); -+ -+ if (playerFishEvent.isCancelled()) { -+ return 0; -+ } -+ if (this.hookedIn != null) { // Paper - re-check to see if there is a hooked entity -+ // CraftBukkit end - this.pullEntity(this.hookedIn); - CriteriaTriggers.FISHING_ROD_HOOKED.trigger((ServerPlayer) entityhuman, usedItem, this, Collections.emptyList()); - this.level().broadcastEntityEvent(this, (byte) 31); - i = this.hookedIn instanceof ItemEntity ? 3 : 5; -+ } // Paper - re-check to see if there is a hooked entity - } else if (this.nibble > 0) { - LootParams lootparams = (new LootParams.Builder((ServerLevel) this.level())).withParameter(LootContextParams.ORIGIN, this.position()).withParameter(LootContextParams.TOOL, usedItem).withParameter(LootContextParams.THIS_ENTITY, this).withLuck((float) this.luck + entityhuman.getLuck()).create(LootContextParamSets.FISHING); - LootTable loottable = this.level().getServer().reloadableRegistries().getLootTable(BuiltInLootTables.FISHING); -@@ -466,15 +535,38 @@ - - while (iterator.hasNext()) { - ItemStack itemstack1 = (ItemStack) iterator.next(); -- ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemstack1); -+ // Paper start - new ItemEntity would throw if for whatever reason (mostly shitty datapacks) the itemstack1 turns out to be empty -+ // if the item stack is empty we instead just have our entityitem as null -+ ItemEntity entityitem = null; -+ if (!itemstack1.isEmpty()) { -+ entityitem = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemstack1); -+ } -+ // Paper end -+ // CraftBukkit start -+ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), entityitem != null ? entityitem.getBukkitEntity() : null, (FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), PlayerFishEvent.State.CAUGHT_FISH); // Paper - entityitem may be null // Paper - Add hand parameter to PlayerFishEvent -+ playerFishEvent.setExpToDrop(this.random.nextInt(6) + 1); -+ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); -+ -+ if (playerFishEvent.isCancelled()) { -+ return 0; -+ } -+ // CraftBukkit end - double d0 = entityhuman.getX() - this.getX(); - double d1 = entityhuman.getY() - this.getY(); - double d2 = entityhuman.getZ() - this.getZ(); - double d3 = 0.1D; - -- entityitem.setDeltaMovement(d0 * 0.1D, d1 * 0.1D + Math.sqrt(Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2)) * 0.08D, d2 * 0.1D); -- this.level().addFreshEntity(entityitem); -- entityhuman.level().addFreshEntity(new ExperienceOrb(entityhuman.level(), entityhuman.getX(), entityhuman.getY() + 0.5D, entityhuman.getZ() + 0.5D, this.random.nextInt(6) + 1)); -+ // Paper start - entity item can be null, so we need to check against this -+ if (entityitem != null) { -+ entityitem.setDeltaMovement(d0 * 0.1D, d1 * 0.1D + Math.sqrt(Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2)) * 0.08D, d2 * 0.1D); -+ this.level().addFreshEntity(entityitem); -+ } -+ // Paper end -+ // CraftBukkit start - this.random.nextInt(6) + 1 -> playerFishEvent.getExpToDrop() -+ if (playerFishEvent.getExpToDrop() > 0) { -+ entityhuman.level().addFreshEntity(new ExperienceOrb(entityhuman.level(), entityhuman.getX(), entityhuman.getY() + 0.5D, entityhuman.getZ() + 0.5D, playerFishEvent.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.FISHING, this.getPlayerOwner(), this)); // Paper -+ } -+ // CraftBukkit end - if (itemstack1.is(ItemTags.FISHES)) { - entityhuman.awardStat(Stats.FISH_CAUGHT, 1); - } -@@ -484,10 +576,27 @@ - } - - if (this.onGround()) { -+ // CraftBukkit start -+ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), PlayerFishEvent.State.IN_GROUND); // Paper - Add hand parameter to PlayerFishEvent -+ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); -+ -+ if (playerFishEvent.isCancelled()) { -+ return 0; -+ } -+ // CraftBukkit end - i = 2; - } -+ // CraftBukkit start -+ if (i == 0) { -+ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), PlayerFishEvent.State.REEL_IN); // Paper - Add hand parameter to PlayerFishEvent -+ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); -+ if (playerFishEvent.isCancelled()) { -+ return 0; -+ } -+ } -+ // CraftBukkit end - -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - return i; - } else { - return 0; -@@ -496,7 +605,7 @@ - - @Override - public void handleEntityEvent(byte status) { -- if (status == 31 && this.level().isClientSide && this.hookedIn instanceof Player && ((Player) this.hookedIn).isLocalPlayer()) { -+ if (status == 31 && this.level().isClientSide && this.hookedIn instanceof net.minecraft.world.entity.player.Player && ((net.minecraft.world.entity.player.Player) this.hookedIn).isLocalPlayer()) { - this.pullEntity(this.hookedIn); - } - -@@ -520,8 +629,15 @@ - - @Override - public void remove(Entity.RemovalReason reason) { -+ // CraftBukkit start - add Bukkit remove cause -+ this.remove(reason, null); -+ } -+ -+ @Override -+ public void remove(Entity.RemovalReason entity_removalreason, EntityRemoveEvent.Cause cause) { -+ // CraftBukkit end - this.updateOwnerInfo((FishingHook) null); -- super.remove(reason); -+ super.remove(entity_removalreason, cause); // CraftBukkit - add Bukkit remove cause - } - - @Override -@@ -536,7 +652,7 @@ - } - - private void updateOwnerInfo(@Nullable FishingHook fishingBobber) { -- Player entityhuman = this.getPlayerOwner(); -+ net.minecraft.world.entity.player.Player entityhuman = this.getPlayerOwner(); - - if (entityhuman != null) { - entityhuman.fishing = fishingBobber; -@@ -545,10 +661,10 @@ - } - - @Nullable -- public Player getPlayerOwner() { -+ public net.minecraft.world.entity.player.Player getPlayerOwner() { - Entity entity = this.getOwner(); - -- return entity instanceof Player ? (Player) entity : null; -+ return entity instanceof net.minecraft.world.entity.player.Player ? (net.minecraft.world.entity.player.Player) entity : null; - } - - @Nullable -@@ -575,7 +691,7 @@ - int i = packet.getData(); - - FishingHook.LOGGER.error("Failed to recreate fishing hook on client. {} (id: {}) is not a valid owner.", this.level().getEntity(i), i); -- this.discard(); -+ this.discard(null); // CraftBukkit - add Bukkit remove cause - } - - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/LargeFireball.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/LargeFireball.java.patch deleted file mode 100644 index 494d25292d..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/LargeFireball.java.patch +++ /dev/null @@ -1,56 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/LargeFireball.java -+++ b/net/minecraft/world/entity/projectile/LargeFireball.java -@@ -12,6 +12,10 @@ - import net.minecraft.world.phys.EntityHitResult; - import net.minecraft.world.phys.HitResult; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityRemoveEvent; -+import org.bukkit.event.entity.ExplosionPrimeEvent; -+// CraftBukkit end - - public class LargeFireball extends Fireball { - -@@ -19,11 +23,13 @@ - - public LargeFireball(EntityType type, Level world) { - super(type, world); -+ this.isIncendiary = (world instanceof ServerLevel worldserver) && worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit - } - - public LargeFireball(Level world, LivingEntity owner, Vec3 velocity, int explosionPower) { - super(EntityType.FIREBALL, owner, velocity, world); - this.explosionPower = explosionPower; -+ this.isIncendiary = (world instanceof ServerLevel worldserver) && worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit - } - - @Override -@@ -34,8 +40,16 @@ - if (world instanceof ServerLevel worldserver) { - boolean flag = worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); - -- this.level().explode(this, this.getX(), this.getY(), this.getZ(), (float) this.explosionPower, flag, Level.ExplosionInteraction.MOB); -- this.discard(); -+ // CraftBukkit start - fire ExplosionPrimeEvent -+ ExplosionPrimeEvent event = new ExplosionPrimeEvent((org.bukkit.entity.Explosive) this.getBukkitEntity()); -+ this.level().getCraftServer().getPluginManager().callEvent(event); -+ -+ if (!event.isCancelled()) { -+ // give 'this' instead of (Entity) null so we know what causes the damage -+ this.level().explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); -+ } -+ // CraftBukkit end -+ this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause - } - - } -@@ -65,7 +79,8 @@ - public void readAdditionalSaveData(CompoundTag nbt) { - super.readAdditionalSaveData(nbt); - if (nbt.contains("ExplosionPower", 99)) { -- this.explosionPower = nbt.getByte("ExplosionPower"); -+ // CraftBukkit - set bukkitYield when setting explosionpower -+ this.bukkitYield = this.explosionPower = nbt.getByte("ExplosionPower"); - } - - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/LlamaSpit.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/LlamaSpit.java.patch deleted file mode 100644 index 370c83f5da..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/LlamaSpit.java.patch +++ /dev/null @@ -1,42 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/LlamaSpit.java -+++ b/net/minecraft/world/entity/projectile/LlamaSpit.java -@@ -17,6 +17,9 @@ - import net.minecraft.world.phys.EntityHitResult; - import net.minecraft.world.phys.HitResult; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class LlamaSpit extends Projectile { - -@@ -41,7 +44,7 @@ - Vec3 vec3d = this.getDeltaMovement(); - HitResult movingobjectposition = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); - -- this.hitTargetOrDeflectSelf(movingobjectposition); -+ this.preHitTargetOrDeflectSelf(movingobjectposition); // CraftBukkit - projectile hit event - double d0 = this.getX() + vec3d.x; - double d1 = this.getY() + vec3d.y; - double d2 = this.getZ() + vec3d.z; -@@ -50,9 +53,9 @@ - float f = 0.99F; - - if (this.level().getBlockStates(this.getBoundingBox()).noneMatch(BlockBehaviour.BlockStateBase::isAir)) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - } else if (this.isInWaterOrBubble()) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - } else { - this.setDeltaMovement(vec3d.scale(0.9900000095367432D)); - this.applyGravity(); -@@ -83,7 +86,7 @@ - protected void onHitBlock(BlockHitResult blockHitResult) { - super.onHitBlock(blockHitResult); - if (!this.level().isClientSide) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause - } - - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/Projectile.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/Projectile.java.patch deleted file mode 100644 index 4e0aeff12d..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/Projectile.java.patch +++ /dev/null @@ -1,231 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/Projectile.java -+++ b/net/minecraft/world/entity/projectile/Projectile.java -@@ -35,6 +35,9 @@ - import net.minecraft.world.phys.EntityHitResult; - import net.minecraft.world.phys.HitResult; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start -+import org.bukkit.projectiles.ProjectileSource; -+// CraftBukkit end - - public abstract class Projectile extends Entity implements TraceableEntity { - -@@ -47,6 +50,10 @@ - @Nullable - private Entity lastDeflectedBy; - -+ // CraftBukkit start -+ protected boolean hitCancelled = false; -+ // CraftBukkit end -+ - Projectile(EntityType type, Level world) { - super(type, world); - } -@@ -56,16 +63,35 @@ - this.ownerUUID = entity.getUUID(); - this.cachedOwner = entity; - } -- -+ // Paper start - Refresh ProjectileSource for projectiles -+ else { -+ this.ownerUUID = null; -+ this.cachedOwner = null; -+ this.projectileSource = null; -+ } -+ // Paper end - Refresh ProjectileSource for projectiles -+ this.refreshProjectileSource(false); // Paper - } -+ // Paper start - Refresh ProjectileSource for projectiles -+ public void refreshProjectileSource(boolean fillCache) { -+ if (fillCache) { -+ this.getOwner(); -+ } -+ if (this.cachedOwner != null && !this.cachedOwner.isRemoved() && this.projectileSource == null && this.cachedOwner.getBukkitEntity() instanceof ProjectileSource projSource) { -+ this.projectileSource = projSource; -+ } -+ } -+ // Paper end - Refresh ProjectileSource for projectiles - - @Nullable - @Override - public Entity getOwner() { - if (this.cachedOwner != null && !this.cachedOwner.isRemoved()) { -+ this.refreshProjectileSource(false); // Paper - Refresh ProjectileSource for projectiles - return this.cachedOwner; - } else if (this.ownerUUID != null) { - this.cachedOwner = this.findOwner(this.ownerUUID); -+ this.refreshProjectileSource(false); // Paper - Refresh ProjectileSource for projectiles - return this.cachedOwner; - } else { - return null; -@@ -108,6 +134,7 @@ - protected void readAdditionalSaveData(CompoundTag nbt) { - if (nbt.hasUUID("Owner")) { - this.setOwnerThroughUUID(nbt.getUUID("Owner")); -+ if (this instanceof ThrownEnderpearl && this.level() != null && this.level().paperConfig().fixes.disableUnloadedChunkEnderpearlExploit && this.level().paperConfig().misc.legacyEnderPearlBehavior) { this.ownerUUID = null; } // Paper - Reset pearls when they stop being ticked; Don't store shooter name for pearls to block enderpearl travel exploit - } - - this.leftOwner = nbt.getBoolean("LeftOwner"); -@@ -184,12 +211,20 @@ - - this.shoot((double) f5, (double) f6, (double) f7, speed, divergence); - Vec3 vec3d = shooter.getKnownMovement(); -- -+ // Paper start - allow disabling relative velocity -+ if (!shooter.level().paperConfig().misc.disableRelativeProjectileVelocity) { - this.setDeltaMovement(this.getDeltaMovement().add(vec3d.x, shooter.onGround() ? 0.0D : vec3d.y, vec3d.z)); -+ } -+ // Paper end - allow disabling relative velocity - } - - public static T spawnProjectileFromRotation(Projectile.ProjectileFactory creator, ServerLevel world, ItemStack projectileStack, LivingEntity shooter, float roll, float power, float divergence) { -- return Projectile.spawnProjectile(creator.create(world, shooter, projectileStack), world, projectileStack, (iprojectile) -> { -+ // Paper start - PlayerLaunchProjectileEvent -+ return spawnProjectileFromRotationDelayed(creator, world, projectileStack, shooter, roll, power, divergence).spawn(); -+ } -+ public static Delayed spawnProjectileFromRotationDelayed(Projectile.ProjectileFactory creator, ServerLevel world, ItemStack projectileStack, LivingEntity shooter, float roll, float power, float divergence) { -+ return Projectile.spawnProjectileDelayed(creator.create(world, shooter, projectileStack), world, projectileStack, (iprojectile) -> { -+ // Paper end - PlayerLaunchProjectileEvent - iprojectile.shootFromRotation(shooter, shooter.getXRot(), shooter.getYRot(), roll, power, divergence); - }); - } -@@ -201,7 +236,12 @@ - } - - public static T spawnProjectileUsingShoot(T projectile, ServerLevel world, ItemStack projectileStack, double velocityX, double velocityY, double velocityZ, float power, float divergence) { -- return Projectile.spawnProjectile(projectile, world, projectileStack, (iprojectile) -> { -+ // Paper start - fixes and addition to spawn reason API -+ return spawnProjectileUsingShootDelayed(projectile, world, projectileStack, velocityX, velocityY, velocityZ, power, divergence).spawn(); -+ } -+ public static Delayed spawnProjectileUsingShootDelayed(T projectile, ServerLevel world, ItemStack projectileStack, double velocityX, double velocityY, double velocityZ, float power, float divergence) { -+ return Projectile.spawnProjectileDelayed(projectile, world, projectileStack, (iprojectile) -> { -+ // Paper end - fixes and addition to spawn reason API - projectile.shoot(velocityX, velocityY, velocityZ, power, divergence); - }); - } -@@ -211,11 +251,45 @@ - }); - } - -+ // Paper start - delayed projectile spawning -+ public record Delayed( -+ T projectile, -+ ServerLevel world, -+ ItemStack projectileStack -+ ) { -+ // Taken from net.minecraft.world.entity.projectile.Projectile.spawnProjectile(T, net.minecraft.server.level.ServerLevel, net.minecraft.world.item.ItemStack, java.util.function.Consumer) -+ public boolean attemptSpawn() { -+ if (!world.addFreshEntity(projectile)) return false; -+ projectile.applyOnProjectileSpawned(this.world, this.projectileStack); -+ return true; -+ } -+ -+ public T spawn() { -+ this.attemptSpawn(); -+ return projectile(); -+ } -+ -+ public boolean attemptSpawn(final org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { -+ if (!world.addFreshEntity(projectile, reason)) return false; -+ projectile.applyOnProjectileSpawned(this.world, this.projectileStack); -+ return true; -+ } -+ -+ public T spawn(final org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { -+ this.attemptSpawn(reason); -+ return projectile(); -+ } -+ } -+ // Paper end - delayed projectile spawning -+ - public static T spawnProjectile(T projectile, ServerLevel world, ItemStack projectileStack, Consumer beforeSpawn) { -+ // Paper start - delayed projectile spawning -+ return spawnProjectileDelayed(projectile, world, projectileStack, beforeSpawn).spawn(); -+ } -+ public static Delayed spawnProjectileDelayed(T projectile, ServerLevel world, ItemStack projectileStack, Consumer beforeSpawn) { -+ // Paper end - delayed projectile spawning - beforeSpawn.accept(projectile); -- world.addFreshEntity(projectile); -- projectile.applyOnProjectileSpawned(world, projectileStack); -- return projectile; -+ return new Delayed<>(projectile, world, projectileStack); // Paper - delayed projectile spawning - } - - public void applyOnProjectileSpawned(ServerLevel world, ItemStack projectileStack) { -@@ -232,6 +306,17 @@ - - } - -+ // CraftBukkit start - call projectile hit event -+ public ProjectileDeflection preHitTargetOrDeflectSelf(HitResult movingobjectposition) { // Paper - protected -> public -+ org.bukkit.event.entity.ProjectileHitEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callProjectileHitEvent(this, movingobjectposition); -+ this.hitCancelled = event != null && event.isCancelled(); -+ if (movingobjectposition.getType() == HitResult.Type.BLOCK || !this.hitCancelled) { -+ return this.hitTargetOrDeflectSelf(movingobjectposition); -+ } -+ return ProjectileDeflection.NONE; -+ } -+ // CraftBukkit end -+ - protected ProjectileDeflection hitTargetOrDeflectSelf(HitResult hitResult) { - if (hitResult.getType() == HitResult.Type.ENTITY) { - EntityHitResult movingobjectpositionentity = (EntityHitResult) hitResult; -@@ -269,7 +354,13 @@ - public boolean deflect(ProjectileDeflection deflection, @Nullable Entity deflector, @Nullable Entity owner, boolean fromAttack) { - deflection.deflect(this, deflector, this.random); - if (!this.level().isClientSide) { -- this.setOwner(owner); -+ // Paper start - Fix PickupStatus getting reset -+ if (this instanceof AbstractArrow arrow) { -+ arrow.setOwner(owner, false); -+ } else { -+ this.setOwner(owner); -+ } -+ // Paper end - Fix PickupStatus getting reset - this.onDeflection(deflector, fromAttack); - } - -@@ -309,6 +400,11 @@ - protected void onHitEntity(EntityHitResult entityHitResult) {} - - protected void onHitBlock(BlockHitResult blockHitResult) { -+ // CraftBukkit start - cancellable hit event -+ if (this.hitCancelled) { -+ return; -+ } -+ // CraftBukkit end - BlockState iblockdata = this.level().getBlockState(blockHitResult.getBlockPos()); - - iblockdata.onProjectileHit(this.level(), iblockdata, blockHitResult, this); -@@ -320,6 +416,15 @@ - } else { - Entity entity1 = this.getOwner(); - -+ // Paper start - Cancel hit for vanished players -+ if (entity1 instanceof net.minecraft.server.level.ServerPlayer && entity instanceof net.minecraft.server.level.ServerPlayer) { -+ org.bukkit.entity.Player collided = (org.bukkit.entity.Player) entity.getBukkitEntity(); -+ org.bukkit.entity.Player shooter = (org.bukkit.entity.Player) entity1.getBukkitEntity(); -+ if (!shooter.canSee(collided)) { -+ return false; -+ } -+ } -+ // Paper end - Cancel hit for vanished players - return entity1 == null || this.leftOwner || !entity1.isPassengerOfSameVehicle(entity); - } - } -@@ -333,14 +438,8 @@ - } - - protected static float lerpRotation(float prevRot, float newRot) { -- while (newRot - prevRot < -180.0F) { -- prevRot -= 360.0F; -- } -+ prevRot += Math.round((newRot - prevRot) / 360.0F) * 360.0F; // Paper - stop large look changes from crashing the server - -- while (newRot - prevRot >= 180.0F) { -- prevRot += 360.0F; -- } -- - return Mth.lerp(0.2F, prevRot, newRot); - } - diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch deleted file mode 100644 index bac5f4b417..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch +++ /dev/null @@ -1,100 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/ShulkerBullet.java -+++ b/net/minecraft/world/entity/projectile/ShulkerBullet.java -@@ -31,6 +31,9 @@ - import net.minecraft.world.phys.EntityHitResult; - import net.minecraft.world.phys.HitResult; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class ShulkerBullet extends Projectile { - -@@ -60,8 +63,21 @@ - this.finalTarget = target; - this.currentMoveDirection = Direction.UP; - this.selectNextMoveDirection(axis); -+ this.projectileSource = (org.bukkit.entity.LivingEntity) owner.getBukkitEntity(); // CraftBukkit - } - -+ // CraftBukkit start -+ public Entity getTarget() { -+ return this.finalTarget; -+ } -+ -+ public void setTarget(Entity e) { -+ this.finalTarget = e; -+ this.currentMoveDirection = Direction.UP; -+ this.selectNextMoveDirection(Direction.Axis.X); -+ } -+ // CraftBukkit end -+ - @Override - public SoundSource getSoundSource() { - return SoundSource.HOSTILE; -@@ -194,7 +210,7 @@ - @Override - public void checkDespawn() { - if (this.level().getDifficulty() == Difficulty.PEACEFUL) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - } - - } -@@ -239,7 +255,7 @@ - } - - if (movingobjectposition != null && this.isAlive() && movingobjectposition.getType() != HitResult.Type.MISS) { -- this.hitTargetOrDeflectSelf(movingobjectposition); -+ this.preHitTargetOrDeflectSelf(movingobjectposition); // CraftBukkit - projectile hit event - } - - ProjectileUtil.rotateTowardsMovement(this, 0.5F); -@@ -312,7 +328,7 @@ - if (entity instanceof LivingEntity) { - LivingEntity entityliving1 = (LivingEntity) entity; - -- entityliving1.addEffect(new MobEffectInstance(MobEffects.LEVITATION, 200), (Entity) MoreObjects.firstNonNull(entity1, this)); -+ entityliving1.addEffect(new MobEffectInstance(MobEffects.LEVITATION, 200), (Entity) MoreObjects.firstNonNull(entity1, this), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit - } - } - -@@ -326,14 +342,20 @@ - } - - private void destroy() { -- this.discard(); -+ // CraftBukkit start - add Bukkit remove cause -+ this.destroy(null); -+ } -+ -+ private void destroy(EntityRemoveEvent.Cause cause) { -+ this.discard(cause); -+ // CraftBukkit end - this.level().gameEvent((Holder) GameEvent.ENTITY_DAMAGE, this.position(), GameEvent.Context.of((Entity) this)); - } - - @Override - protected void onHit(HitResult hitResult) { - super.onHit(hitResult); -- this.destroy(); -+ this.destroy(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause - } - - @Override -@@ -348,9 +370,14 @@ - - @Override - public boolean hurtServer(ServerLevel world, DamageSource source, float amount) { -+ // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, amount, false)) { -+ return false; -+ } -+ // CraftBukkit end - this.playSound(SoundEvents.SHULKER_BULLET_HURT, 1.0F, 1.0F); - world.sendParticles(ParticleTypes.CRIT, this.getX(), this.getY(), this.getZ(), 15, 0.2D, 0.2D, 0.2D, 0.0D); -- this.destroy(); -+ this.destroy(EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause - return true; - } - diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/SmallFireball.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/SmallFireball.java.patch deleted file mode 100644 index 65522ba256..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/SmallFireball.java.patch +++ /dev/null @@ -1,63 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/SmallFireball.java -+++ b/net/minecraft/world/entity/projectile/SmallFireball.java -@@ -15,6 +15,10 @@ - import net.minecraft.world.phys.EntityHitResult; - import net.minecraft.world.phys.HitResult; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityCombustByEntityEvent; -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class SmallFireball extends Fireball { - -@@ -24,6 +28,11 @@ - - public SmallFireball(Level world, LivingEntity owner, Vec3 velocity) { - super(EntityType.SMALL_FIREBALL, owner, velocity, world); -+ // CraftBukkit start -+ if (this.getOwner() != null && this.getOwner() instanceof Mob) { -+ this.isIncendiary = (world instanceof ServerLevel worldserver) && worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); -+ } -+ // CraftBukkit end - } - - public SmallFireball(Level world, double x, double y, double z, Vec3 velocity) { -@@ -40,7 +49,14 @@ - Entity entity1 = this.getOwner(); - int i = entity.getRemainingFireTicks(); - -- entity.igniteForSeconds(5.0F); -+ // CraftBukkit start - Entity damage by entity event + combust event -+ EntityCombustByEntityEvent event = new EntityCombustByEntityEvent((org.bukkit.entity.Projectile) this.getBukkitEntity(), entity.getBukkitEntity(), 5.0F); -+ entity.level().getCraftServer().getPluginManager().callEvent(event); -+ -+ if (!event.isCancelled()) { -+ entity.igniteForSeconds(event.getDuration(), false); -+ } -+ // CraftBukkit end - DamageSource damagesource = this.damageSources().fireball(this, entity1); - - if (!entity.hurtServer(worldserver, damagesource, 5.0F)) { -@@ -60,10 +76,10 @@ - if (world instanceof ServerLevel worldserver) { - Entity entity = this.getOwner(); - -- if (!(entity instanceof Mob) || worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { -+ if (this.isIncendiary) { // CraftBukkit - BlockPos blockposition = blockHitResult.getBlockPos().relative(blockHitResult.getDirection()); - -- if (this.level().isEmptyBlock(blockposition)) { -+ if (this.level().isEmptyBlock(blockposition) && !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level(), blockposition, this).isCancelled()) { // CraftBukkit - this.level().setBlockAndUpdate(blockposition, BaseFireBlock.getState(this.level(), blockposition)); - } - } -@@ -75,7 +91,7 @@ - protected void onHit(HitResult hitResult) { - super.onHit(hitResult); - if (!this.level().isClientSide) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause - } - - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/Snowball.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/Snowball.java.patch deleted file mode 100644 index 8d2ce7e8d8..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/Snowball.java.patch +++ /dev/null @@ -1,21 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/Snowball.java -+++ b/net/minecraft/world/entity/projectile/Snowball.java -@@ -13,6 +13,9 @@ - import net.minecraft.world.level.Level; - import net.minecraft.world.phys.EntityHitResult; - import net.minecraft.world.phys.HitResult; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class Snowball extends ThrowableItemProjectile { - -@@ -65,7 +68,7 @@ - super.onHit(hitResult); - if (!this.level().isClientSide) { - this.level().broadcastEntityEvent(this, (byte) 3); -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause - } - - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/SpectralArrow.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/SpectralArrow.java.patch deleted file mode 100644 index 629d60da70..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/SpectralArrow.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/SpectralArrow.java -+++ b/net/minecraft/world/entity/projectile/SpectralArrow.java -@@ -41,7 +41,7 @@ - super.doPostHurtEffects(target); - MobEffectInstance mobeffect = new MobEffectInstance(MobEffects.GLOWING, this.duration, 0); - -- target.addEffect(mobeffect, this.getEffectSource()); -+ target.addEffect(mobeffect, this.getEffectSource(), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ARROW); // CraftBukkit - } - - @Override diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch deleted file mode 100644 index db8a43fd04..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/ThrowableProjectile.java -+++ b/net/minecraft/world/entity/projectile/ThrowableProjectile.java -@@ -63,7 +63,7 @@ - this.applyEffectsFromBlocks(); - super.tick(); - if (movingobjectposition.getType() != HitResult.Type.MISS && this.isAlive()) { -- this.hitTargetOrDeflectSelf(movingobjectposition); -+ this.preHitTargetOrDeflectSelf(movingobjectposition); // CraftBukkit - projectile hit event - } - - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrownEgg.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrownEgg.java.patch deleted file mode 100644 index 5df84b160a..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrownEgg.java.patch +++ /dev/null @@ -1,121 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/ThrownEgg.java -+++ b/net/minecraft/world/entity/projectile/ThrownEgg.java -@@ -1,33 +1,39 @@ - package net.minecraft.world.entity.projectile; - --import net.minecraft.core.particles.ItemParticleOption; --import net.minecraft.core.particles.ParticleTypes; --import net.minecraft.world.entity.EntityDimensions; - import net.minecraft.world.entity.EntitySpawnReason; --import net.minecraft.world.entity.EntityType; - import net.minecraft.world.entity.LivingEntity; --import net.minecraft.world.entity.animal.Chicken; - import net.minecraft.world.item.Item; - import net.minecraft.world.item.ItemStack; - import net.minecraft.world.item.Items; - import net.minecraft.world.level.Level; - import net.minecraft.world.phys.EntityHitResult; - import net.minecraft.world.phys.HitResult; -+import net.minecraft.core.particles.ItemParticleOption; -+import net.minecraft.core.particles.ParticleTypes; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.entity.EntityDimensions; -+import org.bukkit.entity.Ageable; -+import org.bukkit.entity.EntityType; -+import org.bukkit.entity.Player; -+import org.bukkit.event.entity.EntityRemoveEvent; -+import org.bukkit.event.player.PlayerEggThrowEvent; -+// CraftBukkit end - - public class ThrownEgg extends ThrowableItemProjectile { - - private static final EntityDimensions ZERO_SIZED_DIMENSIONS = EntityDimensions.fixed(0.0F, 0.0F); - -- public ThrownEgg(EntityType type, Level world) { -+ public ThrownEgg(net.minecraft.world.entity.EntityType type, Level world) { - super(type, world); - } - - public ThrownEgg(Level world, LivingEntity owner, ItemStack stack) { -- super(EntityType.EGG, owner, world, stack); -+ super(net.minecraft.world.entity.EntityType.EGG, owner, world, stack); - } - - public ThrownEgg(Level world, double x, double y, double z, ItemStack stack) { -- super(EntityType.EGG, x, y, z, world, stack); -+ super(net.minecraft.world.entity.EntityType.EGG, x, y, z, world, stack); - } - - @Override -@@ -52,30 +58,65 @@ - protected void onHit(HitResult hitResult) { - super.onHit(hitResult); - if (!this.level().isClientSide) { -- if (this.random.nextInt(8) == 0) { -+ // CraftBukkit start -+ boolean hatching = this.random.nextInt(8) == 0; -+ if (true) { -+ // CraftBukkit end - byte b0 = 1; - - if (this.random.nextInt(32) == 0) { - b0 = 4; - } - -+ // CraftBukkit start -+ EntityType hatchingType = EntityType.CHICKEN; -+ -+ Entity shooter = this.getOwner(); -+ if (!hatching) { -+ b0 = 0; -+ } -+ if (shooter instanceof ServerPlayer) { -+ PlayerEggThrowEvent event = new PlayerEggThrowEvent((Player) shooter.getBukkitEntity(), (org.bukkit.entity.Egg) this.getBukkitEntity(), hatching, b0, hatchingType); -+ this.level().getCraftServer().getPluginManager().callEvent(event); -+ -+ b0 = event.getNumHatches(); -+ hatching = event.isHatching(); -+ hatchingType = event.getHatchingType(); -+ // If hatching is set to false, ensure child count is 0 -+ if (!hatching) { -+ b0 = 0; -+ } -+ } -+ // CraftBukkit end -+ // Paper start - Add ThrownEggHatchEvent -+ com.destroystokyo.paper.event.entity.ThrownEggHatchEvent event = new com.destroystokyo.paper.event.entity.ThrownEggHatchEvent((org.bukkit.entity.Egg) getBukkitEntity(), hatching, b0, hatchingType); -+ event.callEvent(); -+ hatching = event.isHatching(); -+ b0 = hatching ? event.getNumHatches() : 0; // If hatching is set to false, ensure child count is 0 -+ hatchingType = event.getHatchingType(); -+ // Paper end - Add ThrownEggHatchEvent -+ - for (int i = 0; i < b0; ++i) { -- Chicken entitychicken = (Chicken) EntityType.CHICKEN.create(this.level(), EntitySpawnReason.TRIGGERED); -+ Entity entitychicken = this.level().getWorld().makeEntity(new org.bukkit.Location(this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F), hatchingType.getEntityClass()); // CraftBukkit - - if (entitychicken != null) { -- entitychicken.setAge(-24000); -+ // CraftBukkit start -+ if (entitychicken.getBukkitEntity() instanceof Ageable) { -+ ((Ageable) entitychicken.getBukkitEntity()).setBaby(); -+ } -+ // CraftBukkit end - entitychicken.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F); - if (!entitychicken.fudgePositionAfterSizeChange(ThrownEgg.ZERO_SIZED_DIMENSIONS)) { - break; - } - -- this.level().addFreshEntity(entitychicken); -+ this.level().addFreshEntity(entitychicken, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EGG); // CraftBukkit - } - } - } - - this.level().broadcastEntityEvent(this, (byte) 3); -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause - } - - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch deleted file mode 100644 index f24cfeb088..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch +++ /dev/null @@ -1,95 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -+++ b/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -@@ -24,10 +24,15 @@ - import net.minecraft.world.level.Level; - import net.minecraft.world.level.block.Blocks; - import net.minecraft.world.level.block.state.BlockState; -+import net.minecraft.world.level.dimension.LevelStem; - import net.minecraft.world.level.portal.TeleportTransition; - import net.minecraft.world.phys.EntityHitResult; - import net.minecraft.world.phys.HitResult; - import net.minecraft.world.phys.Vec3; -+import org.bukkit.event.entity.CreatureSpawnEvent; -+import org.bukkit.event.entity.EntityRemoveEvent; -+import org.bukkit.event.player.PlayerTeleportEvent; -+// CraftBukkit end - - public class ThrownEnderpearl extends ThrowableItemProjectile { - -@@ -140,12 +145,19 @@ - ServerPlayer entityplayer = (ServerPlayer) entity; - - if (entityplayer.connection.isAcceptingMessages()) { -+ // CraftBukkit start -+ ServerPlayer entityplayer1 = entityplayer.teleport(new TeleportTransition(worldserver, vec3d, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.ROTATION, Relative.DELTA), TeleportTransition.DO_NOTHING, PlayerTeleportEvent.TeleportCause.ENDER_PEARL)); -+ if (entityplayer1 == null) { -+ this.discard(EntityRemoveEvent.Cause.HIT); -+ return; -+ } -+ // CraftBukkit end - if (this.random.nextFloat() < 0.05F && worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { - Endermite entityendermite = (Endermite) EntityType.ENDERMITE.create(worldserver, EntitySpawnReason.TRIGGERED); - - if (entityendermite != null) { - entityendermite.moveTo(entity.getX(), entity.getY(), entity.getZ(), entity.getYRot(), entity.getXRot()); -- worldserver.addFreshEntity(entityendermite); -+ worldserver.addFreshEntity(entityendermite, CreatureSpawnEvent.SpawnReason.ENDER_PEARL); - } - } - -@@ -153,12 +165,12 @@ - entity.setPortalCooldown(); - } - -- ServerPlayer entityplayer1 = entityplayer.teleport(new TeleportTransition(worldserver, vec3d, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.ROTATION, Relative.DELTA), TeleportTransition.DO_NOTHING)); -+ // EntityPlayer entityplayer1 = entityplayer.teleport(new TeleportTransition(worldserver, vec3d, Vec3D.ZERO, 0.0F, 0.0F, Relative.union(Relative.ROTATION, Relative.DELTA), TeleportTransition.DO_NOTHING)); // CraftBukkit - moved up - - if (entityplayer1 != null) { - entityplayer1.resetFallDistance(); - entityplayer1.resetCurrentImpulseContext(); -- entityplayer1.hurtServer(entityplayer.serverLevel(), this.damageSources().enderPearl(), 5.0F); -+ entityplayer1.hurtServer(entityplayer.serverLevel(), this.damageSources().enderPearl().customEventDamager(this), 5.0F); // CraftBukkit // Paper - fix DamageSource API - } - - this.playSound(worldserver, vec3d); -@@ -173,11 +185,11 @@ - this.playSound(worldserver, vec3d); - } - -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause - return; - } - -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause - return; - } - } -@@ -210,7 +222,7 @@ - entity = this.getOwner(); - if (entity instanceof ServerPlayer entityplayer) { - if (!entity.isAlive() && entityplayer.serverLevel().getGameRules().getBoolean(GameRules.RULE_ENDER_PEARLS_VANISH_ON_DEATH)) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - break label30; - } - } -@@ -240,7 +252,7 @@ - Entity entity = super.teleport(teleportTarget); - - if (entity != null) { -- entity.placePortalTicket(BlockPos.containing(entity.position())); -+ if (!this.level().paperConfig().misc.legacyEnderPearlBehavior) entity.placePortalTicket(BlockPos.containing(entity.position())); // Paper - Allow using old ender pearl behavior - } - - return entity; -@@ -248,7 +260,7 @@ - - @Override - public boolean canTeleport(Level from, Level to) { -- if (from.dimension() == Level.END && to.dimension() == Level.OVERWORLD) { -+ if (from.getTypeKey() == LevelStem.END && to.getTypeKey() == LevelStem.OVERWORLD) { // CraftBukkit - Entity entity = this.getOwner(); - - if (entity instanceof ServerPlayer) { diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java.patch deleted file mode 100644 index 40cd201036..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java.patch +++ /dev/null @@ -1,36 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java -+++ b/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java -@@ -9,6 +9,9 @@ - import net.minecraft.world.item.Items; - import net.minecraft.world.level.Level; - import net.minecraft.world.phys.HitResult; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class ThrownExperienceBottle extends ThrowableItemProjectile { - -@@ -38,11 +41,20 @@ - protected void onHit(HitResult hitResult) { - super.onHit(hitResult); - if (this.level() instanceof ServerLevel) { -- this.level().levelEvent(2002, this.blockPosition(), -13083194); -+ // CraftBukkit - moved to after event -+ // this.level().levelEvent(2002, this.blockPosition(), -13083194); - int i = 3 + this.level().random.nextInt(5) + this.level().random.nextInt(5); - -- ExperienceOrb.award((ServerLevel) this.level(), this.position(), i); -- this.discard(); -+ // CraftBukkit start -+ org.bukkit.event.entity.ExpBottleEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExpBottleEvent(this, hitResult, i); -+ i = event.getExperience(); -+ if (event.getShowEffect()) { -+ this.level().levelEvent(2002, this.blockPosition(), -13083194); -+ } -+ // CraftBukkit end -+ -+ ExperienceOrb.award((ServerLevel) this.level(), this.position(), i, org.bukkit.entity.ExperienceOrb.SpawnReason.EXP_BOTTLE, this.getOwner(), this); // Paper -+ this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause - } - - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrownPotion.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrownPotion.java.patch deleted file mode 100644 index babee054f3..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrownPotion.java.patch +++ /dev/null @@ -1,322 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/ThrownPotion.java -+++ b/net/minecraft/world/entity/projectile/ThrownPotion.java -@@ -10,6 +10,7 @@ - import net.minecraft.core.Holder; - import net.minecraft.core.component.DataComponents; - import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; - import net.minecraft.tags.BlockTags; - import net.minecraft.world.damagesource.DamageSource; - import net.minecraft.world.effect.MobEffect; -@@ -17,7 +18,6 @@ - import net.minecraft.world.entity.AreaEffectCloud; - import net.minecraft.world.entity.Entity; - import net.minecraft.world.entity.EntityType; --import net.minecraft.world.entity.LivingEntity; - import net.minecraft.world.entity.animal.axolotl.Axolotl; - import net.minecraft.world.entity.player.Player; - import net.minecraft.world.item.Item; -@@ -28,18 +28,28 @@ - import net.minecraft.world.item.alchemy.Potions; - import net.minecraft.world.level.Level; - import net.minecraft.world.level.block.AbstractCandleBlock; -+// CraftBukkit start -+import java.util.HashMap; -+import java.util.Map; -+import net.minecraft.world.effect.MobEffects; -+import net.minecraft.world.level.block.Blocks; - import net.minecraft.world.level.block.CampfireBlock; - import net.minecraft.world.level.block.state.BlockState; - import net.minecraft.world.phys.AABB; - import net.minecraft.world.phys.BlockHitResult; - import net.minecraft.world.phys.EntityHitResult; - import net.minecraft.world.phys.HitResult; -+import org.bukkit.craftbukkit.entity.CraftLivingEntity; -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+import org.bukkit.entity.LivingEntity; -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class ThrownPotion extends ThrowableItemProjectile { - - public static final double SPLASH_RANGE = 4.0D; - private static final double SPLASH_RANGE_SQ = 16.0D; -- public static final Predicate WATER_SENSITIVE_OR_ON_FIRE = (entityliving) -> { -+ public static final Predicate WATER_SENSITIVE_OR_ON_FIRE = (entityliving) -> { - return entityliving.isSensitiveToWater() || entityliving.isOnFire(); - }; - -@@ -47,7 +57,7 @@ - super(type, world); - } - -- public ThrownPotion(Level world, LivingEntity owner, ItemStack stack) { -+ public ThrownPotion(Level world, net.minecraft.world.entity.LivingEntity owner, ItemStack stack) { - super(EntityType.POTION, owner, world, stack); - } - -@@ -93,70 +103,96 @@ - @Override - protected void onHit(HitResult hitResult) { - super.onHit(hitResult); -+ // Paper start - More projectile API -+ this.splash(hitResult); -+ } -+ public void splash(@Nullable HitResult hitResult) { -+ // Paper end - More projectile API - Level world = this.level(); -- - if (world instanceof ServerLevel worldserver) { - ItemStack itemstack = this.getItem(); - PotionContents potioncontents = (PotionContents) itemstack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); - -+ boolean showParticles = true; // Paper - Fix potions splash events - if (potioncontents.is(Potions.WATER)) { -- this.applyWater(worldserver); -- } else if (potioncontents.hasEffects()) { -+ showParticles = this.applyWater(worldserver, hitResult); // Paper - Fix potions splash events -+ } else if (true || potioncontents.hasEffects()) { // CraftBukkit - Call event even if no effects to apply - if (this.isLingering()) { -- this.makeAreaOfEffectCloud(potioncontents); -+ showParticles = this.makeAreaOfEffectCloud(potioncontents, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper - } else { -- this.applySplash(worldserver, potioncontents.getAllEffects(), hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null); -+ showParticles = this.applySplash(worldserver, potioncontents.getAllEffects(), hitResult != null && hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper - More projectile API - } - } - -+ if (showParticles) { // Paper - Fix potions splash events - int i = potioncontents.potion().isPresent() && ((Potion) ((Holder) potioncontents.potion().get()).value()).hasInstantEffects() ? 2007 : 2002; - - worldserver.levelEvent(i, this.blockPosition(), potioncontents.getColor()); -- this.discard(); -+ } // Paper - Fix potions splash events -+ this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause - } - } - -- private void applyWater(ServerLevel world) { -+ private static final Predicate APPLY_WATER_GET_ENTITIES_PREDICATE = ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE.or(Axolotl.class::isInstance); // Paper - Fix potions splash events -+ private boolean applyWater(ServerLevel world, @Nullable HitResult hitResult) { // Paper - Fix potions splash events - AABB axisalignedbb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D); -- List list = this.level().getEntitiesOfClass(LivingEntity.class, axisalignedbb, ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE); -+ // Paper start - Fix potions splash events -+ List list = this.level().getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb, ThrownPotion.APPLY_WATER_GET_ENTITIES_PREDICATE); -+ Map affected = new HashMap<>(); -+ java.util.Set rehydrate = new java.util.HashSet<>(); -+ java.util.Set extinguish = new java.util.HashSet<>(); - Iterator iterator = list.iterator(); - - while (iterator.hasNext()) { -- LivingEntity entityliving = (LivingEntity) iterator.next(); -+ net.minecraft.world.entity.LivingEntity entityliving = (net.minecraft.world.entity.LivingEntity) iterator.next(); -+ if (entityliving instanceof Axolotl axolotl) { -+ rehydrate.add(((org.bukkit.entity.Axolotl) axolotl.getBukkitEntity())); -+ } - double d0 = this.distanceToSqr((Entity) entityliving); - - if (d0 < 16.0D) { - if (entityliving.isSensitiveToWater()) { -- entityliving.hurtServer(world, this.damageSources().indirectMagic(this, this.getOwner()), 1.0F); -+ affected.put(entityliving.getBukkitLivingEntity(), 1.0); - } - - if (entityliving.isOnFire() && entityliving.isAlive()) { -- entityliving.extinguishFire(); -+ extinguish.add(entityliving.getBukkitLivingEntity()); - } - } - } - -- List list1 = this.level().getEntitiesOfClass(Axolotl.class, axisalignedbb); -- Iterator iterator1 = list1.iterator(); -- -- while (iterator1.hasNext()) { -- Axolotl axolotl = (Axolotl) iterator1.next(); -- -- axolotl.rehydrate(); -+ io.papermc.paper.event.entity.WaterBottleSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callWaterBottleSplashEvent( -+ this, hitResult, affected, rehydrate, extinguish -+ ); -+ if (!event.isCancelled()) { -+ for (LivingEntity affectedEntity : event.getToDamage()) { -+ ((CraftLivingEntity) affectedEntity).getHandle().hurtServer(world, this.damageSources().indirectMagic(this, this.getOwner()), 1.0F); -+ } -+ for (LivingEntity toExtinguish : event.getToExtinguish()) { -+ ((CraftLivingEntity) toExtinguish).getHandle().extinguishFire(); -+ } -+ for (LivingEntity toRehydrate : event.getToRehydrate()) { -+ if (((CraftLivingEntity) toRehydrate).getHandle() instanceof Axolotl axolotl) { -+ axolotl.rehydrate(); -+ } -+ } -+ // Paper end - Fix potions splash events - } -+ return !event.isCancelled(); // Paper - Fix potions splash events - - } - -- private void applySplash(ServerLevel world, Iterable effects, @Nullable Entity entity) { -+ private boolean applySplash(ServerLevel worldserver, Iterable iterable, @Nullable Entity entity, @Nullable HitResult position) { // CraftBukkit - Pass MovingObjectPosition // Paper - Fix potions splash events & More projectile API - AABB axisalignedbb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D); -- List list = world.getEntitiesOfClass(LivingEntity.class, axisalignedbb); -+ List list = worldserver.getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb); -+ Map affected = new HashMap(); // CraftBukkit - - if (!list.isEmpty()) { - Entity entity1 = this.getEffectSource(); - Iterator iterator = list.iterator(); - - while (iterator.hasNext()) { -- LivingEntity entityliving = (LivingEntity) iterator.next(); -+ net.minecraft.world.entity.LivingEntity entityliving = (net.minecraft.world.entity.LivingEntity) iterator.next(); - - if (entityliving.isAffectedByPotions()) { - double d0 = this.distanceToSqr((Entity) entityliving); -@@ -164,43 +200,71 @@ - if (d0 < 16.0D) { - double d1; - -+ // Paper - diff on change, used when calling the splash event for water splash potions - if (entityliving == entity) { - d1 = 1.0D; - } else { - d1 = 1.0D - Math.sqrt(d0) / 4.0D; - } - -- Iterator iterator1 = effects.iterator(); -+ // CraftBukkit start -+ affected.put((LivingEntity) entityliving.getBukkitEntity(), d1); -+ } -+ } -+ } -+ } - -- while (iterator1.hasNext()) { -- MobEffectInstance mobeffect = (MobEffectInstance) iterator1.next(); -- Holder holder = mobeffect.getEffect(); -+ org.bukkit.event.entity.PotionSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPotionSplashEvent(this, position, affected); -+ if (!event.isCancelled() && list != null && !list.isEmpty()) { // do not process effects if there are no effects to process -+ Entity entity1 = this.getEffectSource(); -+ for (LivingEntity victim : event.getAffectedEntities()) { -+ if (!(victim instanceof CraftLivingEntity)) { -+ continue; -+ } - -- if (((MobEffect) holder.value()).isInstantenous()) { -- ((MobEffect) holder.value()).applyInstantenousEffect(world, this, this.getOwner(), entityliving, mobeffect.getAmplifier(), d1); -- } else { -- int i = mobeffect.mapDuration((j) -> { -- return (int) (d1 * (double) j + 0.5D); -- }); -- MobEffectInstance mobeffect1 = new MobEffectInstance(holder, i, mobeffect.getAmplifier(), mobeffect.isAmbient(), mobeffect.isVisible()); -+ net.minecraft.world.entity.LivingEntity entityliving = ((CraftLivingEntity) victim).getHandle(); -+ double d1 = event.getIntensity(victim); -+ // CraftBukkit end - -- if (!mobeffect1.endsWithin(20)) { -- entityliving.addEffect(mobeffect1, entity1); -- } -- } -+ Iterator iterator1 = iterable.iterator(); -+ -+ while (iterator1.hasNext()) { -+ MobEffectInstance mobeffect = (MobEffectInstance) iterator1.next(); -+ Holder holder = mobeffect.getEffect(); -+ // CraftBukkit start - Abide by PVP settings - for players only! -+ if (!this.level().pvpMode && this.getOwner() instanceof ServerPlayer && entityliving instanceof ServerPlayer && entityliving != this.getOwner()) { -+ MobEffect mobeffectlist = (MobEffect) holder.value(); -+ if (mobeffectlist == MobEffects.MOVEMENT_SLOWDOWN || mobeffectlist == MobEffects.DIG_SLOWDOWN || mobeffectlist == MobEffects.HARM || mobeffectlist == MobEffects.BLINDNESS -+ || mobeffectlist == MobEffects.HUNGER || mobeffectlist == MobEffects.WEAKNESS || mobeffectlist == MobEffects.POISON) { -+ continue; - } - } -+ // CraftBukkit end -+ -+ if (((MobEffect) holder.value()).isInstantenous()) { -+ ((MobEffect) holder.value()).applyInstantenousEffect(worldserver, this, this.getOwner(), entityliving, mobeffect.getAmplifier(), d1); -+ } else { -+ int i = mobeffect.mapDuration((j) -> { -+ return (int) (d1 * (double) j + 0.5D); -+ }); -+ MobEffectInstance mobeffect1 = new MobEffectInstance(holder, i, mobeffect.getAmplifier(), mobeffect.isAmbient(), mobeffect.isVisible()); -+ -+ if (!mobeffect1.endsWithin(20)) { -+ entityliving.addEffect(mobeffect1, entity1, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.POTION_SPLASH); // CraftBukkit -+ } -+ } - } - } - } -+ return !event.isCancelled(); // Paper - Fix potions splash events - - } - -- private void makeAreaOfEffectCloud(PotionContents potion) { -+ private boolean makeAreaOfEffectCloud(PotionContents potioncontents, @Nullable HitResult position) { // CraftBukkit - Pass MovingObjectPosition // Paper - More projectile API - AreaEffectCloud entityareaeffectcloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ()); - Entity entity = this.getOwner(); - -- if (entity instanceof LivingEntity entityliving) { -+ if (entity instanceof net.minecraft.world.entity.LivingEntity entityliving) { - entityareaeffectcloud.setOwner(entityliving); - } - -@@ -208,8 +272,17 @@ - entityareaeffectcloud.setRadiusOnUse(-0.5F); - entityareaeffectcloud.setWaitTime(10); - entityareaeffectcloud.setRadiusPerTick(-entityareaeffectcloud.getRadius() / (float) entityareaeffectcloud.getDuration()); -- entityareaeffectcloud.setPotionContents(potion); -- this.level().addFreshEntity(entityareaeffectcloud); -+ entityareaeffectcloud.setPotionContents(potioncontents); -+ boolean noEffects = potioncontents.hasEffects(); // Paper - Fix potions splash events -+ // CraftBukkit start -+ org.bukkit.event.entity.LingeringPotionSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callLingeringPotionSplashEvent(this, position, entityareaeffectcloud); -+ if (!(event.isCancelled() || entityareaeffectcloud.isRemoved() || (!event.allowsEmptyCreation() && (noEffects && !entityareaeffectcloud.potionContents.hasEffects())))) { // Paper - don't spawn area effect cloud if the effects were empty and not changed during the event handling -+ this.level().addFreshEntity(entityareaeffectcloud); -+ } else { -+ entityareaeffectcloud.discard(null); // CraftBukkit - add Bukkit remove cause -+ } -+ // CraftBukkit end -+ return !event.isCancelled(); // Paper - Fix potions splash events - } - - public boolean isLingering() { -@@ -220,19 +293,31 @@ - BlockState iblockdata = this.level().getBlockState(pos); - - if (iblockdata.is(BlockTags.FIRE)) { -- this.level().destroyBlock(pos, false, this); -+ // CraftBukkit start -+ if (CraftEventFactory.callEntityChangeBlockEvent(this, pos, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state -+ this.level().destroyBlock(pos, false, this); -+ } -+ // CraftBukkit end - } else if (AbstractCandleBlock.isLit(iblockdata)) { -- AbstractCandleBlock.extinguish((Player) null, iblockdata, this.level(), pos); -+ // CraftBukkit start -+ if (CraftEventFactory.callEntityChangeBlockEvent(this, pos, iblockdata.setValue(AbstractCandleBlock.LIT, false))) { -+ AbstractCandleBlock.extinguish((Player) null, iblockdata, this.level(), pos); -+ } -+ // CraftBukkit end - } else if (CampfireBlock.isLitCampfire(iblockdata)) { -- this.level().levelEvent((Player) null, 1009, pos, 0); -- CampfireBlock.dowse(this.getOwner(), this.level(), pos, iblockdata); -- this.level().setBlockAndUpdate(pos, (BlockState) iblockdata.setValue(CampfireBlock.LIT, false)); -+ // CraftBukkit start -+ if (CraftEventFactory.callEntityChangeBlockEvent(this, pos, iblockdata.setValue(CampfireBlock.LIT, false))) { -+ this.level().levelEvent((Player) null, 1009, pos, 0); -+ CampfireBlock.dowse(this.getOwner(), this.level(), pos, iblockdata); -+ this.level().setBlockAndUpdate(pos, (BlockState) iblockdata.setValue(CampfireBlock.LIT, false)); -+ } -+ // CraftBukkit end - } - - } - - @Override -- public DoubleDoubleImmutablePair calculateHorizontalHurtKnockbackDirection(LivingEntity target, DamageSource source) { -+ public DoubleDoubleImmutablePair calculateHorizontalHurtKnockbackDirection(net.minecraft.world.entity.LivingEntity target, DamageSource source) { - double d0 = target.position().x - this.position().x; - double d1 = target.position().z - this.position().z; - diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrownTrident.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrownTrident.java.patch deleted file mode 100644 index fff7300b9e..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/ThrownTrident.java.patch +++ /dev/null @@ -1,86 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/ThrownTrident.java -+++ b/net/minecraft/world/entity/projectile/ThrownTrident.java -@@ -23,6 +23,9 @@ - import net.minecraft.world.phys.BlockHitResult; - import net.minecraft.world.phys.EntityHitResult; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class ThrownTrident extends AbstractArrow { - -@@ -34,16 +37,19 @@ - - public ThrownTrident(EntityType type, Level world) { - super(type, world); -+ this.setBaseDamage(net.minecraft.world.item.TridentItem.BASE_DAMAGE); // Paper - Allow trident custom damage - } - - public ThrownTrident(Level world, LivingEntity owner, ItemStack stack) { - super(EntityType.TRIDENT, owner, world, stack, (ItemStack) null); -+ this.setBaseDamage(net.minecraft.world.item.TridentItem.BASE_DAMAGE); // Paper - Allow trident custom damage - this.entityData.set(ThrownTrident.ID_LOYALTY, this.getLoyaltyFromItem(stack)); - this.entityData.set(ThrownTrident.ID_FOIL, stack.hasFoil()); - } - - public ThrownTrident(Level world, double x, double y, double z, ItemStack stack) { - super(EntityType.TRIDENT, x, y, z, world, stack, stack); -+ this.setBaseDamage(net.minecraft.world.item.TridentItem.BASE_DAMAGE); // Paper - Allow trident custom damage - this.entityData.set(ThrownTrident.ID_LOYALTY, this.getLoyaltyFromItem(stack)); - this.entityData.set(ThrownTrident.ID_FOIL, stack.hasFoil()); - } -@@ -76,10 +82,10 @@ - } - } - -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause - } else { - if (!(entity instanceof Player) && this.position().distanceTo(entity.getEyePosition()) < (double) entity.getBbWidth() + 1.0D) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - return; - } - -@@ -109,8 +115,22 @@ - - public boolean isFoil() { - return (Boolean) this.entityData.get(ThrownTrident.ID_FOIL); -+ } -+ -+ // Paper start -+ public void setFoil(boolean foil) { -+ this.entityData.set(ThrownTrident.ID_FOIL, foil); - } - -+ public int getLoyalty() { -+ return this.entityData.get(ThrownTrident.ID_LOYALTY); -+ } -+ -+ public void setLoyalty(byte loyalty) { -+ this.entityData.set(ThrownTrident.ID_LOYALTY, loyalty); -+ } -+ // Paper end -+ - @Nullable - @Override - protected EntityHitResult findHitEntity(Vec3 currentPosition, Vec3 nextPosition) { -@@ -120,7 +140,7 @@ - @Override - protected void onHitEntity(EntityHitResult entityHitResult) { - Entity entity = entityHitResult.getEntity(); -- float f = 8.0F; -+ float f = (float) this.getBaseDamage(); // Paper - Allow trident custom damage - Entity entity1 = this.getOwner(); - DamageSource damagesource = this.damageSources().trident(this, (Entity) (entity1 == null ? this : entity1)); - Level world = this.level(); -@@ -137,7 +157,7 @@ - - world = this.level(); - if (world instanceof ServerLevel) { -- worldserver = (ServerLevel) world; -+ ServerLevel worldserver = (ServerLevel) world; // CraftBukkit - decompile error - EnchantmentHelper.doPostAttackEffectsWithItemSourceOnBreak(worldserver, entity, damagesource, this.getWeaponItem(), (item) -> { - this.kill(worldserver); - }); diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/WitherSkull.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/WitherSkull.java.patch deleted file mode 100644 index 96234163f1..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/projectile/WitherSkull.java.patch +++ /dev/null @@ -1,55 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/WitherSkull.java -+++ b/net/minecraft/world/entity/projectile/WitherSkull.java -@@ -23,6 +23,10 @@ - import net.minecraft.world.phys.EntityHitResult; - import net.minecraft.world.phys.HitResult; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityRemoveEvent; -+import org.bukkit.event.entity.ExplosionPrimeEvent; -+// CraftBukkit end - - public class WitherSkull extends AbstractHurtingProjectile { - -@@ -69,11 +73,11 @@ - if (entity.isAlive()) { - EnchantmentHelper.doPostAttackEffects(worldserver, entity, damagesource); - } else { -- entityliving.heal(5.0F); -+ entityliving.heal(5.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.WITHER); // CraftBukkit - } - } - } else { -- flag = entity.hurtServer(worldserver, this.damageSources().magic(), 5.0F); -+ flag = entity.hurtServer(worldserver, this.damageSources().magic().customEventDamager(this), 5.0F); // Paper - Fire EntityDamageByEntityEvent for unowned wither skulls // Paper - fix DamageSource API - } - - if (flag && entity instanceof LivingEntity entityliving) { -@@ -86,7 +90,7 @@ - } - - if (b0 > 0) { -- entityliving.addEffect(new MobEffectInstance(MobEffects.WITHER, 20 * b0, 1), this.getEffectSource()); -+ entityliving.addEffect(new MobEffectInstance(MobEffects.WITHER, 20 * b0, 1), this.getEffectSource(), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit - } - } - -@@ -97,8 +101,16 @@ - protected void onHit(HitResult hitResult) { - super.onHit(hitResult); - if (!this.level().isClientSide) { -- this.level().explode(this, this.getX(), this.getY(), this.getZ(), 1.0F, false, Level.ExplosionInteraction.MOB); -- this.discard(); -+ // CraftBukkit start -+ // this.level().explode(this, this.getX(), this.getY(), this.getZ(), 1.0F, false, World.a.MOB); -+ ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 1.0F, false); -+ this.level().getCraftServer().getPluginManager().callEvent(event); -+ -+ if (!event.isCancelled()) { -+ this.level().explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); -+ } -+ // CraftBukkit end -+ this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause - } - - }