From 96dde2d7305d9d9fe4029ba6797be0c733fe9419 Mon Sep 17 00:00:00 2001 From: Esoteric Enderman <90862990+EsotericEnderman@users.noreply.github.com> Date: Sat, 28 Sep 2024 20:32:56 +0100 Subject: [PATCH] Add API for explosions to damage the explosion cause (#11180) This intends to give plugin developers more control over explosions created using the World#createExplosion method, specifically by adding the option for explosions to damage the explosion cause (not the default behavior, and previously impossible to do, as far as I know). This is done by overloading existing methods with an extra `excludeSourceFromDamage` parameter. Co-authored-by: Bjarne Koll --- patches/api/Expand-Explosions-API.patch | 21 +++- patches/server/Expand-Explosions-API.patch | 96 ++++++++++++++++++- .../Moonrise-optimisation-patches.patch | 2 +- 3 files changed, 115 insertions(+), 4 deletions(-) diff --git a/patches/api/Expand-Explosions-API.patch b/patches/api/Expand-Explosions-API.patch index f9fdbc350c..a93aeba132 100644 --- a/patches/api/Expand-Explosions-API.patch +++ b/patches/api/Expand-Explosions-API.patch @@ -5,6 +5,9 @@ Subject: [PATCH] Expand Explosions API Add Entity as a Source capability, and add more API choices, and on Location. +Co-authored-by: Slqmy <90862990+Slqmy@users.noreply.github.com> +Co-authored-by: Bjarne Koll + diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/Location.java @@ -125,9 +128,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @param power The power of explosion, where 4F is TNT + * @param setFire Whether or not to set blocks on fire + * @param breakBlocks Whether or not to have blocks be destroyed ++ * @param excludeSourceFromDamage whether the explosion should exclude the passed source from taking damage like vanilla explosions do. + * @return false if explosion was canceled, otherwise true + */ -+ public boolean createExplosion(@Nullable Entity source, @NotNull Location loc, float power, boolean setFire, boolean breakBlocks); ++ public boolean createExplosion(@Nullable Entity source, @NotNull Location loc, float power, boolean setFire, boolean breakBlocks, boolean excludeSourceFromDamage); ++ ++ /** ++ * Creates explosion at given location with given power and optionally ++ * setting blocks on fire, with the specified entity as the source. ++ * ++ * @param source The source entity of the explosion ++ * @param loc Location to blow up ++ * @param power The power of explosion, where 4F is TNT ++ * @param setFire Whether or not to set blocks on fire ++ * @param breakBlocks Whether or not to have blocks be destroyed ++ * @return false if explosion was canceled, otherwise true ++ */ ++ default boolean createExplosion(@Nullable Entity source, @NotNull Location loc, float power, boolean setFire, boolean breakBlocks) { ++ return createExplosion(source, loc, power, setFire, breakBlocks, true); ++ } + + /** + * Creates explosion at given location with given power and optionally diff --git a/patches/server/Expand-Explosions-API.patch b/patches/server/Expand-Explosions-API.patch index 27001e63b4..a0d48f2081 100644 --- a/patches/server/Expand-Explosions-API.patch +++ b/patches/server/Expand-Explosions-API.patch @@ -5,6 +5,96 @@ Subject: [PATCH] Expand Explosions API Add Entity as a Source capability, and add more API choices, and on Location. +Co-authored-by: Slqmy <90862990+Slqmy@users.noreply.github.com> +Co-authored-by: Bjarne Koll + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { + } + + @Override +- public Explosion explode(@Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Level.ExplosionInteraction explosionSourceType, ParticleOptions particle, ParticleOptions emitterParticle, Holder soundEvent) { +- Explosion explosion = this.explode(entity, damageSource, behavior, x, y, z, power, createFire, explosionSourceType, false, particle, emitterParticle, soundEvent); ++ // Paper start - Allow explosions to damage source ++ public Explosion explode(@Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Level.ExplosionInteraction explosionSourceType, ParticleOptions particle, ParticleOptions emitterParticle, Holder soundEvent, java.util.function.Consumer configurator) { ++ Explosion explosion = this.explode(entity, damageSource, behavior, x, y, z, power, createFire, explosionSourceType, false, particle, emitterParticle, soundEvent, configurator); ++ // Paper end - Allow explosions to damage source + // CraftBukkit start + if (explosion.wasCanceled) { + return explosion; +diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/level/Explosion.java ++++ b/src/main/java/net/minecraft/world/level/Explosion.java +@@ -0,0 +0,0 @@ public class Explosion { + public boolean wasCanceled = false; + public float yield; + // CraftBukkit end ++ public boolean excludeSourceFromDamage = true; // Paper - Allow explosions to damage source + + public static DamageSource getDefaultDamageSource(Level world, @Nullable Entity source) { + return world.damageSources().explosion(source, Explosion.getIndirectSourceEntityInternal(source)); +@@ -0,0 +0,0 @@ public class Explosion { + int i1 = Mth.floor(this.y + (double) f2 + 1.0D); + int j1 = Mth.floor(this.z - (double) f2 - 1.0D); + int k1 = Mth.floor(this.z + (double) f2 + 1.0D); +- List list = this.level.getEntities(this.source, new AABB((double) i, (double) l, (double) j1, (double) j, (double) i1, (double) k1), (com.google.common.base.Predicate) entity -> entity.isAlive() && !entity.isSpectator()); // Paper - Fix lag from explosions processing dead entities ++ List list = this.level.getEntities(excludeSourceFromDamage ? this.source : null, new AABB((double) i, (double) l, (double) j1, (double) j, (double) i1, (double) k1), (com.google.common.base.Predicate) entity -> entity.isAlive() && !entity.isSpectator()); // Paper - Fix lag from explosions processing dead entities, Allow explosions to damage source + Vec3 vec3d = new Vec3(this.x, this.y, this.z); + Iterator iterator = list.iterator(); + +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + } + + public Explosion explode(@Nullable Entity entity, double x, double y, double z, float power, boolean createFire, Level.ExplosionInteraction explosionSourceType) { +- return this.explode(entity, Explosion.getDefaultDamageSource(this, entity), (ExplosionDamageCalculator) null, x, y, z, power, createFire, explosionSourceType, ParticleTypes.EXPLOSION, ParticleTypes.EXPLOSION_EMITTER, SoundEvents.GENERIC_EXPLODE); ++ // Paper start - Allow explosions to damage source ++ return this.explode(entity, x, y, z, power, createFire, explosionSourceType, null); ++ } ++ public Explosion explode(@Nullable Entity entity, double x, double y, double z, float power, boolean createFire, Level.ExplosionInteraction explosionSourceType, @Nullable Consumer configurator) { ++ return this.explode(entity, Explosion.getDefaultDamageSource(this, entity), (ExplosionDamageCalculator) null, x, y, z, power, createFire, explosionSourceType, ParticleTypes.EXPLOSION, ParticleTypes.EXPLOSION_EMITTER, SoundEvents.GENERIC_EXPLODE, configurator); ++ // Paper end - Allow explosions to damage source + } + + public Explosion explode(@Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, Vec3 pos, float power, boolean createFire, Level.ExplosionInteraction explosionSourceType) { +@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + } + + public Explosion explode(@Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Level.ExplosionInteraction explosionSourceType, ParticleOptions particle, ParticleOptions emitterParticle, Holder soundEvent) { +- return this.explode(entity, damageSource, behavior, x, y, z, power, createFire, explosionSourceType, true, particle, emitterParticle, soundEvent); ++ // Paper start - Allow explosions to damage source ++ return this.explode(entity, damageSource, behavior, x, y, z, power, createFire, explosionSourceType, particle, emitterParticle, soundEvent, null); ++ } ++ ++ public Explosion explode(@Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Level.ExplosionInteraction explosionSourceType, ParticleOptions particle, ParticleOptions emitterParticle, Holder soundEvent, @Nullable Consumer configurator) { ++ return this.explode(entity, damageSource, behavior, x, y, z, power, createFire, explosionSourceType, true, particle, emitterParticle, soundEvent, configurator); ++ // Paper end - Allow explosions to damage source + } + + public Explosion explode(@Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Level.ExplosionInteraction explosionSourceType, boolean particles, ParticleOptions particle, ParticleOptions emitterParticle, Holder soundEvent) { ++ // Paper start - Allow explosions to damage source ++ return this.explode(entity, damageSource, behavior, x, y, z, power, createFire, explosionSourceType, particle, emitterParticle, soundEvent, null); ++ } ++ public Explosion explode(@Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Level.ExplosionInteraction explosionSourceType, boolean particles, ParticleOptions particle, ParticleOptions emitterParticle, Holder soundEvent, @Nullable Consumer configurator) { ++ // Paper end - Allow explosions to damage source + Explosion.BlockInteraction explosion_effect; + + switch (explosionSourceType.ordinal()) { +@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + + Explosion.BlockInteraction explosion_effect1 = explosion_effect; + Explosion explosion = new Explosion(this, entity, damageSource, behavior, x, y, z, power, createFire, explosion_effect1, particle, emitterParticle, soundEvent); ++ if (configurator != null) configurator.accept(explosion); // Paper - Allow explosions to damage source + + explosion.explode(); + explosion.finalizeExplosion(particles); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -15,8 +105,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + // Paper start + @Override -+ public boolean createExplosion(Entity source, Location loc, float power, boolean setFire, boolean breakBlocks) { -+ return !world.explode(source != null ? ((org.bukkit.craftbukkit.entity.CraftEntity) source).getHandle() : null, loc.getX(), loc.getY(), loc.getZ(), power, setFire, breakBlocks ? net.minecraft.world.level.Level.ExplosionInteraction.MOB : net.minecraft.world.level.Level.ExplosionInteraction.NONE).wasCanceled; ++ public boolean createExplosion(Entity source, Location loc, float power, boolean setFire, boolean breakBlocks, boolean excludeSourceFromDamage) { ++ return !world.explode(source != null ? ((org.bukkit.craftbukkit.entity.CraftEntity) source).getHandle() : null, loc.getX(), loc.getY(), loc.getZ(), power, setFire, breakBlocks ? net.minecraft.world.level.Level.ExplosionInteraction.MOB : net.minecraft.world.level.Level.ExplosionInteraction.NONE, explosion -> { ++ explosion.excludeSourceFromDamage = excludeSourceFromDamage; ++ }).wasCanceled; + } + // Paper end diff --git a/patches/server/Moonrise-optimisation-patches.patch b/patches/server/Moonrise-optimisation-patches.patch index dd2aec71a5..8ba5cedff0 100644 --- a/patches/server/Moonrise-optimisation-patches.patch +++ b/patches/server/Moonrise-optimisation-patches.patch @@ -27719,8 +27719,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/Explosion.java +++ b/src/main/java/net/minecraft/world/level/Explosion.java @@ -0,0 +0,0 @@ public class Explosion { - public float yield; // CraftBukkit end + public boolean excludeSourceFromDamage = true; // Paper - Allow explosions to damage source + // Paper start - optimise collisions + private static final double[] CACHED_RAYS;