SPIGOT-7967, #887: Call explode events for EXPLODE effect (enchantments) and non block changes (mobGriefing false)

This commit is contained in:
Doc 2025-01-15 19:14:37 +11:00 committed by md_5
parent 03a8c14939
commit c16b696e41
No known key found for this signature in database
GPG Key ID: E8E901AC7C617C11
3 changed files with 73 additions and 46 deletions

View File

@ -0,0 +1,11 @@
--- a/net/minecraft/world/item/enchantment/effects/ExplodeEffect.java
+++ b/net/minecraft/world/item/enchantment/effects/ExplodeEffect.java
@@ -40,7 +40,7 @@
@Nullable
private DamageSource getDamageSource(Entity entity, Vec3D vec3d) {
- return this.damageType.isEmpty() ? null : (this.attributeToUser ? new DamageSource((Holder) this.damageType.get(), entity) : new DamageSource((Holder) this.damageType.get(), vec3d));
+ return this.damageType.isEmpty() ? (entity == null ? null : entity.level().damageSources().explosion(null).customCausingEntityDamager(entity)) : (this.attributeToUser ? new DamageSource((Holder) this.damageType.get(), entity) : new DamageSource((Holder) this.damageType.get(), vec3d)); // CraftBukkit - copy from explosion default damagesource to allow tracking entity behind the effect
}
@Override

View File

