geforkt von Mirrors/Paper
Ender dragon
Dieser Commit ist enthalten in:
Ursprung
5c68cc7cef
Commit
1ed5242f38
@ -0,0 +1,79 @@
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
|
||||
@@ -25,6 +_,7 @@
|
||||
);
|
||||
private static final EntityDataAccessor<Boolean> DATA_SHOW_BOTTOM = SynchedEntityData.defineId(EndCrystal.class, EntityDataSerializers.BOOLEAN);
|
||||
public int time;
|
||||
+ public boolean generatedByDragonFight = false; // Paper - Fix invulnerable end crystals
|
||||
|
||||
public EndCrystal(EntityType<? extends EndCrystal> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
@@ -56,9 +_,23 @@
|
||||
if (this.level() instanceof ServerLevel) {
|
||||
BlockPos blockPos = this.blockPosition();
|
||||
if (((ServerLevel)this.level()).getDragonFight() != null && this.level().getBlockState(blockPos).isAir()) {
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level(), blockPos, this).isCancelled()) { // Paper
|
||||
this.level().setBlockAndUpdate(blockPos, BaseFireBlock.getState(this.level(), blockPos));
|
||||
- }
|
||||
- }
|
||||
+ } // Paper
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Paper start - Fix invulnerable end crystals
|
||||
+ if (this.level().paperConfig().unsupportedSettings.fixInvulnerableEndCrystalExploit && this.generatedByDragonFight && this.isInvulnerable()) {
|
||||
+ if (!java.util.Objects.equals(((ServerLevel) this.level()).uuid, this.getOriginWorld())
|
||||
+ || ((ServerLevel) this.level()).getDragonFight() == null
|
||||
+ || ((ServerLevel) this.level()).getDragonFight().respawnStage == null
|
||||
+ || ((ServerLevel) this.level()).getDragonFight().respawnStage.ordinal() > net.minecraft.world.level.dimension.end.DragonRespawnAnimation.SUMMONING_DRAGON.ordinal()) {
|
||||
+ this.setInvulnerable(false);
|
||||
+ this.setBeamTarget(null);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Fix invulnerable end crystals
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,6 +_,7 @@
|
||||
}
|
||||
|
||||
compound.putBoolean("ShowBottom", this.showsBottom());
|
||||
+ if (this.generatedByDragonFight) compound.putBoolean("Paper.GeneratedByDragonFight", this.generatedByDragonFight); // Paper - Fix invulnerable end crystals
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,6 +_,7 @@
|
||||
if (compound.contains("ShowBottom", 1)) {
|
||||
this.setShowBottom(compound.getBoolean("ShowBottom"));
|
||||
}
|
||||
+ if (compound.contains("Paper.GeneratedByDragonFight", 1)) this.generatedByDragonFight = compound.getBoolean("Paper.GeneratedByDragonFight"); // Paper - Fix invulnerable end crystals
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,10 +_,24 @@
|
||||
return false;
|
||||
} else {
|
||||
if (!this.isRemoved()) {
|
||||
- this.remove(Entity.RemovalReason.KILLED);
|
||||
+ // Paper start - All non-living entities need this
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount, false)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (!damageSource.is(DamageTypeTags.IS_EXPLOSION)) {
|
||||
DamageSource damageSource1 = damageSource.getEntity() != null ? this.damageSources().explosion(this, damageSource.getEntity()) : null;
|
||||
- level.explode(this, damageSource1, null, this.getX(), this.getY(), this.getZ(), 6.0F, false, Level.ExplosionInteraction.BLOCK);
|
||||
+ // Paper start
|
||||
+ org.bukkit.event.entity.ExplosionPrimeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExplosionPrimeEvent(this, 6.0F, false);
|
||||
+ if (event.isCancelled()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ this.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.EXPLODE); // Paper - add Bukkit remove cause
|
||||
+ level.explode(this, damageSource1, null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.BLOCK);
|
||||
+ } else {
|
||||
+ this.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // Paper - add Bukkit remove cause
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
this.onDestroyedBy(level, damageSource);
|
@ -0,0 +1,283 @@
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
|
||||
@@ -86,6 +_,10 @@
|
||||
private final Node[] nodes = new Node[24];
|
||||
private final int[] nodeAdjacency = new int[24];
|
||||
private final BinaryHeap openSet = new BinaryHeap();
|
||||
+ // Paper start
|
||||
+ private final net.minecraft.world.level.Explosion explosionSource; // Paper - reusable source for CraftTNTPrimed.getSource()
|
||||
+ @Nullable private BlockPos podium;
|
||||
+ // Paper end
|
||||
|
||||
public EnderDragon(EntityType<? extends EnderDragon> entityType, Level level) {
|
||||
super(EntityType.ENDER_DRAGON, level);
|
||||
@@ -101,6 +_,7 @@
|
||||
this.setHealth(this.getMaxHealth());
|
||||
this.noPhysics = true;
|
||||
this.phaseManager = new EnderDragonPhaseManager(this);
|
||||
+ this.explosionSource = new net.minecraft.world.level.ServerExplosion(level.getMinecraftWorld(), this, null, null, new Vec3(Double.NaN, Double.NaN, Double.NaN), Float.NaN, true, net.minecraft.world.level.Explosion.BlockInteraction.DESTROY); // Paper
|
||||
}
|
||||
|
||||
public void setDragonFight(EndDragonFight dragonFight) {
|
||||
@@ -119,6 +_,19 @@
|
||||
return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0);
|
||||
}
|
||||
|
||||
+ // Paper start - Allow changing the EnderDragon podium
|
||||
+ public BlockPos getPodium() {
|
||||
+ if (this.podium == null) {
|
||||
+ return EndPodiumFeature.getLocation(this.getFightOrigin());
|
||||
+ }
|
||||
+ return this.podium;
|
||||
+ }
|
||||
+
|
||||
+ public void setPodium(@Nullable BlockPos blockPos) {
|
||||
+ this.podium = blockPos;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public boolean isFlapping() {
|
||||
float cos = Mth.cos(this.flapTime * (float) (Math.PI * 2));
|
||||
@@ -210,7 +_,7 @@
|
||||
}
|
||||
|
||||
Vec3 flyTargetLocation = currentPhase.getFlyTargetLocation();
|
||||
- if (flyTargetLocation != null) {
|
||||
+ if (flyTargetLocation != null && currentPhase.getPhase() != EnderDragonPhase.HOVERING) { // Paper - Don't move when hovering
|
||||
double d = flyTargetLocation.x - this.getX();
|
||||
double d1 = flyTargetLocation.y - this.getY();
|
||||
double d2 = flyTargetLocation.z - this.getZ();
|
||||
@@ -369,7 +_,14 @@
|
||||
if (this.nearestCrystal.isRemoved()) {
|
||||
this.nearestCrystal = null;
|
||||
} else if (this.tickCount % 10 == 0 && this.getHealth() < this.getMaxHealth()) {
|
||||
- this.setHealth(this.getHealth() + 1.0F);
|
||||
+ // Paper start
|
||||
+ org.bukkit.event.entity.EntityRegainHealthEvent event = new org.bukkit.event.entity.EntityRegainHealthEvent(this.getBukkitEntity(), 1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.ENDER_CRYSTAL);
|
||||
+ this.level().getCraftServer().getPluginManager().callEvent(event);
|
||||
+
|
||||
+ if (!event.isCancelled()) {
|
||||
+ this.setHealth((float) (this.getHealth() + event.getAmount()));
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,7 +_,7 @@
|
||||
double d2 = entity.getX() - d;
|
||||
double d3 = entity.getZ() - d1;
|
||||
double max = Math.max(d2 * d2 + d3 * d3, 0.1);
|
||||
- entity.push(d2 / max * 4.0, 0.2F, d3 / max * 4.0);
|
||||
+ entity.push(d2 / max * 4.0, 0.2F, d3 / max * 4.0, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent
|
||||
if (!this.phaseManager.getCurrentPhase().isSitting() && livingEntity.getLastHurtByMobTimestamp() < entity.tickCount - 2) {
|
||||
DamageSource damageSource = this.damageSources().mobAttack(this);
|
||||
entity.hurtServer(level, damageSource, 5.0F);
|
||||
@@ -433,6 +_,7 @@
|
||||
int floor5 = Mth.floor(box.maxZ);
|
||||
boolean flag = false;
|
||||
boolean flag1 = false;
|
||||
+ List<org.bukkit.block.Block> destroyedBlocks = new java.util.ArrayList<>(); // Paper - Create a list to hold all the destroyed blocks
|
||||
|
||||
for (int i = floor; i <= floor3; i++) {
|
||||
for (int i1 = floor1; i1 <= floor4; i1++) {
|
||||
@@ -441,7 +_,11 @@
|
||||
BlockState blockState = level.getBlockState(blockPos);
|
||||
if (!blockState.isAir() && !blockState.is(BlockTags.DRAGON_TRANSPARENT)) {
|
||||
if (level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && !blockState.is(BlockTags.DRAGON_IMMUNE)) {
|
||||
- flag1 = level.removeBlock(blockPos, false) || flag1;
|
||||
+ // Paper start - Add blocks to list rather than destroying them
|
||||
+ //flag1 = level.removeBlock(blockPos, false) || flag1;
|
||||
+ flag1 = true;
|
||||
+ destroyedBlocks.add(org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPos));
|
||||
+ // Paper end
|
||||
} else {
|
||||
flag = true;
|
||||
}
|
||||
@@ -450,6 +_,54 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - Set off an EntityExplodeEvent for the dragon exploding all these blocks
|
||||
+ // SPIGOT-4882: don't fire event if nothing hit
|
||||
+ if (!flag1) {
|
||||
+ return flag;
|
||||
+ }
|
||||
+
|
||||
+ org.bukkit.event.entity.EntityExplodeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityExplodeEvent(this, destroyedBlocks, 0F, this.explosionSource.getBlockInteraction());
|
||||
+ if (event.isCancelled()) {
|
||||
+ // This flag literally means 'Dragon hit something hard' (Obsidian, White Stone or Bedrock) and will cause the dragon to slow down.
|
||||
+ // We should consider adding an event extension for it, or perhaps returning true if the event is cancelled.
|
||||
+ return flag;
|
||||
+ } else if (event.getYield() == 0F) {
|
||||
+ // Yield zero ==> no drops
|
||||
+ for (org.bukkit.block.Block block : event.blockList()) {
|
||||
+ this.level().removeBlock(new BlockPos(block.getX(), block.getY(), block.getZ()), false);
|
||||
+ }
|
||||
+ } else {
|
||||
+ for (org.bukkit.block.Block block : event.blockList()) {
|
||||
+ org.bukkit.Material blockId = block.getType();
|
||||
+ if (blockId.isAir()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ org.bukkit.craftbukkit.block.CraftBlock craftBlock = ((org.bukkit.craftbukkit.block.CraftBlock) block);
|
||||
+ BlockPos blockposition = craftBlock.getPosition();
|
||||
+
|
||||
+ net.minecraft.world.level.block.Block nmsBlock = craftBlock.getNMS().getBlock();
|
||||
+ if (nmsBlock.dropFromExplosion(this.explosionSource)) {
|
||||
+ net.minecraft.world.level.block.entity.BlockEntity tileentity = craftBlock.getNMS().hasBlockEntity() ? this.level().getBlockEntity(blockposition) : null;
|
||||
+ net.minecraft.world.level.storage.loot.LootParams.Builder loottableinfo_builder = (new net.minecraft.world.level.storage.loot.LootParams.Builder((ServerLevel) this.level())).withParameter(net.minecraft.world.level.storage.loot.parameters.LootContextParams.ORIGIN, Vec3.atCenterOf(blockposition)).withParameter(net.minecraft.world.level.storage.loot.parameters.LootContextParams.TOOL, net.minecraft.world.item.ItemStack.EMPTY).withParameter(net.minecraft.world.level.storage.loot.parameters.LootContextParams.EXPLOSION_RADIUS, 1.0F / event.getYield()).withOptionalParameter(net.minecraft.world.level.storage.loot.parameters.LootContextParams.BLOCK_ENTITY, tileentity);
|
||||
+
|
||||
+ craftBlock.getNMS().getDrops(loottableinfo_builder).forEach((itemstack) -> {
|
||||
+ net.minecraft.world.level.block.Block.popResource(this.level(), blockposition, itemstack);
|
||||
+ });
|
||||
+ craftBlock.getNMS().spawnAfterBreak((ServerLevel) this.level(), blockposition, net.minecraft.world.item.ItemStack.EMPTY, false);
|
||||
+ }
|
||||
+ // Paper start - TNTPrimeEvent
|
||||
+ org.bukkit.block.Block tntBlock = org.bukkit.craftbukkit.block.CraftBlock.at(this.level(), blockposition);
|
||||
+ if (!new com.destroystokyo.paper.event.block.TNTPrimeEvent(tntBlock, com.destroystokyo.paper.event.block.TNTPrimeEvent.PrimeReason.EXPLOSION, explosionSource.getIndirectSourceEntity().getBukkitEntity()).callEvent())
|
||||
+ continue;
|
||||
+ // Paper end - TNTPrimeEvent
|
||||
+ nmsBlock.wasExploded((ServerLevel) this.level(), blockposition, this.explosionSource);
|
||||
+
|
||||
+ this.level().removeBlock(blockposition, false);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
if (flag1) {
|
||||
BlockPos blockPos1 = new BlockPos(
|
||||
floor + this.random.nextInt(floor3 - floor + 1),
|
||||
@@ -507,7 +_,15 @@
|
||||
|
||||
@Override
|
||||
public void kill(ServerLevel level) {
|
||||
- this.remove(Entity.RemovalReason.KILLED);
|
||||
+ // Paper start - Fire entity death event
|
||||
+ this.silentDeath = true;
|
||||
+ org.bukkit.event.entity.EntityDeathEvent deathEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, this.damageSources().genericKill());
|
||||
+ if (deathEvent.isCancelled()) {
|
||||
+ this.silentDeath = false; // Reset to default if event was cancelled
|
||||
+ return;
|
||||
+ }
|
||||
+ this.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // Paper - add Bukkit remove cause
|
||||
+ // Paper end - Fire entity death event
|
||||
this.gameEvent(GameEvent.ENTITY_DIE);
|
||||
if (this.dragonFight != null) {
|
||||
this.dragonFight.updateDragon(this);
|
||||
@@ -529,18 +_,41 @@
|
||||
this.level().addParticle(ParticleTypes.EXPLOSION_EMITTER, this.getX() + f, this.getY() + 2.0 + f1, this.getZ() + f2, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
+ // Paper start - SPIGOT-2420: Moved up to #getExpReward method
|
||||
+ /*
|
||||
int i = 500;
|
||||
if (this.dragonFight != null && !this.dragonFight.hasPreviouslyKilledDragon()) {
|
||||
i = 12000;
|
||||
}
|
||||
+ */
|
||||
+ int i = this.expToDrop;
|
||||
+ // Paper end
|
||||
|
||||
if (this.level() instanceof ServerLevel serverLevel) {
|
||||
- if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0 && serverLevel.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
|
||||
- ExperienceOrb.award(serverLevel, this.position(), Mth.floor(i * 0.08F));
|
||||
+ if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0) { // Paper - SPIGOT-2420: Already checked for the game rule when calculating the xp
|
||||
+ ExperienceOrb.award(serverLevel, this.position(), Mth.floor(i * 0.08F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, this.lastHurtByPlayer, this); // Paper
|
||||
}
|
||||
|
||||
if (this.dragonDeathTime == 1 && !this.isSilent()) {
|
||||
- serverLevel.globalLevelEvent(1028, this.blockPosition(), 0);
|
||||
+ // Paper start - Use relative location for far away sounds
|
||||
+ // serverLevel.globalLevelEvent(1028, this.blockPosition(), 0);
|
||||
+ int viewDistance = serverLevel.getCraftServer().getViewDistance() * 16;
|
||||
+ for (net.minecraft.server.level.ServerPlayer player : serverLevel.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 = serverLevel.getGlobalSoundRangeSquared(config -> config.dragonDeathSoundRadius); // Paper - respect global sound events gamerule
|
||||
+ if (!serverLevel.getGameRules().getBoolean(GameRules.RULE_GLOBAL_SOUND_EVENTS) && distanceSquared > soundRadiusSquared) continue; // 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 net.minecraft.network.protocol.game.ClientboundLevelEventPacket(1028, new BlockPos((int) relativeX, (int) this.getY(), (int) relativeZ), 0, true));
|
||||
+ } else {
|
||||
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelEventPacket(1028, new BlockPos((int) this.getX(), (int) this.getY(), (int) this.getZ()), 0, true));
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,15 +_,15 @@
|
||||
}
|
||||
|
||||
if (this.dragonDeathTime == 200 && this.level() instanceof ServerLevel serverLevel1) {
|
||||
- if (serverLevel1.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
|
||||
- ExperienceOrb.award(serverLevel1, this.position(), Mth.floor(i * 0.2F));
|
||||
+ if (true) { // Paper - SPIGOT-2420: Already checked for the game rule when calculating the xp
|
||||
+ ExperienceOrb.award(serverLevel1, this.position(), Mth.floor(i * 0.2F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, this.lastHurtByPlayer, this); // Paper
|
||||
}
|
||||
|
||||
if (this.dragonFight != null) {
|
||||
this.dragonFight.setDragonKilled(this);
|
||||
}
|
||||
|
||||
- this.remove(Entity.RemovalReason.KILLED);
|
||||
+ this.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // Paper - add Bukkit remove cause
|
||||
this.gameEvent(GameEvent.ENTITY_DIE);
|
||||
}
|
||||
}
|
||||
@@ -743,6 +_,7 @@
|
||||
super.addAdditionalSaveData(compound);
|
||||
compound.putInt("DragonPhase", this.phaseManager.getCurrentPhase().getPhase().getId());
|
||||
compound.putInt("DragonDeathTime", this.dragonDeathTime);
|
||||
+ compound.putInt("Bukkit.expToDrop", this.expToDrop); // Paper - SPIGOT-2420: The ender dragon drops xp over time which can also happen between server starts
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -755,6 +_,12 @@
|
||||
if (compound.contains("DragonDeathTime")) {
|
||||
this.dragonDeathTime = compound.getInt("DragonDeathTime");
|
||||
}
|
||||
+
|
||||
+ // Paper start - SPIGOT-2420: The ender dragon drops xp over time which can also happen between server starts
|
||||
+ if (compound.contains("Bukkit.expToDrop")) {
|
||||
+ this.expToDrop = compound.getInt("Bukkit.expToDrop");
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -795,7 +_,7 @@
|
||||
EnderDragonPhase<? extends DragonPhaseInstance> phase = currentPhase.getPhase();
|
||||
Vec3 viewVector;
|
||||
if (phase == EnderDragonPhase.LANDING || phase == EnderDragonPhase.TAKEOFF) {
|
||||
- BlockPos heightmapPos = this.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.fightOrigin));
|
||||
+ BlockPos heightmapPos = this.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.getPodium()); // Paper - Allow changing the EnderDragon podium
|
||||
float max = Math.max((float)Math.sqrt(heightmapPos.distToCenterSqr(this.position())) / 4.0F, 1.0F);
|
||||
float f = 6.0F / max;
|
||||
float xRot = this.getXRot();
|
||||
@@ -883,4 +_,20 @@
|
||||
protected float sanitizeScale(float scale) {
|
||||
return 1.0F;
|
||||
}
|
||||
+
|
||||
+ // Paper start - SPIGOT-2420: Special case, the ender dragon drops 12000 xp for the first kill and 500 xp for every other kill and this over time.
|
||||
+ @Override
|
||||
+ public int getExpReward(ServerLevel worldserver, Entity entity) {
|
||||
+ // CraftBukkit - Moved from #tickDeath method
|
||||
+ boolean flag = worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT);
|
||||
+ short short0 = 500;
|
||||
+
|
||||
+ if (this.dragonFight != null && !this.dragonFight.hasPreviouslyKilledDragon()) {
|
||||
+ short0 = 12000;
|
||||
+ }
|
||||
+
|
||||
+ return flag ? short0 : 0;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java
|
||||
@@ -34,7 +_,7 @@
|
||||
public void doServerTick(ServerLevel level) {
|
||||
this.time++;
|
||||
if (this.targetLocation == null) {
|
||||
- BlockPos heightmapPos = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.dragon.getFightOrigin()));
|
||||
+ BlockPos heightmapPos = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium
|
||||
this.targetLocation = Vec3.atBottomCenterOf(heightmapPos);
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java
|
||||
@@ -53,7 +53,7 @@
|
||||
@@ -53,7 +_,7 @@
|
||||
|
||||
private void findNewTarget(ServerLevel world) {
|
||||
private void findNewTarget(ServerLevel level) {
|
||||
if (this.currentPath != null && this.currentPath.isDone()) {
|
||||
- BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin()));
|
||||
+ BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium
|
||||
- BlockPos heightmapPos = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin()));
|
||||
+ BlockPos heightmapPos = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium
|
||||
int i = this.dragon.getDragonFight() == null ? 0 : this.dragon.getDragonFight().getCrystalsAlive();
|
||||
if (this.dragon.getRandom().nextInt(i + 3) == 0) {
|
||||
this.dragon.getPhaseManager().setPhase(EnderDragonPhase.LANDING_APPROACH);
|
@ -0,0 +1,11 @@
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java
|
||||
@@ -52,7 +_,7 @@
|
||||
private void findNewTarget(ServerLevel level) {
|
||||
if (this.currentPath == null || this.currentPath.isDone()) {
|
||||
int i = this.dragon.findClosestNode();
|
||||
- BlockPos heightmapPos = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin()));
|
||||
+ BlockPos heightmapPos = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium
|
||||
Player nearestPlayer = level.getNearestPlayer(NEAR_EGG_TARGETING, this.dragon, heightmapPos.getX(), heightmapPos.getY(), heightmapPos.getZ());
|
||||
int i1;
|
||||
if (nearestPlayer != null) {
|
@ -1,11 +1,11 @@
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java
|
||||
@@ -42,7 +42,7 @@
|
||||
public void doServerTick(ServerLevel world) {
|
||||
@@ -50,7 +_,7 @@
|
||||
public void doServerTick(ServerLevel level) {
|
||||
if (this.targetLocation == null) {
|
||||
this.targetLocation = Vec3.atBottomCenterOf(
|
||||
- world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin()))
|
||||
+ world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()) // Paper - Allow changing the EnderDragon podium
|
||||
- level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin()))
|
||||
+ level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()) // Paper - Allow changing the EnderDragon podium
|
||||
);
|
||||
}
|
||||
|
@ -1,35 +1,25 @@
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/phases/DragonSittingFlamingPhase.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonSittingFlamingPhase.java
|
||||
@@ -10,6 +10,9 @@
|
||||
import net.minecraft.world.entity.AreaEffectCloud;
|
||||
import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.event.entity.EntityRemoveEvent;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class DragonSittingFlamingPhase extends AbstractDragonSittingPhase {
|
||||
|
||||
@@ -86,7 +89,13 @@
|
||||
@@ -82,7 +_,13 @@
|
||||
this.flame.setDuration(200);
|
||||
this.flame.setParticle(ParticleTypes.DRAGON_BREATH);
|
||||
this.flame.addEffect(new MobEffectInstance(MobEffects.HARM));
|
||||
+ if (new com.destroystokyo.paper.event.entity.EnderDragonFlameEvent((org.bukkit.entity.EnderDragon) this.dragon.getBukkitEntity(), (org.bukkit.entity.AreaEffectCloud) this.flame.getBukkitEntity()).callEvent()) { // Paper - EnderDragon Events
|
||||
world.addFreshEntity(this.flame);
|
||||
+ // Paper start - EnderDragon Events
|
||||
level.addFreshEntity(this.flame);
|
||||
+ // Paper start
|
||||
+ } else {
|
||||
+ this.end();
|
||||
+ }
|
||||
+ // Paper end - EnderDragon Events
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
}
|
||||
@@ -100,7 +109,7 @@
|
||||
|
||||
@@ -95,7 +_,7 @@
|
||||
@Override
|
||||
public void end() {
|
||||
if (this.flame != null) {
|
||||
- this.flame.discard();
|
||||
+ this.flame.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
||||
+ this.flame.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // Paper- add Bukkit remove cause
|
||||
this.flame = null;
|
||||
}
|
||||
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java
|
||||
@@ -79,8 +79,11 @@
|
||||
@@ -77,8 +_,11 @@
|
||||
}
|
||||
|
||||
DragonFireball dragonFireball = new DragonFireball(world, this.dragon, vec34.normalize());
|
||||
DragonFireball dragonFireball = new DragonFireball(level, this.dragon, vec32.normalize());
|
||||
+ dragonFireball.preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported
|
||||
dragonFireball.moveTo(o, p, q, 0.0F, 0.0F);
|
||||
dragonFireball.moveTo(d2, d3, d4, 0.0F, 0.0F);
|
||||
+ if (new com.destroystokyo.paper.event.entity.EnderDragonShootFireballEvent((org.bukkit.entity.EnderDragon) dragon.getBukkitEntity(), (org.bukkit.entity.DragonFireball) dragonFireball.getBukkitEntity()).callEvent()) // Paper - EnderDragon Events
|
||||
world.addFreshEntity(dragonFireball);
|
||||
level.addFreshEntity(dragonFireball);
|
||||
+ else dragonFireball.discard(null); // Paper - EnderDragon Events
|
||||
this.fireballCharge = 0;
|
||||
if (this.currentPath != null) {
|
@ -0,0 +1,11 @@
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java
|
||||
@@ -24,7 +_,7 @@
|
||||
@Override
|
||||
public void doServerTick(ServerLevel level) {
|
||||
if (!this.firstTick && this.currentPath != null) {
|
||||
- BlockPos heightmapPos = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin()));
|
||||
+ BlockPos heightmapPos = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium
|
||||
if (!heightmapPos.closerToCenterThan(this.dragon.position(), 10.0)) {
|
||||
this.dragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN);
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java
|
||||
@@ -23,6 +_,19 @@
|
||||
this.currentPhase.end();
|
||||
}
|
||||
|
||||
+ // Paper start - Call EnderDragonChangePhaseEvent
|
||||
+ org.bukkit.event.entity.EnderDragonChangePhaseEvent event = new org.bukkit.event.entity.EnderDragonChangePhaseEvent(
|
||||
+ (org.bukkit.craftbukkit.entity.CraftEnderDragon) this.dragon.getBukkitEntity(),
|
||||
+ (this.currentPhase == null) ? null : org.bukkit.craftbukkit.entity.CraftEnderDragon.getBukkitPhase(this.currentPhase.getPhase()),
|
||||
+ org.bukkit.craftbukkit.entity.CraftEnderDragon.getBukkitPhase(phase)
|
||||
+ );
|
||||
+ this.dragon.level().getCraftServer().getPluginManager().callEvent(event);
|
||||
+ if (event.isCancelled()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ phase = org.bukkit.craftbukkit.entity.CraftEnderDragon.getMinecraftPhase(event.getNewPhase());
|
||||
+ // Paper end
|
||||
+
|
||||
this.currentPhase = this.getPhase((EnderDragonPhase<DragonPhaseInstance>)phase);
|
||||
if (!this.dragon.level().isClientSide) {
|
||||
this.dragon.getEntityData().set(EnderDragon.DATA_PHASE, phase.getId());
|
@ -0,0 +1,11 @@
|
||||
--- a/net/minecraft/world/level/dimension/end/EndDragonFight.java
|
||||
+++ b/net/minecraft/world/level/dimension/end/EndDragonFight.java
|
||||
@@ -92,7 +_,7 @@
|
||||
@Nullable
|
||||
private BlockPos portalLocation;
|
||||
@Nullable
|
||||
- private DragonRespawnAnimation respawnStage;
|
||||
+ public DragonRespawnAnimation respawnStage;// Paper-At: public net.minecraft.world.level.dimension.end.EndDragonFight respawnStage
|
||||
private int respawnTime;
|
||||
@Nullable
|
||||
private List<EndCrystal> respawnCrystals;
|
@ -1,91 +0,0 @@
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
|
||||
@@ -19,12 +19,18 @@
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.BaseFireBlock;
|
||||
import net.minecraft.world.level.dimension.end.EndDragonFight;
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
||||
+import org.bukkit.event.entity.EntityRemoveEvent;
|
||||
+import org.bukkit.event.entity.ExplosionPrimeEvent;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class EndCrystal extends Entity {
|
||||
|
||||
private static final EntityDataAccessor<Optional<BlockPos>> DATA_BEAM_TARGET = SynchedEntityData.defineId(EndCrystal.class, EntityDataSerializers.OPTIONAL_BLOCK_POS);
|
||||
private static final EntityDataAccessor<Boolean> DATA_SHOW_BOTTOM = SynchedEntityData.defineId(EndCrystal.class, EntityDataSerializers.BOOLEAN);
|
||||
public int time;
|
||||
+ public boolean generatedByDragonFight = false; // Paper - Fix invulnerable end crystals
|
||||
|
||||
public EndCrystal(EntityType<? extends EndCrystal> type, Level world) {
|
||||
super(type, world);
|
||||
@@ -57,8 +63,23 @@
|
||||
BlockPos blockposition = this.blockPosition();
|
||||
|
||||
if (((ServerLevel) this.level()).getDragonFight() != null && this.level().getBlockState(blockposition).isAir()) {
|
||||
- this.level().setBlockAndUpdate(blockposition, BaseFireBlock.getState(this.level(), blockposition));
|
||||
+ // CraftBukkit start
|
||||
+ if (!CraftEventFactory.callBlockIgniteEvent(this.level(), blockposition, this).isCancelled()) {
|
||||
+ this.level().setBlockAndUpdate(blockposition, BaseFireBlock.getState(this.level(), blockposition));
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
+ // Paper start - Fix invulnerable end crystals
|
||||
+ if (this.level().paperConfig().unsupportedSettings.fixInvulnerableEndCrystalExploit && this.generatedByDragonFight && this.isInvulnerable()) {
|
||||
+ if (!java.util.Objects.equals(((ServerLevel) this.level()).uuid, this.getOriginWorld())
|
||||
+ || ((ServerLevel) this.level()).getDragonFight() == null
|
||||
+ || ((ServerLevel) this.level()).getDragonFight().respawnStage == null
|
||||
+ || ((ServerLevel) this.level()).getDragonFight().respawnStage.ordinal() > net.minecraft.world.level.dimension.end.DragonRespawnAnimation.SUMMONING_DRAGON.ordinal()) {
|
||||
+ this.setInvulnerable(false);
|
||||
+ this.setBeamTarget(null);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Fix invulnerable end crystals
|
||||
}
|
||||
|
||||
}
|
||||
@@ -70,6 +91,7 @@
|
||||
}
|
||||
|
||||
nbt.putBoolean("ShowBottom", this.showsBottom());
|
||||
+ if (this.generatedByDragonFight) nbt.putBoolean("Paper.GeneratedByDragonFight", this.generatedByDragonFight); // Paper - Fix invulnerable end crystals
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,6 +100,7 @@
|
||||
if (nbt.contains("ShowBottom", 1)) {
|
||||
this.setShowBottom(nbt.getBoolean("ShowBottom"));
|
||||
}
|
||||
+ if (nbt.contains("Paper.GeneratedByDragonFight", 1)) this.generatedByDragonFight = nbt.getBoolean("Paper.GeneratedByDragonFight"); // Paper - Fix invulnerable end crystals
|
||||
|
||||
}
|
||||
|
||||
@@ -99,12 +122,26 @@
|
||||
return false;
|
||||
} else {
|
||||
if (!this.isRemoved()) {
|
||||
- this.remove(Entity.RemovalReason.KILLED);
|
||||
+ // CraftBukkit start - All non-living entities need this
|
||||
+ if (CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, amount, false)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
if (!source.is(DamageTypeTags.IS_EXPLOSION)) {
|
||||
DamageSource damagesource1 = source.getEntity() != null ? this.damageSources().explosion(this, source.getEntity()) : null;
|
||||
|
||||
- world.explode(this, damagesource1, (ExplosionDamageCalculator) null, this.getX(), this.getY(), this.getZ(), 6.0F, false, Level.ExplosionInteraction.BLOCK);
|
||||
+ // CraftBukkit start
|
||||
+ ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent(this, 6.0F, false);
|
||||
+ if (event.isCancelled()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause
|
||||
+ world.explode(this, damagesource1, (ExplosionDamageCalculator) null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.BLOCK);
|
||||
+ } else {
|
||||
+ this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause
|
||||
}
|
||||
+ // CraftBukkit end
|
||||
|
||||
this.onDestroyedBy(world, source);
|
||||
}
|
@ -1,331 +0,0 @@
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
|
||||
@@ -37,20 +37,35 @@
|
||||
import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhaseManager;
|
||||
import net.minecraft.world.entity.monster.Enemy;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
-import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.world.level.GameRules;
|
||||
import net.minecraft.world.level.Level;
|
||||
-import net.minecraft.world.level.block.state.BlockState;
|
||||
-import net.minecraft.world.level.dimension.end.EndDragonFight;
|
||||
import net.minecraft.world.level.gameevent.GameEvent;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.levelgen.feature.EndPodiumFeature;
|
||||
import net.minecraft.world.level.pathfinder.BinaryHeap;
|
||||
import net.minecraft.world.level.pathfinder.Node;
|
||||
import net.minecraft.world.level.pathfinder.Path;
|
||||
+import org.slf4j.Logger;
|
||||
+
|
||||
+// CraftBukkit start
|
||||
+import net.minecraft.world.item.ItemStack;
|
||||
+import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||
+import net.minecraft.world.level.Explosion;
|
||||
+import net.minecraft.world.level.ServerExplosion;
|
||||
+import net.minecraft.world.level.block.Block;
|
||||
+import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
+import net.minecraft.world.level.block.state.BlockState;
|
||||
+import net.minecraft.world.level.dimension.end.EndDragonFight;
|
||||
+import net.minecraft.world.level.storage.loot.LootParams;
|
||||
+import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
-import org.slf4j.Logger;
|
||||
+import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
+import org.bukkit.event.entity.EntityExplodeEvent;
|
||||
+import org.bukkit.event.entity.EntityRegainHealthEvent;
|
||||
+import org.bukkit.event.entity.EntityRemoveEvent;
|
||||
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
||||
+// CraftBukkit end
|
||||
|
||||
public class EnderDragon extends Mob implements Enemy {
|
||||
|
||||
@@ -88,6 +103,11 @@
|
||||
private final Node[] nodes;
|
||||
private final int[] nodeAdjacency;
|
||||
private final BinaryHeap openSet;
|
||||
+ private final Explosion explosionSource; // CraftBukkit - reusable source for CraftTNTPrimed.getSource()
|
||||
+ // Paper start - Allow changing the EnderDragon podium
|
||||
+ @Nullable
|
||||
+ private BlockPos podium;
|
||||
+ // Paper end - Allow changing the EnderDragon podium
|
||||
|
||||
public EnderDragon(EntityType<? extends EnderDragon> entitytypes, Level world) {
|
||||
super(EntityType.ENDER_DRAGON, world);
|
||||
@@ -108,6 +128,7 @@
|
||||
this.setHealth(this.getMaxHealth());
|
||||
this.noPhysics = true;
|
||||
this.phaseManager = new EnderDragonPhaseManager(this);
|
||||
+ this.explosionSource = new ServerExplosion(world.getMinecraftWorld(), this, null, null, new Vec3(Double.NaN, Double.NaN, Double.NaN), Float.NaN, true, Explosion.BlockInteraction.DESTROY); // CraftBukkit
|
||||
}
|
||||
|
||||
public void setDragonFight(EndDragonFight fight) {
|
||||
@@ -124,7 +145,20 @@
|
||||
|
||||
public static AttributeSupplier.Builder createAttributes() {
|
||||
return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0D);
|
||||
+ }
|
||||
+
|
||||
+ // Paper start - Allow changing the EnderDragon podium
|
||||
+ public BlockPos getPodium() {
|
||||
+ if (this.podium == null) {
|
||||
+ return EndPodiumFeature.getLocation(this.getFightOrigin());
|
||||
+ }
|
||||
+ return this.podium;
|
||||
+ }
|
||||
+
|
||||
+ public void setPodium(@Nullable BlockPos blockPos) {
|
||||
+ this.podium = blockPos;
|
||||
}
|
||||
+ // Paper end - Allow changing the EnderDragon podium
|
||||
|
||||
@Override
|
||||
public boolean isFlapping() {
|
||||
@@ -218,7 +252,7 @@
|
||||
|
||||
Vec3 vec3d1 = idragoncontroller.getFlyTargetLocation();
|
||||
|
||||
- if (vec3d1 != null) {
|
||||
+ if (vec3d1 != null && idragoncontroller.getPhase() != EnderDragonPhase.HOVERING) { // CraftBukkit - Don't move when hovering
|
||||
double d0 = vec3d1.x - this.getX();
|
||||
double d1 = vec3d1.y - this.getY();
|
||||
double d2 = vec3d1.z - this.getZ();
|
||||
@@ -379,7 +413,14 @@
|
||||
if (this.nearestCrystal.isRemoved()) {
|
||||
this.nearestCrystal = null;
|
||||
} else if (this.tickCount % 10 == 0 && this.getHealth() < this.getMaxHealth()) {
|
||||
- this.setHealth(this.getHealth() + 1.0F);
|
||||
+ // CraftBukkit start
|
||||
+ EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), 1.0F, EntityRegainHealthEvent.RegainReason.ENDER_CRYSTAL);
|
||||
+ this.level().getCraftServer().getPluginManager().callEvent(event);
|
||||
+
|
||||
+ if (!event.isCancelled()) {
|
||||
+ this.setHealth((float) (this.getHealth() + event.getAmount()));
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,7 +458,7 @@
|
||||
double d3 = entity.getZ() - d1;
|
||||
double d4 = Math.max(d2 * d2 + d3 * d3, 0.1D);
|
||||
|
||||
- entity.push(d2 / d4 * 4.0D, 0.20000000298023224D, d3 / d4 * 4.0D);
|
||||
+ entity.push(d2 / d4 * 4.0D, 0.20000000298023224D, d3 / d4 * 4.0D, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent
|
||||
if (!this.phaseManager.getCurrentPhase().isSitting() && entityliving.getLastHurtByMobTimestamp() < entity.tickCount - 2) {
|
||||
DamageSource damagesource = this.damageSources().mobAttack(this);
|
||||
|
||||
@@ -458,6 +499,9 @@
|
||||
int j1 = Mth.floor(box.maxZ);
|
||||
boolean flag = false;
|
||||
boolean flag1 = false;
|
||||
+ // CraftBukkit start - Create a list to hold all the destroyed blocks
|
||||
+ List<org.bukkit.block.Block> destroyedBlocks = new java.util.ArrayList<org.bukkit.block.Block>();
|
||||
+ // CraftBukkit end
|
||||
|
||||
for (int k1 = i; k1 <= l; ++k1) {
|
||||
for (int l1 = j; l1 <= i1; ++l1) {
|
||||
@@ -467,14 +511,66 @@
|
||||
|
||||
if (!iblockdata.isAir() && !iblockdata.is(BlockTags.DRAGON_TRANSPARENT)) {
|
||||
if (world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && !iblockdata.is(BlockTags.DRAGON_IMMUNE)) {
|
||||
- flag1 = world.removeBlock(blockposition, false) || flag1;
|
||||
+ // CraftBukkit start - Add blocks to list rather than destroying them
|
||||
+ // flag1 = worldserver.removeBlock(blockposition, false) || flag1;
|
||||
+ flag1 = true;
|
||||
+ destroyedBlocks.add(CraftBlock.at(world, blockposition));
|
||||
+ // CraftBukkit end
|
||||
} else {
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // CraftBukkit start - Set off an EntityExplodeEvent for the dragon exploding all these blocks
|
||||
+ // SPIGOT-4882: don't fire event if nothing hit
|
||||
+ if (!flag1) {
|
||||
+ return flag;
|
||||
+ }
|
||||
+
|
||||
+ EntityExplodeEvent event = CraftEventFactory.callEntityExplodeEvent(this, destroyedBlocks, 0F, this.explosionSource.getBlockInteraction());
|
||||
+ if (event.isCancelled()) {
|
||||
+ // This flag literally means 'Dragon hit something hard' (Obsidian, White Stone or Bedrock) and will cause the dragon to slow down.
|
||||
+ // We should consider adding an event extension for it, or perhaps returning true if the event is cancelled.
|
||||
+ return flag;
|
||||
+ } else if (event.getYield() == 0F) {
|
||||
+ // Yield zero ==> no drops
|
||||
+ for (org.bukkit.block.Block block : event.blockList()) {
|
||||
+ this.level().removeBlock(new BlockPos(block.getX(), block.getY(), block.getZ()), false);
|
||||
+ }
|
||||
+ } else {
|
||||
+ for (org.bukkit.block.Block block : event.blockList()) {
|
||||
+ org.bukkit.Material blockId = block.getType();
|
||||
+ if (blockId.isAir()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ CraftBlock craftBlock = ((CraftBlock) block);
|
||||
+ BlockPos blockposition = craftBlock.getPosition();
|
||||
+
|
||||
+ Block nmsBlock = craftBlock.getNMS().getBlock();
|
||||
+ if (nmsBlock.dropFromExplosion(this.explosionSource)) {
|
||||
+ BlockEntity tileentity = craftBlock.getNMS().hasBlockEntity() ? this.level().getBlockEntity(blockposition) : null;
|
||||
+ LootParams.Builder loottableinfo_builder = (new LootParams.Builder((ServerLevel) this.level())).withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(blockposition)).withParameter(LootContextParams.TOOL, ItemStack.EMPTY).withParameter(LootContextParams.EXPLOSION_RADIUS, 1.0F / event.getYield()).withOptionalParameter(LootContextParams.BLOCK_ENTITY, tileentity);
|
||||
+
|
||||
+ craftBlock.getNMS().getDrops(loottableinfo_builder).forEach((itemstack) -> {
|
||||
+ Block.popResource(this.level(), blockposition, itemstack);
|
||||
+ });
|
||||
+ craftBlock.getNMS().spawnAfterBreak((ServerLevel) this.level(), blockposition, ItemStack.EMPTY, false);
|
||||
}
|
||||
+ // Paper start - TNTPrimeEvent
|
||||
+ org.bukkit.block.Block tntBlock = CraftBlock.at(this.level(), blockposition);
|
||||
+ if (!new com.destroystokyo.paper.event.block.TNTPrimeEvent(tntBlock, com.destroystokyo.paper.event.block.TNTPrimeEvent.PrimeReason.EXPLOSION, explosionSource.getIndirectSourceEntity().getBukkitEntity()).callEvent())
|
||||
+ continue;
|
||||
+ // Paper end - TNTPrimeEvent
|
||||
+ nmsBlock.wasExploded((ServerLevel) this.level(), blockposition, this.explosionSource);
|
||||
+
|
||||
+ this.level().removeBlock(blockposition, false);
|
||||
}
|
||||
}
|
||||
+ // CraftBukkit end
|
||||
|
||||
if (flag1) {
|
||||
BlockPos blockposition1 = new BlockPos(i + this.random.nextInt(l - i + 1), j + this.random.nextInt(i1 - j + 1), k + this.random.nextInt(j1 - k + 1));
|
||||
@@ -531,7 +627,15 @@
|
||||
|
||||
@Override
|
||||
public void kill(ServerLevel world) {
|
||||
- this.remove(Entity.RemovalReason.KILLED);
|
||||
+ // Paper start - Fire entity death event
|
||||
+ this.silentDeath = true;
|
||||
+ org.bukkit.event.entity.EntityDeathEvent deathEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, this.damageSources().genericKill());
|
||||
+ if (deathEvent.isCancelled()) {
|
||||
+ this.silentDeath = false; // Reset to default if event was cancelled
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Fire entity death event
|
||||
+ this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause
|
||||
this.gameEvent(GameEvent.ENTITY_DIE);
|
||||
if (this.dragonFight != null) {
|
||||
this.dragonFight.updateDragon(this);
|
||||
@@ -540,7 +644,22 @@
|
||||
|
||||
}
|
||||
|
||||
+ // CraftBukkit start - SPIGOT-2420: Special case, the ender dragon drops 12000 xp for the first kill and 500 xp for every other kill and this over time.
|
||||
@Override
|
||||
+ public int getExpReward(ServerLevel worldserver, Entity entity) {
|
||||
+ // CraftBukkit - Moved from #tickDeath method
|
||||
+ boolean flag = worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT);
|
||||
+ short short0 = 500;
|
||||
+
|
||||
+ if (this.dragonFight != null && !this.dragonFight.hasPreviouslyKilledDragon()) {
|
||||
+ short0 = 12000;
|
||||
+ }
|
||||
+
|
||||
+ return flag ? short0 : 0;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
+ @Override
|
||||
protected void tickDeath() {
|
||||
if (this.dragonFight != null) {
|
||||
this.dragonFight.updateDragon(this);
|
||||
@@ -555,21 +674,44 @@
|
||||
this.level().addParticle(ParticleTypes.EXPLOSION_EMITTER, this.getX() + (double) f, this.getY() + 2.0D + (double) f1, this.getZ() + (double) f2, 0.0D, 0.0D, 0.0D);
|
||||
}
|
||||
|
||||
+ // CraftBukkit start - SPIGOT-2420: Moved up to #getExpReward method
|
||||
+ /*
|
||||
short short0 = 500;
|
||||
|
||||
if (this.dragonFight != null && !this.dragonFight.hasPreviouslyKilledDragon()) {
|
||||
short0 = 12000;
|
||||
}
|
||||
+ */
|
||||
+ int short0 = this.expToDrop;
|
||||
+ // CraftBukkit end
|
||||
|
||||
Level world = this.level();
|
||||
|
||||
if (world instanceof ServerLevel worldserver) {
|
||||
- if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0 && worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
|
||||
- ExperienceOrb.award(worldserver, this.position(), Mth.floor((float) short0 * 0.08F));
|
||||
+ if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0 && true) { // CraftBukkit - SPIGOT-2420: Already checked for the game rule when calculating the xp
|
||||
+ ExperienceOrb.award(worldserver, this.position(), Mth.floor((float) short0 * 0.08F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, this.lastHurtByPlayer, this); // Paper
|
||||
}
|
||||
|
||||
if (this.dragonDeathTime == 1 && !this.isSilent()) {
|
||||
- worldserver.globalLevelEvent(1028, this.blockPosition(), 0);
|
||||
+ // CraftBukkit start - Use relative location for far away sounds
|
||||
+ // worldserver.globalLevelEvent(1028, this.blockPosition(), 0);
|
||||
+ int viewDistance = worldserver.getCraftServer().getViewDistance() * 16;
|
||||
+ for (net.minecraft.server.level.ServerPlayer player : worldserver.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 = worldserver.getGlobalSoundRangeSquared(config -> config.dragonDeathSoundRadius); // Paper - respect global sound events gamerule
|
||||
+ if ( !worldserver.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 net.minecraft.network.protocol.game.ClientboundLevelEventPacket(1028, new BlockPos((int) relativeX, (int) this.getY(), (int) relativeZ), 0, true));
|
||||
+ } else {
|
||||
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelEventPacket(1028, new BlockPos((int) this.getX(), (int) this.getY(), (int) this.getZ()), 0, true));
|
||||
+ }
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,15 +734,15 @@
|
||||
if (world1 instanceof ServerLevel) {
|
||||
ServerLevel worldserver1 = (ServerLevel) world1;
|
||||
|
||||
- if (worldserver1.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
|
||||
- ExperienceOrb.award(worldserver1, this.position(), Mth.floor((float) short0 * 0.2F));
|
||||
+ if (true) { // CraftBukkit - SPIGOT-2420: Already checked for the game rule when calculating the xp
|
||||
+ ExperienceOrb.award(worldserver1, this.position(), Mth.floor((float) short0 * 0.2F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, this.lastHurtByPlayer, this); // Paper
|
||||
}
|
||||
|
||||
if (this.dragonFight != null) {
|
||||
this.dragonFight.setDragonKilled(this);
|
||||
}
|
||||
|
||||
- this.remove(Entity.RemovalReason.KILLED);
|
||||
+ this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause
|
||||
this.gameEvent(GameEvent.ENTITY_DIE);
|
||||
}
|
||||
}
|
||||
@@ -814,6 +956,7 @@
|
||||
super.addAdditionalSaveData(nbt);
|
||||
nbt.putInt("DragonPhase", this.phaseManager.getCurrentPhase().getPhase().getId());
|
||||
nbt.putInt("DragonDeathTime", this.dragonDeathTime);
|
||||
+ nbt.putInt("Bukkit.expToDrop", this.expToDrop); // CraftBukkit - SPIGOT-2420: The ender dragon drops xp over time which can also happen between server starts
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -827,6 +970,11 @@
|
||||
this.dragonDeathTime = nbt.getInt("DragonDeathTime");
|
||||
}
|
||||
|
||||
+ // CraftBukkit start - SPIGOT-2420: The ender dragon drops xp over time which can also happen between server starts
|
||||
+ if (nbt.contains("Bukkit.expToDrop")) {
|
||||
+ this.expToDrop = nbt.getInt("Bukkit.expToDrop");
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -879,7 +1027,7 @@
|
||||
vec3d = this.getViewVector(tickDelta);
|
||||
}
|
||||
} else {
|
||||
- BlockPos blockposition = this.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.fightOrigin));
|
||||
+ BlockPos blockposition = this.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.getPodium()); // Paper - Allow changing the EnderDragon podium
|
||||
|
||||
f1 = Math.max((float) Math.sqrt(blockposition.distToCenterSqr(this.position())) / 4.0F, 1.0F);
|
||||
float f3 = 6.0F / f1;
|
@ -1,11 +0,0 @@
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java
|
||||
@@ -42,7 +42,7 @@
|
||||
public void doServerTick(ServerLevel world) {
|
||||
this.time++;
|
||||
if (this.targetLocation == null) {
|
||||
- BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.dragon.getFightOrigin()));
|
||||
+ BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium
|
||||
this.targetLocation = Vec3.atBottomCenterOf(blockPos);
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java
|
||||
@@ -52,7 +52,7 @@
|
||||
private void findNewTarget(ServerLevel world) {
|
||||
if (this.currentPath == null || this.currentPath.isDone()) {
|
||||
int i = this.dragon.findClosestNode();
|
||||
- BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin()));
|
||||
+ BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium
|
||||
Player player = world.getNearestPlayer(NEAR_EGG_TARGETING, this.dragon, (double)blockPos.getX(), (double)blockPos.getY(), (double)blockPos.getZ());
|
||||
int j;
|
||||
if (player != null) {
|
@ -1,11 +0,0 @@
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java
|
||||
@@ -24,7 +24,7 @@
|
||||
@Override
|
||||
public void doServerTick(ServerLevel world) {
|
||||
if (!this.firstTick && this.currentPath != null) {
|
||||
- BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin()));
|
||||
+ BlockPos blockPos = world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium
|
||||
if (!blockPos.closerToCenterThan(this.dragon.position(), 10.0)) {
|
||||
this.dragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN);
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java
|
||||
@@ -5,6 +5,11 @@
|
||||
import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import org.bukkit.craftbukkit.entity.CraftEnderDragon;
|
||||
+import org.bukkit.event.entity.EnderDragonChangePhaseEvent;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public class EnderDragonPhaseManager {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
@@ -24,6 +29,19 @@
|
||||
this.currentPhase.end();
|
||||
}
|
||||
|
||||
+ // CraftBukkit start - Call EnderDragonChangePhaseEvent
|
||||
+ EnderDragonChangePhaseEvent event = new EnderDragonChangePhaseEvent(
|
||||
+ (CraftEnderDragon) this.dragon.getBukkitEntity(),
|
||||
+ (this.currentPhase == null) ? null : CraftEnderDragon.getBukkitPhase(this.currentPhase.getPhase()),
|
||||
+ CraftEnderDragon.getBukkitPhase(type)
|
||||
+ );
|
||||
+ this.dragon.level().getCraftServer().getPluginManager().callEvent(event);
|
||||
+ if (event.isCancelled()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ type = CraftEnderDragon.getMinecraftPhase(event.getNewPhase());
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
this.currentPhase = this.getPhase(type);
|
||||
if (!this.dragon.level().isClientSide) {
|
||||
this.dragon.getEntityData().set(EnderDragon.DATA_PHASE, type.getId());
|
||||
@@ -45,6 +63,6 @@
|
||||
this.phases[i] = type.createInstance(this.dragon);
|
||||
}
|
||||
|
||||
- return this.phases[i];
|
||||
+ return (T) this.phases[i]; // CraftBukkit - decompile error
|
||||
}
|
||||
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren