diff --git a/paper-api/src/main/java/io/papermc/paper/event/entity/GolemConstructEvent.java b/paper-api/src/main/java/io/papermc/paper/event/entity/GolemConstructEvent.java new file mode 100644 index 000000000000..5f466ed97c29 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/event/entity/GolemConstructEvent.java @@ -0,0 +1,66 @@ +package io.papermc.paper.event.entity; + +import org.bukkit.block.Block; +import org.bukkit.entity.Golem; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; +import org.bukkit.event.entity.EntitySpawnEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Unmodifiable; +import org.jspecify.annotations.NullMarked; +import java.util.List; + +/** + * Called just before a {@link Golem} spawns due to a pattern of blocks being constructed. + *
+ * Note: This event is fired before {@link EntitySpawnEvent}, before the golem is added to the world, + * the success of this event does not guarantee the golem will actually spawn. + */ +@NullMarked +public class GolemConstructEvent extends EntityEvent implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final List blocks; + private boolean cancelled; + + @ApiStatus.Internal + public GolemConstructEvent(Golem golem, List blocks) { + super(golem); + this.blocks = List.copyOf(blocks); + } + + @Override + public Golem getEntity() { + return (Golem) super.getEntity(); + } + + /** + * Get an immutable list of the blocks for this golem + * + * @return the golem blocks + */ + public @Unmodifiable List getBlocks() { + return blocks; + } + + @Override + public void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public HandlerList getHandlers() { + return HANDLER_LIST; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } +} diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CarvedPumpkinBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CarvedPumpkinBlock.java.patch index 53f2111574c8..ce9a06013c66 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CarvedPumpkinBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CarvedPumpkinBlock.java.patch @@ -8,7 +8,7 @@ this.replaceCopperBlockWithChest(level, copperGolemMatch); copperGolem.spawn(this.getWeatherStateFromPattern(copperGolemMatch)); } -@@ -105,9 +_,22 @@ +@@ -105,9 +_,32 @@ } private static void spawnGolemInWorld(final Level level, final BlockPattern.BlockPatternMatch match, final Entity golem, final BlockPos spawnPos) { @@ -17,6 +17,16 @@ golem.snapTo(spawnPos.getX() + 0.5, spawnPos.getY() + 0.05, spawnPos.getZ() + 0.5, 0.0F, 0.0F); - level.addFreshEntity(golem); + // Paper start ++ java.util.List blocks = new java.util.ArrayList<>(); ++ for (int x = 0; x < match.getWidth(); x++) { ++ for (int y = 0; y < match.getHeight(); y++) { ++ BlockInWorld block = match.getBlock(x, y, 0); ++ blocks.add(org.bukkit.craftbukkit.block.CraftBlock.at(level, block.getPos())); ++ } ++ } ++ if (!new io.papermc.paper.event.entity.GolemConstructEvent((org.bukkit.entity.Golem) golem.getBukkitEntity(), blocks).callEvent()) { ++ return; ++ } + org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; + if (golem.getType() == net.minecraft.world.entity.EntityType.SNOW_GOLEM) { + spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BUILD_SNOWMAN;