@ -1,6 +1,6 @@
--- a/net/minecraft/world/level/ServerExplosion.java --- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java
@@ -35,6 +35,17 @@ @@ -35,6 +35,13 @@
import net.minecraft.world.phys.MovingObjectPosition; import net.minecraft.world.phys.MovingObjectPosition;
import net.minecraft.world.phys.Vec3D; import net.minecraft.world.phys.Vec3D;
@ -9,16 +9,12 @@
+import net.minecraft.world.entity.boss.enderdragon.EntityEnderDragon; +import net.minecraft.world.entity.boss.enderdragon.EntityEnderDragon;
+import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.Blocks;
+import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.craftbukkit.util.CraftLocation;
+import org.bukkit.event.entity.EntityExplodeEvent;
+import org.bukkit.Location;
+import org.bukkit.event.block.BlockExplodeEvent;
+// CraftBukkit end +// CraftBukkit end
+ +
public class ServerExplosion implements Explosion { public class ServerExplosion implements Explosion {
private static final ExplosionDamageCalculator EXPLOSION_DAMAGE_CALCULATOR = new ExplosionDamageCalculator(); private static final ExplosionDamageCalculator EXPLOSION_DAMAGE_CALCULATOR = new ExplosionDamageCalculator();
@@ -50,16 +61,21 @@ @@ -50,16 +57,21 @@
private final DamageSource damageSource; private final DamageSource damageSource;
private final ExplosionDamageCalculator damageCalculator; private final ExplosionDamageCalculator damageCalculator;
private final Map<EntityHuman, Vec3D> hitPlayers = new HashMap(); private final Map<EntityHuman, Vec3D> hitPlayers = new HashMap();
@ -41,7 +37,7 @@
} }
private ExplosionDamageCalculator makeDamageCalculator(@Nullable Entity entity) { private ExplosionDamageCalculator makeDamageCalculator(@Nullable Entity entity) {
@@ -195,7 +211,35 @@ @@ -195,7 +207,35 @@
float f2 = !flag && f1 == 0.0F ? 0.0F : getSeenPercent(this.center, entity); float f2 = !flag && f1 == 0.0F ? 0.0F : getSeenPercent(this.center, entity);
if (flag) { if (flag) {
@ -78,7 +74,7 @@
} }
double d5 = (1.0D - d0) * (double) f2 * (double) f1; double d5 = (1.0D - d0) * (double) f2 * (double) f1;
@@ -214,6 +258,17 @@ @@ -214,6 +254,17 @@
d3 *= d6; d3 *= d6;
Vec3D vec3d = new Vec3D(d1, d2, d3); Vec3D vec3d = new Vec3D(d1, d2, d3);
@ -96,45 +92,15 @@
entity.push(vec3d); entity.push(vec3d);
if (entity instanceof EntityHuman) { if (entity instanceof EntityHuman) {
EntityHuman entityhuman = (EntityHuman) entity; EntityHuman entityhuman = (EntityHuman) entity;
@@ -235,10 +290,62 @@ @@ -235,10 +286,31 @@
List<ServerExplosion.a> list1 = new ArrayList(); List<ServerExplosion.a> list1 = new ArrayList();
SystemUtils.shuffle(list, this.level.random); SystemUtils.shuffle(list, this.level.random);
+ // CraftBukkit start + // CraftBukkit start
+ org.bukkit.World bworld = this.level.getWorld(); + List<org.bukkit.block.Block> bukkitBlocks = CraftEventFactory.handleExplodeEvent(this, list);
+ Location location = CraftLocation.toBukkit(this.center, bworld);
+
+ List<org.bukkit.block.Block> blockList = new ObjectArrayList<>();
+ for (int i1 = list.size() - 1; i1 >= 0; i1--) {
+ BlockPosition cpos = list.get(i1);
+ org.bukkit.block.Block bblock = bworld.getBlockAt(cpos.getX(), cpos.getY(), cpos.getZ());
+ if (!bblock.getType().isAir()) {
+ blockList.add(bblock);
+ }
+ }
+
+ List<org.bukkit.block.Block> bukkitBlocks;
+
+ if (this.source != null) {
+ EntityExplodeEvent event = CraftEventFactory.callEntityExplodeEvent(this.source, blockList, this.yield, getBlockInteraction());
+ this.wasCanceled = event.isCancelled();
+ bukkitBlocks = event.blockList();
+ this.yield = event.getYield();
+ } else {
+ org.bukkit.block.Block block = location.getBlock();
+ org.bukkit.block.BlockState blockState = (damageSource.getDirectBlockState() != null) ? damageSource.getDirectBlockState() : block.getState();
+ BlockExplodeEvent event = CraftEventFactory.callBlockExplodeEvent(block, blockState, blockList, this.yield, getBlockInteraction());
+ this.wasCanceled = event.isCancelled();
+ bukkitBlocks = event.blockList();
+ this.yield = event.getYield();
+ }
+ +
+ list.clear(); + list.clear();
+ + list.addAll(bukkitBlocks.stream().map(bblock -> new BlockPosition(bblock.getX(), bblock.getY(), bblock.getZ())).toList());
+ for (org.bukkit.block.Block bblock : bukkitBlocks) {
+ BlockPosition coords = new BlockPosition(bblock.getX(), bblock.getY(), bblock.getZ());
+ list.add(coords);
+ }
+ +
+ if (this.wasCanceled) { + if (this.wasCanceled) {
+ return; + return;
@ -148,9 +114,8 @@
+ IBlockData iblockdata = this.level.getBlockState(blockposition); + IBlockData iblockdata = this.level.getBlockState(blockposition);
+ Block block = iblockdata.getBlock(); + Block block = iblockdata.getBlock();
+ if (block instanceof net.minecraft.world.level.block.BlockTNT) { + if (block instanceof net.minecraft.world.level.block.BlockTNT) {
+ Entity sourceEntity = source == null ? null : source; + BlockPosition sourceBlock = source == null ? BlockPosition.containing(this.center) : null;
+ BlockPosition sourceBlock = sourceEntity == null ? BlockPosition.containing(this.center) : null; + if (!CraftEventFactory.callTNTPrimeEvent(this.level, blockposition, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.EXPLOSION, source, sourceBlock)) {
+ if (!CraftEventFactory.callTNTPrimeEvent(this.level, blockposition, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.EXPLOSION, sourceEntity, sourceBlock)) {
+ this.level.sendBlockUpdated(blockposition, Blocks.AIR.defaultBlockState(), iblockdata, 3); // Update the block on the client + this.level.sendBlockUpdated(blockposition, Blocks.AIR.defaultBlockState(), iblockdata, 3); // Update the block on the client
+ continue; + continue;
+ } + }
@ -159,7 +124,7 @@
this.level.getBlockState(blockposition).onExplosionHit(this.level, blockposition, this, (itemstack, blockposition1) -> { this.level.getBlockState(blockposition).onExplosionHit(this.level, blockposition, this, (itemstack, blockposition1) -> {
addOrAppendStack(list1, itemstack, blockposition1); addOrAppendStack(list1, itemstack, blockposition1);
@@ -262,13 +369,22 @@ @@ -262,13 +334,22 @@
BlockPosition blockposition = (BlockPosition) iterator.next(); BlockPosition blockposition = (BlockPosition) iterator.next();
if (this.level.random.nextInt(3) == 0 && this.level.getBlockState(blockposition).isAir() && this.level.getBlockState(blockposition.below()).isSolidRender()) { if (this.level.random.nextInt(3) == 0 && this.level.getBlockState(blockposition).isAir() && this.level.getBlockState(blockposition.below()).isSolidRender()) {
@ -183,7 +148,23 @@
this.level.gameEvent(this.source, (Holder) GameEvent.EXPLODE, this.center); this.level.gameEvent(this.source, (Holder) GameEvent.EXPLODE, this.center);
List<BlockPosition> list = this.calculateExplodedPositions(); List<BlockPosition> list = this.calculateExplodedPositions();
@@ -288,6 +404,7 @@ @@ -279,7 +360,15 @@
gameprofilerfiller.push("explosion_blocks");
this.interactWithBlocks(list);
gameprofilerfiller.pop();
+ // CraftBukkit start - handle KEEP effect
+ } else {
+ SystemUtils.shuffle(list, this.level.random); // CraftBukkit - Copy from calculateExplodedPositions
+ List<org.bukkit.block.Block> bukkitBlocks = CraftEventFactory.handleExplodeEvent(this, list);
+
+ list.clear();
+ list.addAll(bukkitBlocks.stream().map(bblock -> new BlockPosition(bblock.getX(), bblock.getY(), bblock.getZ())).toList());
}
+ // CraftBukkit end
if (this.fire) {
this.createFire(list);
@@ -288,6 +377,7 @@
} }
private static void addOrAppendStack(List<ServerExplosion.a> list, ItemStack itemstack, BlockPosition blockposition) { private static void addOrAppendStack(List<ServerExplosion.a> list, ItemStack itemstack, BlockPosition blockposition) {

View File

@ -5,6 +5,7 @@ import com.google.common.base.Functions;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.ArrayList; import java.util.ArrayList;
@ -66,6 +67,7 @@ import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.level.ChunkCoordIntPair; import net.minecraft.world.level.ChunkCoordIntPair;
import net.minecraft.world.level.Explosion; import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.GeneratorAccess; import net.minecraft.world.level.GeneratorAccess;
import net.minecraft.world.level.ServerExplosion;
import net.minecraft.world.level.World; import net.minecraft.world.level.World;
import net.minecraft.world.level.block.entity.TileEntitySign; import net.minecraft.world.level.block.entity.TileEntitySign;
import net.minecraft.world.level.block.state.IBlockData; import net.minecraft.world.level.block.state.IBlockData;
@ -108,6 +110,7 @@ import org.bukkit.craftbukkit.inventory.CraftInventoryCrafting;
import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.inventory.CraftItemType; import org.bukkit.craftbukkit.inventory.CraftItemType;
import org.bukkit.craftbukkit.potion.CraftPotionUtil; import org.bukkit.craftbukkit.potion.CraftPotionUtil;
import org.bukkit.craftbukkit.util.CraftLocation;
import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.craftbukkit.util.CraftVector; import org.bukkit.craftbukkit.util.CraftVector;
import org.bukkit.entity.AbstractHorse; import org.bukkit.entity.AbstractHorse;
@ -1877,6 +1880,38 @@ public class CraftEventFactory {
return !event.isCancelled(); return !event.isCancelled();
} }
public static List<org.bukkit.block.Block> handleExplodeEvent(ServerExplosion serverExplosion, List<BlockPosition> blockPositions) {
// First convert the blockPositionList related to the explosion to Bukkit objects
org.bukkit.World bworld = serverExplosion.level().getWorld();
List<org.bukkit.block.Block> blockList = new ObjectArrayList<>();
for (int i1 = blockPositions.size() - 1; i1 >= 0; i1--) {
BlockPosition cpos = blockPositions.get(i1);
org.bukkit.block.Block bblock = bworld.getBlockAt(cpos.getX(), cpos.getY(), cpos.getZ());
if (!bblock.getType().isAir()) {
blockList.add(bblock);
}
}
// Handle based on explosion or damage source whether we need to call EntityExplodeEvent
if (serverExplosion.getDirectSourceEntity() != null || serverExplosion.getDamageSource().getCausingDamager() != null) {
EntityExplodeEvent event = CraftEventFactory.callEntityExplodeEvent((serverExplosion.getDirectSourceEntity() != null) ? serverExplosion.getDirectSourceEntity() : serverExplosion.getDamageSource().getCausingDamager(), blockList, serverExplosion.yield, serverExplosion.getBlockInteraction());
serverExplosion.wasCanceled = event.isCancelled();
serverExplosion.yield = event.getYield();
return event.blockList();
}
// Else BlockExplodeEvent when entity not found in previous if statement
Location location = CraftLocation.toBukkit(serverExplosion.center(), bworld);
org.bukkit.block.Block block = location.getBlock();
org.bukkit.block.BlockState blockState = (serverExplosion.getDamageSource().getDirectBlockState() != null) ? serverExplosion.getDamageSource().getDirectBlockState() : block.getState();
BlockExplodeEvent event = CraftEventFactory.callBlockExplodeEvent(block, blockState, blockList, serverExplosion.yield, serverExplosion.getBlockInteraction());
serverExplosion.wasCanceled = event.isCancelled();
serverExplosion.yield = event.getYield();
return event.blockList();
}
public static EntityExplodeEvent callEntityExplodeEvent(Entity entity, List<Block> blocks, float yield, Explosion.Effect effect) { public static EntityExplodeEvent callEntityExplodeEvent(Entity entity, List<Block> blocks, float yield, Explosion.Effect effect) {
EntityExplodeEvent event = new EntityExplodeEvent(entity.getBukkitEntity(), entity.getBukkitEntity().getLocation(), blocks, yield, CraftExplosionResult.toBukkit(effect)); EntityExplodeEvent event = new EntityExplodeEvent(entity.getBukkitEntity(), entity.getBukkitEntity().getLocation(), blocks, yield, CraftExplosionResult.toBukkit(effect));
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);