From cc2458fd04ead2c73a5dd444a5d32e6afb074d32 Mon Sep 17 00:00:00 2001 From: Biquaternions Date: Wed, 22 Jul 2026 13:57:37 -0500 Subject: [PATCH 1/3] Event for end portal creation --- .../bukkit/event/world/PortalCreateEvent.java | 7 +++++- .../world/item/EnderEyeItem.java.patch | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/paper-api/src/main/java/org/bukkit/event/world/PortalCreateEvent.java b/paper-api/src/main/java/org/bukkit/event/world/PortalCreateEvent.java index 0bf1d29747be..8046ee1ec1cc 100644 --- a/paper-api/src/main/java/org/bukkit/event/world/PortalCreateEvent.java +++ b/paper-api/src/main/java/org/bukkit/event/world/PortalCreateEvent.java @@ -107,6 +107,11 @@ public enum CreateReason { * When the target end platform is created as a result of a player * entering an end portal. */ - END_PLATFORM + END_PLATFORM, + /** + * When the blocks inside an end portal are created due to an end portal + * frame being completed with all ender eyes. + */ + ENDER_EYE } } diff --git a/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch index 2e3644f19f92..d523740d0fc7 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch @@ -12,6 +12,30 @@ Block.pushEntitiesUp(targetState, newState, level, pos); level.setBlock(pos, newState, Block.UPDATE_CLIENTS); level.updateNeighbourForOutputSignal(pos, Blocks.END_PORTAL_FRAME); +@@ -56,6 +_,23 @@ + if (match != null) { + BlockPos blockPos = match.getFrontTopLeft().offset(-3, 0, -3); + ++ // Paper start - Trigger PortalCreateEvent on end portal creation ++ org.bukkit.craftbukkit.util.BlockStateListPopulator populator = new org.bukkit.craftbukkit.util.BlockStateListPopulator(level.getMinecraftWorld()); ++ // Copy below for loop ++ for (int x = 0; x < 3; x++) { ++ for (int z = 0; z < 3; z++) { ++ BlockPos portalBlockPos = blockPos.offset(x, 0, z); ++ populator.setBlock(portalBlockPos, Blocks.END_PORTAL.defaultBlockState(), Block.UPDATE_CLIENTS); ++ } ++ } ++ Player portalCreator = context.getPlayer(); ++ org.bukkit.World bworld = level.getMinecraftWorld().getWorld(); ++ org.bukkit.event.world.PortalCreateEvent event = new org.bukkit.event.world.PortalCreateEvent((java.util.List) (java.util.List) populator.getSnapshotBlocks(), bworld, (portalCreator == null) ? null : portalCreator.getBukkitEntity(), org.bukkit.event.world.PortalCreateEvent.CreateReason.ENDER_EYE); ++ level.getMinecraftWorld().getServer().server.getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ return InteractionResult.PASS; ++ } ++ // Paper end - Trigger PortalCreateEvent on end portal creation + for (int x = 0; x < 3; x++) { + for (int z = 0; z < 3; z++) { + BlockPos portalBlockPos = blockPos.offset(x, 0, z); @@ -64,7 +_,27 @@ } } From d9ad4cfa13c8ec5935ba14063e78e052021ea919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9D=91=A9=F0=9D=92=8A=F0=9D=92=92=F0=9D=92=96?= =?UTF-8?q?=F0=9D=92=82=F0=9D=92=95=F0=9D=92=86=F0=9D=92=93=F0=9D=92=8F?= =?UTF-8?q?=F0=9D=92=8A=F0=9D=92=90=F0=9D=92=8F=F0=9D=92=94?= <11415969+Biquaternions@users.noreply.github.com> Date: Mon, 27 Jul 2026 11:04:30 -0500 Subject: [PATCH 2/3] Call the event directly Co-authored-by: Pedro <3602279+Doc94@users.noreply.github.com> --- .../sources/net/minecraft/world/item/EnderEyeItem.java.patch | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch index d523740d0fc7..399ffbe4000f 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch @@ -28,8 +28,7 @@ + Player portalCreator = context.getPlayer(); + org.bukkit.World bworld = level.getMinecraftWorld().getWorld(); + org.bukkit.event.world.PortalCreateEvent event = new org.bukkit.event.world.PortalCreateEvent((java.util.List) (java.util.List) populator.getSnapshotBlocks(), bworld, (portalCreator == null) ? null : portalCreator.getBukkitEntity(), org.bukkit.event.world.PortalCreateEvent.CreateReason.ENDER_EYE); -+ level.getMinecraftWorld().getServer().server.getPluginManager().callEvent(event); -+ if (event.isCancelled()) { ++ if (!event.callEvent()) { + return InteractionResult.PASS; + } + // Paper end - Trigger PortalCreateEvent on end portal creation From 687a4c73d9f6b696b8ac0110efa13be32c5ba949 Mon Sep 17 00:00:00 2001 From: Biquaternions Date: Tue, 28 Jul 2026 18:39:13 -0500 Subject: [PATCH 3/3] Use block populator to create/destroy blocks --- .../world/item/EnderEyeItem.java.patch | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch index 399ffbe4000f..07c61a24104a 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch @@ -12,32 +12,29 @@ Block.pushEntitiesUp(targetState, newState, level, pos); level.setBlock(pos, newState, Block.UPDATE_CLIENTS); level.updateNeighbourForOutputSignal(pos, Blocks.END_PORTAL_FRAME); -@@ -56,6 +_,23 @@ +@@ -56,15 +_,45 @@ if (match != null) { BlockPos blockPos = match.getFrontTopLeft().offset(-3, 0, -3); ++ org.bukkit.craftbukkit.util.BlockStateListPopulator populator = new org.bukkit.craftbukkit.util.BlockStateListPopulator(level.getMinecraftWorld()); // Paper + for (int x = 0; x < 3; x++) { + for (int z = 0; z < 3; z++) { + BlockPos portalBlockPos = blockPos.offset(x, 0, z); +- level.destroyBlock(portalBlockPos, true, null); +- level.setBlock(portalBlockPos, Blocks.END_PORTAL.defaultBlockState(), Block.UPDATE_CLIENTS); ++ populator.destroyBlock(portalBlockPos, true, null); // Paper ++ populator.setBlock(portalBlockPos, Blocks.END_PORTAL.defaultBlockState(), Block.UPDATE_CLIENTS); // Paper + } + } + // Paper start - Trigger PortalCreateEvent on end portal creation -+ org.bukkit.craftbukkit.util.BlockStateListPopulator populator = new org.bukkit.craftbukkit.util.BlockStateListPopulator(level.getMinecraftWorld()); -+ // Copy below for loop -+ for (int x = 0; x < 3; x++) { -+ for (int z = 0; z < 3; z++) { -+ BlockPos portalBlockPos = blockPos.offset(x, 0, z); -+ populator.setBlock(portalBlockPos, Blocks.END_PORTAL.defaultBlockState(), Block.UPDATE_CLIENTS); -+ } -+ } + Player portalCreator = context.getPlayer(); + org.bukkit.World bworld = level.getMinecraftWorld().getWorld(); + org.bukkit.event.world.PortalCreateEvent event = new org.bukkit.event.world.PortalCreateEvent((java.util.List) (java.util.List) populator.getSnapshotBlocks(), bworld, (portalCreator == null) ? null : portalCreator.getBukkitEntity(), org.bukkit.event.world.PortalCreateEvent.CreateReason.ENDER_EYE); + if (!event.callEvent()) { + return InteractionResult.PASS; + } ++ populator.placeBlocks(state -> level.destroyBlock(state.getPosition(), true, null)); + // Paper end - Trigger PortalCreateEvent on end portal creation - for (int x = 0; x < 3; x++) { - for (int z = 0; z < 3; z++) { - BlockPos portalBlockPos = blockPos.offset(x, 0, z); -@@ -64,7 +_,27 @@ - } - } - level.globalLevelEvent(LevelEvent.SOUND_END_PORTAL_SPAWN, blockPos.offset(1, 0, 1), 0); + // CraftBukkit start - Use relative location for far away sounds