diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch new file mode 100644 index 0000000000..b4eaea2841 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch @@ -0,0 +1,123 @@ +--- a/net/minecraft/world/entity/boss/wither/WitherBoss.java ++++ b/net/minecraft/world/entity/boss/wither/WitherBoss.java +@@ -77,6 +_,12 @@ + && entity.attackable(); + private static final TargetingConditions TARGETING_CONDITIONS = TargetingConditions.forCombat().range(20.0).selector(LIVING_ENTITY_SELECTOR); + ++ // Paper start ++ private boolean canPortal = false; ++ ++ public void setCanTravelThroughPortals(boolean canPortal) { this.canPortal = canPortal; } ++ // Paper end ++ + public WitherBoss(EntityType entityType, Level level) { + super(entityType, level); + this.moveControl = new FlyingMoveControl(this, 10, false); +@@ -260,15 +_,40 @@ + int i = this.getInvulnerableTicks() - 1; + this.bossEvent.setProgress(1.0F - i / 220.0F); + if (i <= 0) { +- level.explode(this, this.getX(), this.getEyeY(), this.getZ(), 7.0F, false, Level.ExplosionInteraction.MOB); ++ // CraftBukkit start ++ org.bukkit.event.entity.ExplosionPrimeEvent event = new org.bukkit.event.entity.ExplosionPrimeEvent(this.getBukkitEntity(), 7.0F, false); ++ level.getCraftServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ level.explode(this, this.getX(), this.getEyeY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); ++ } ++ // CraftBukkit end + if (!this.isSilent()) { +- level.globalLevelEvent(1023, this.blockPosition(), 0); ++ // CraftBukkit start - Use relative location for far away sounds ++ // level.globalLevelEvent(1023, this.blockPosition(), 0); ++ int viewDistance = level.getCraftServer().getViewDistance() * 16; ++ for (ServerPlayer player : level.getPlayersForGlobalSoundGamerule()) { // Paper - respect global sound events gamerule ++ double deltaX = this.getX() - player.getX(); ++ double deltaZ = this.getZ() - player.getZ(); ++ double distanceSquared = deltaX * deltaX + deltaZ * deltaZ; ++ final double soundRadiusSquared = level.getGlobalSoundRangeSquared(config -> config.witherSpawnSoundRadius); // Paper - respect global sound events gamerule ++ if (!level.getGameRules().getBoolean(GameRules.RULE_GLOBAL_SOUND_EVENTS) && distanceSquared > soundRadiusSquared) continue; // Spigot // Paper - respect global sound events gamerule ++ if (distanceSquared > viewDistance * viewDistance) { ++ double deltaLength = Math.sqrt(distanceSquared); ++ double relativeX = player.getX() + (deltaX / deltaLength) * viewDistance; ++ double relativeZ = player.getZ() + (deltaZ / deltaLength) * viewDistance; ++ player.connection.send(new ClientboundLevelEventPacket(1023, new BlockPos((int) relativeX, (int) this.getY(), (int) relativeZ), 0, true)); ++ } else { ++ player.connection.send(new ClientboundLevelEventPacket(1023, this.blockPosition(), 0, true)); ++ } ++ } ++ // CraftBukkit end + } + } + + this.setInvulnerableTicks(i); + if (this.tickCount % 10 == 0) { +- this.heal(10.0F); ++ this.heal(10.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.WITHER_SPAWN); // CraftBukkit + } + } else { + super.customServerAiStep(level); +@@ -305,6 +_,7 @@ + ); + if (!nearbyEntities.isEmpty()) { + LivingEntity livingEntity1 = nearbyEntities.get(this.random.nextInt(nearbyEntities.size())); ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(this, livingEntity1, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY).isCancelled()) continue; // CraftBukkit + this.setAlternativeTarget(ix, livingEntity1.getId()); + } + } +@@ -334,6 +_,11 @@ + )) { + BlockState blockState = level.getBlockState(blockPos); + if (canDestroy(blockState)) { ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockPos, blockState.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state ++ continue; ++ } ++ // CraftBukkit end + flag = level.destroyBlock(blockPos, true, this) || flag; + } + } +@@ -345,7 +_,7 @@ + } + + if (this.tickCount % 20 == 0) { +- this.heal(1.0F); ++ this.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit + } + + this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth()); +@@ -483,16 +_,16 @@ + @Override + protected void dropCustomDeathLoot(ServerLevel level, DamageSource damageSource, boolean recentlyHit) { + super.dropCustomDeathLoot(level, damageSource, recentlyHit); +- ItemEntity itemEntity = this.spawnAtLocation(level, Items.NETHER_STAR); ++ ItemEntity itemEntity = this.spawnAtLocation(level, new net.minecraft.world.item.ItemStack(Items.NETHER_STAR), 0, ItemEntity::setExtendedLifetime); // Paper - Restore vanilla drops behavior; spawnAtLocation returns null so modify the item entity with a consumer + if (itemEntity != null) { +- itemEntity.setExtendedLifetime(); ++ itemEntity.setExtendedLifetime(); // Paper - diff on change + } + } + + @Override + public void checkDespawn() { + if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause + } else { + this.noActionTime = 0; + } +@@ -547,12 +_,12 @@ + + @Override + public boolean canUsePortal(boolean allowPassengers) { +- return false; ++ return this.canPortal; // Paper + } + + @Override + public boolean canBeAffected(MobEffectInstance potioneffect) { +- return !potioneffect.is(MobEffects.WITHER) && super.canBeAffected(potioneffect); ++ return (!potioneffect.is(MobEffects.WITHER) || !this.level().paperConfig().entities.mobEffects.immuneToWitherEffect.wither) && super.canBeAffected(potioneffect); + } + + class WitherDoNothingGoal extends Goal { diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch deleted file mode 100644 index 67144bc046..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch +++ /dev/null @@ -1,165 +0,0 @@ ---- a/net/minecraft/world/entity/boss/wither/WitherBoss.java -+++ b/net/minecraft/world/entity/boss/wither/WitherBoss.java -@@ -10,14 +10,10 @@ - import net.minecraft.core.particles.ParticleTypes; - import net.minecraft.nbt.CompoundTag; - import net.minecraft.network.chat.Component; -+import net.minecraft.network.protocol.game.ClientboundLevelEventPacket; - import net.minecraft.network.syncher.EntityDataAccessor; - import net.minecraft.network.syncher.EntityDataSerializers; - import net.minecraft.network.syncher.SynchedEntityData; --import net.minecraft.server.level.ServerBossEvent; --import net.minecraft.server.level.ServerLevel; --import net.minecraft.server.level.ServerPlayer; --import net.minecraft.sounds.SoundEvent; --import net.minecraft.sounds.SoundEvents; - import net.minecraft.tags.BlockTags; - import net.minecraft.tags.DamageTypeTags; - import net.minecraft.tags.EntityTypeTags; -@@ -54,8 +50,21 @@ - import net.minecraft.world.level.GameRules; - import net.minecraft.world.level.ItemLike; - import net.minecraft.world.level.Level; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.server.level.ServerBossEvent; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.sounds.SoundEvent; -+import net.minecraft.sounds.SoundEvents; -+import net.minecraft.world.level.block.Blocks; - import net.minecraft.world.level.block.state.BlockState; - import net.minecraft.world.phys.Vec3; -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+import org.bukkit.event.entity.EntityRegainHealthEvent; -+import org.bukkit.event.entity.EntityRemoveEvent; -+import org.bukkit.event.entity.EntityTargetEvent; -+import org.bukkit.event.entity.ExplosionPrimeEvent; -+// CraftBukkit end - - public class WitherBoss extends Monster implements RangedAttackMob { - -@@ -77,7 +86,12 @@ - return !entityliving.getType().is(EntityTypeTags.WITHER_FRIENDS) && entityliving.attackable(); - }; - private static final TargetingConditions TARGETING_CONDITIONS = TargetingConditions.forCombat().range(20.0D).selector(WitherBoss.LIVING_ENTITY_SELECTOR); -+ // Paper start -+ private boolean canPortal = false; - -+ public void setCanTravelThroughPortals(boolean canPortal) { this.canPortal = canPortal; } -+ // Paper end -+ - public WitherBoss(EntityType type, Level world) { - super(type, world); - this.bossEvent = (ServerBossEvent) (new ServerBossEvent(this.getDisplayName(), BossEvent.BossBarColor.PURPLE, BossEvent.BossBarOverlay.PROGRESS)).setDarkenScreen(true); -@@ -252,15 +266,42 @@ - i = this.getInvulnerableTicks() - 1; - this.bossEvent.setProgress(1.0F - (float) i / 220.0F); - if (i <= 0) { -- world.explode(this, this.getX(), this.getEyeY(), this.getZ(), 7.0F, false, Level.ExplosionInteraction.MOB); -+ // CraftBukkit start -+ // worldserver.explode(this, this.getX(), this.getEyeY(), this.getZ(), 7.0F, false, World.a.MOB); -+ ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 7.0F, false); -+ world.getCraftServer().getPluginManager().callEvent(event); -+ -+ if (!event.isCancelled()) { -+ world.explode(this, this.getX(), this.getEyeY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); -+ } -+ // CraftBukkit end -+ - if (!this.isSilent()) { -- world.globalLevelEvent(1023, this.blockPosition(), 0); -+ // CraftBukkit start - Use relative location for far away sounds -+ // worldserver.globalLevelEvent(1023, new BlockPosition(this), 0); -+ int viewDistance = world.getCraftServer().getViewDistance() * 16; -+ for (ServerPlayer player : world.getPlayersForGlobalSoundGamerule()) { // Paper - respect global sound events gamerule -+ double deltaX = this.getX() - player.getX(); -+ double deltaZ = this.getZ() - player.getZ(); -+ double distanceSquared = deltaX * deltaX + deltaZ * deltaZ; -+ final double soundRadiusSquared = world.getGlobalSoundRangeSquared(config -> config.witherSpawnSoundRadius); // Paper - respect global sound events gamerule -+ if ( !world.getGameRules().getBoolean(GameRules.RULE_GLOBAL_SOUND_EVENTS) && distanceSquared > soundRadiusSquared ) continue; // Spigot // Paper - respect global sound events gamerule -+ if (distanceSquared > viewDistance * viewDistance) { -+ double deltaLength = Math.sqrt(distanceSquared); -+ double relativeX = player.getX() + (deltaX / deltaLength) * viewDistance; -+ double relativeZ = player.getZ() + (deltaZ / deltaLength) * viewDistance; -+ player.connection.send(new ClientboundLevelEventPacket(1023, new BlockPos((int) relativeX, (int) this.getY(), (int) relativeZ), 0, true)); -+ } else { -+ player.connection.send(new ClientboundLevelEventPacket(1023, this.blockPosition(), 0, true)); -+ } -+ } -+ // CraftBukkit end - } - } - - this.setInvulnerableTicks(i); - if (this.tickCount % 10 == 0) { -- this.heal(10.0F); -+ this.heal(10.0F, EntityRegainHealthEvent.RegainReason.WITHER_SPAWN); // CraftBukkit - } - - } else { -@@ -305,6 +346,7 @@ - if (!list.isEmpty()) { - LivingEntity entityliving1 = (LivingEntity) list.get(this.random.nextInt(list.size())); - -+ if (CraftEventFactory.callEntityTargetLivingEvent(this, entityliving1, EntityTargetEvent.TargetReason.CLOSEST_ENTITY).isCancelled()) continue; // CraftBukkit - this.setAlternativeTarget(i, entityliving1.getId()); - } - } -@@ -331,6 +373,11 @@ - BlockState iblockdata = world.getBlockState(blockposition); - - if (WitherBoss.canDestroy(iblockdata)) { -+ // CraftBukkit start -+ if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state -+ continue; -+ } -+ // CraftBukkit end - flag = world.destroyBlock(blockposition, true, this) || flag; - } - } -@@ -342,7 +389,7 @@ - } - - if (this.tickCount % 20 == 0) { -- this.heal(1.0F); -+ this.heal(1.0F, EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit - } - - this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth()); -@@ -488,10 +535,10 @@ - @Override - protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) { - super.dropCustomDeathLoot(world, source, causedByPlayer); -- ItemEntity entityitem = this.spawnAtLocation(world, (ItemLike) Items.NETHER_STAR); -+ ItemEntity entityitem = this.spawnAtLocation(world, new net.minecraft.world.item.ItemStack(Items.NETHER_STAR), 0, ItemEntity::setExtendedLifetime); // Paper - Restore vanilla drops behavior; spawnAtLocation returns null so modify the item entity with a consumer - - if (entityitem != null) { -- entityitem.setExtendedLifetime(); -+ entityitem.setExtendedLifetime(); // Paper - diff on change - } - - } -@@ -499,7 +546,7 @@ - @Override - public void checkDespawn() { - if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - } else { - this.noActionTime = 0; - } -@@ -549,12 +596,12 @@ - - @Override - public boolean canUsePortal(boolean allowVehicles) { -- return false; -+ return this.canPortal; // Paper - } - - @Override - public boolean canBeAffected(MobEffectInstance effect) { -- return effect.is(MobEffects.WITHER) ? false : super.canBeAffected(effect); -+ return effect.is(MobEffects.WITHER) && this.level().paperConfig().entities.mobEffects.immuneToWitherEffect.wither ? false : super.canBeAffected(effect); // Paper - Add config for mobs immune to default effects - } - - private class WitherDoNothingGoal extends Goal {