mirror of
https://github.com/PaperMC/Paper.git
synced 2025-01-09 19:49:35 +01:00
ed2f6b4efc
Currently the Ender Dragon takes roughly 3x the explosion damage when compared to vanilla 1.19.3. This is caused by a single damage value being calculated for the EntityEnderDragon and then being uniformly applied to every EntityComplexPart belonging to that dragon. This is resolved by restoring the vanilla behavior of calculating explosion damage separately for each EntityComplexPart. By: Jacob Martin <jjm_223@hotmail.com>
172 lines
9.3 KiB
Diff
172 lines
9.3 KiB
Diff
--- a/net/minecraft/world/level/Explosion.java
|
|
+++ b/net/minecraft/world/level/Explosion.java
|
|
@@ -40,6 +40,15 @@
|
|
import net.minecraft.world.phys.MovingObjectPosition;
|
|
import net.minecraft.world.phys.Vec3D;
|
|
|
|
+// CraftBukkit start
|
|
+import net.minecraft.world.entity.boss.EntityComplexPart;
|
|
+import net.minecraft.world.entity.boss.enderdragon.EntityEnderDragon;
|
|
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
|
+import org.bukkit.event.entity.EntityExplodeEvent;
|
|
+import org.bukkit.Location;
|
|
+import org.bukkit.event.block.BlockExplodeEvent;
|
|
+// CraftBukkit end
|
|
+
|
|
public class Explosion {
|
|
|
|
private static final ExplosionDamageCalculator EXPLOSION_DAMAGE_CALCULATOR = new ExplosionDamageCalculator();
|
|
@@ -58,6 +67,7 @@
|
|
private final ExplosionDamageCalculator damageCalculator;
|
|
private final ObjectArrayList<BlockPosition> toBlow;
|
|
private final Map<EntityHuman, Vec3D> hitPlayers;
|
|
+ public boolean wasCanceled = false; // CraftBukkit - add field
|
|
|
|
public Explosion(World world, @Nullable Entity entity, double d0, double d1, double d2, float f, List<BlockPosition> list) {
|
|
this(world, entity, d0, d1, d2, f, false, Explosion.Effect.DESTROY_WITH_DECAY, list);
|
|
@@ -78,7 +88,7 @@
|
|
this.hitPlayers = Maps.newHashMap();
|
|
this.level = world;
|
|
this.source = entity;
|
|
- this.radius = f;
|
|
+ this.radius = (float) Math.max(f, 0.0); // CraftBukkit - clamp bad values
|
|
this.x = d0;
|
|
this.y = d1;
|
|
this.z = d2;
|
|
@@ -128,6 +138,11 @@
|
|
}
|
|
|
|
public void explode() {
|
|
+ // CraftBukkit start
|
|
+ if (this.radius < 0.1F) {
|
|
+ return;
|
|
+ }
|
|
+ // CraftBukkit end
|
|
this.level.gameEvent(this.source, GameEvent.EXPLODE, new Vec3D(this.x, this.y, this.z));
|
|
Set<BlockPosition> set = Sets.newHashSet();
|
|
boolean flag = true;
|
|
@@ -211,7 +226,39 @@
|
|
double d12 = (double) getSeenPercent(vec3d, entity);
|
|
double d13 = (1.0D - d7) * d12;
|
|
|
|
- entity.hurt(this.getDamageSource(), (float) ((int) ((d13 * d13 + d13) / 2.0D * 7.0D * (double) f2 + 1.0D)));
|
|
+ // CraftBukkit start
|
|
+
|
|
+ // Special case ender dragon only give knockback if no damage is cancelled
|
|
+ // Thinks to note:
|
|
+ // - Setting a velocity to a ComplexEntityPart is ignored (and therefore not needed)
|
|
+ // - Damaging ComplexEntityPart while forward the damage to EntityEnderDragon
|
|
+ // - Damaging EntityEnderDragon does nothing
|
|
+ // - EntityEnderDragon hitbock always covers the other parts and is therefore always present
|
|
+ if (entity instanceof EntityComplexPart) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ CraftEventFactory.entityDamage = source;
|
|
+ entity.lastDamageCancelled = false;
|
|
+
|
|
+ if (entity instanceof EntityEnderDragon) {
|
|
+ for (EntityComplexPart entityComplexPart : ((EntityEnderDragon) entity).subEntities) {
|
|
+ // Calculate damage separately for each EntityComplexPart
|
|
+ double d7part;
|
|
+ if (list.contains(entityComplexPart) && (d7part = Math.sqrt(entityComplexPart.distanceToSqr(vec3d)) / f2) <= 1.0D) {
|
|
+ double d13part = (1.0D - d7part) * getSeenPercent(vec3d, entityComplexPart);
|
|
+ entityComplexPart.hurt(this.getDamageSource(), (float) ((int) ((d13part * d13part + d13part) / 2.0D * 7.0D * (double) f2 + 1.0D)));
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ entity.hurt(this.getDamageSource(), (float) ((int) ((d13 * d13 + d13) / 2.0D * 7.0D * (double) f2 + 1.0D)));
|
|
+ }
|
|
+
|
|
+ CraftEventFactory.entityDamage = null;
|
|
+ if (entity.lastDamageCancelled) { // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Skip entity if damage event was cancelled
|
|
+ continue;
|
|
+ }
|
|
+ // CraftBukkit end
|
|
double d14 = d13;
|
|
|
|
if (entity instanceof EntityLiving) {
|
|
@@ -254,6 +301,51 @@
|
|
|
|
SystemUtils.shuffle(this.toBlow, this.level.random);
|
|
ObjectListIterator objectlistiterator = this.toBlow.iterator();
|
|
+ // CraftBukkit start
|
|
+ org.bukkit.World bworld = this.level.getWorld();
|
|
+ org.bukkit.entity.Entity explode = this.source == null ? null : this.source.getBukkitEntity();
|
|
+ Location location = new Location(bworld, this.x, this.y, this.z);
|
|
+
|
|
+ List<org.bukkit.block.Block> blockList = new ObjectArrayList<>();
|
|
+ for (int i1 = this.toBlow.size() - 1; i1 >= 0; i1--) {
|
|
+ BlockPosition cpos = (BlockPosition) this.toBlow.get(i1);
|
|
+ org.bukkit.block.Block bblock = bworld.getBlockAt(cpos.getX(), cpos.getY(), cpos.getZ());
|
|
+ if (!bblock.getType().isAir()) {
|
|
+ blockList.add(bblock);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ boolean cancelled;
|
|
+ List<org.bukkit.block.Block> bukkitBlocks;
|
|
+ float yield;
|
|
+
|
|
+ if (explode != null) {
|
|
+ EntityExplodeEvent event = new EntityExplodeEvent(explode, location, blockList, this.blockInteraction == Explosion.Effect.DESTROY ? 1.0F / this.radius : 1.0F);
|
|
+ this.level.getCraftServer().getPluginManager().callEvent(event);
|
|
+ cancelled = event.isCancelled();
|
|
+ bukkitBlocks = event.blockList();
|
|
+ yield = event.getYield();
|
|
+ } else {
|
|
+ BlockExplodeEvent event = new BlockExplodeEvent(location.getBlock(), blockList, this.blockInteraction == Explosion.Effect.DESTROY ? 1.0F / this.radius : 1.0F);
|
|
+ this.level.getCraftServer().getPluginManager().callEvent(event);
|
|
+ cancelled = event.isCancelled();
|
|
+ bukkitBlocks = event.blockList();
|
|
+ yield = event.getYield();
|
|
+ }
|
|
+
|
|
+ this.toBlow.clear();
|
|
+
|
|
+ for (org.bukkit.block.Block bblock : bukkitBlocks) {
|
|
+ BlockPosition coords = new BlockPosition(bblock.getX(), bblock.getY(), bblock.getZ());
|
|
+ toBlow.add(coords);
|
|
+ }
|
|
+
|
|
+ if (cancelled) {
|
|
+ this.wasCanceled = true;
|
|
+ return;
|
|
+ }
|
|
+ // CraftBukkit end
|
|
+ objectlistiterator = this.toBlow.iterator();
|
|
|
|
while (objectlistiterator.hasNext()) {
|
|
BlockPosition blockposition = (BlockPosition) objectlistiterator.next();
|
|
@@ -272,8 +364,8 @@
|
|
TileEntity tileentity = iblockdata.hasBlockEntity() ? this.level.getBlockEntity(blockposition) : null;
|
|
LootTableInfo.Builder loottableinfo_builder = (new LootTableInfo.Builder(worldserver)).withRandom(this.level.random).withParameter(LootContextParameters.ORIGIN, Vec3D.atCenterOf(blockposition)).withParameter(LootContextParameters.TOOL, ItemStack.EMPTY).withOptionalParameter(LootContextParameters.BLOCK_ENTITY, tileentity).withOptionalParameter(LootContextParameters.THIS_ENTITY, this.source);
|
|
|
|
- if (this.blockInteraction == Explosion.Effect.DESTROY_WITH_DECAY) {
|
|
- loottableinfo_builder.withParameter(LootContextParameters.EXPLOSION_RADIUS, this.radius);
|
|
+ if (this.blockInteraction == Explosion.Effect.DESTROY_WITH_DECAY || yield < 1.0F) { // CraftBukkit - add yield
|
|
+ loottableinfo_builder.withParameter(LootContextParameters.EXPLOSION_RADIUS, 1.0F / yield); // CraftBukkit - add yield
|
|
}
|
|
|
|
iblockdata.spawnAfterBreak(worldserver, blockposition, ItemStack.EMPTY, flag2);
|
|
@@ -305,7 +397,11 @@
|
|
BlockPosition blockposition2 = (BlockPosition) objectlistiterator1.next();
|
|
|
|
if (this.random.nextInt(3) == 0 && this.level.getBlockState(blockposition2).isAir() && this.level.getBlockState(blockposition2.below()).isSolidRender(this.level, blockposition2.below())) {
|
|
- this.level.setBlockAndUpdate(blockposition2, BlockFireAbstract.getState(this.level, blockposition2));
|
|
+ // CraftBukkit start - Ignition by explosion
|
|
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level, blockposition2.getX(), blockposition2.getY(), blockposition2.getZ(), this).isCancelled()) {
|
|
+ this.level.setBlockAndUpdate(blockposition2, BlockFireAbstract.getState(this.level, blockposition2));
|
|
+ }
|
|
+ // CraftBukkit end
|
|
}
|
|
}
|
|
}
|
|
@@ -317,6 +413,7 @@
|
|
}
|
|
|
|
private static void addBlockDrops(ObjectArrayList<Pair<ItemStack, BlockPosition>> objectarraylist, ItemStack itemstack, BlockPosition blockposition) {
|
|
+ if (itemstack.isEmpty()) return; // CraftBukkit - SPIGOT-5425
|
|
int i = objectarraylist.size();
|
|
|
|
for (int j = 0; j < i; ++j) {
|