From 4feaf2a64c427ac0c05b77d2321b0a8f79f014c6 Mon Sep 17 00:00:00 2001 From: Hypnos Date: Thu, 17 Sep 2026 00:37:42 +0100 Subject: [PATCH 1/6] Fix NPE when clearing a flag with "none" setFlag() legitimately returns null when a StateFlag is parsed from "none" (clearing the flag), but the caller unconditionally called .toString() on the result. Fixes EngineHub/WorldGuard#2305 --- .../com/sk89q/worldguard/commands/region/RegionCommands.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/RegionCommands.java b/worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/RegionCommands.java index 9299ad02b..fec4b883c 100644 --- a/worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/RegionCommands.java +++ b/worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/RegionCommands.java @@ -597,7 +597,9 @@ public void flag(CommandContext args, Actor sender) throws CommandException { if (value != null) { // Set the flag if [value] was given even if [-g group] was given as well try { - value = setFlag(existing, foundFlag, sender, value).toString(); + Object parsedValue = setFlag(existing, foundFlag, sender, value); + // Some flags (e.g. StateFlag) parse "none" to a null value to clear the flag. + value = parsedValue == null ? "none" : parsedValue.toString(); } catch (InvalidFlagFormat e) { throw new CommandException(e.getMessage()); } From 7ec1b8c2bb562d4bb4b90c0232b05ba49ae00c7a Mon Sep 17 00:00:00 2001 From: Hypnos Date: Thu, 17 Sep 2026 00:37:57 +0100 Subject: [PATCH 2/6] Fix recurring EntityChangeBlockEvent NPE event.getBlock() can throw when its underlying Location's world no longer resolves, on some platforms. Guard both listeners against it instead of letting it spam the console. Fixes EngineHub/WorldGuard#2238 --- .../bukkit/listener/EventAbstractionListener.java | 10 +++++++++- .../bukkit/listener/WorldGuardEntityListener.java | 14 ++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/EventAbstractionListener.java b/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/EventAbstractionListener.java index d91114a52..c3a358e89 100644 --- a/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/EventAbstractionListener.java +++ b/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/EventAbstractionListener.java @@ -343,7 +343,15 @@ private void setDelegateEventMaterialOptions(DelegateEvent event, Material fromT @EventHandler(ignoreCancelled = true) public void onEntityChangeBlock(EntityChangeBlockEvent event) { - Block block = event.getBlock(); + Block block; + try { + block = event.getBlock(); + } catch (NullPointerException e) { + // Some platforms can fire this event referencing a block whose location no + // longer resolves to a loaded world. Nothing useful can be done, so bail out. + // See EngineHub/WorldGuard#2238 + return; + } Entity entity = event.getEntity(); Material toType = event.getTo(); Material fromType = block.getType(); diff --git a/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardEntityListener.java b/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardEntityListener.java index 080a68db5..c892843c1 100644 --- a/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardEntityListener.java +++ b/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardEntityListener.java @@ -812,9 +812,19 @@ public void onFoodChange(FoodLevelChangeEvent event) { public void onEntityChangeBlock(EntityChangeBlockEvent event) { Entity ent = event.getEntity(); + Block changedBlock; + try { + changedBlock = event.getBlock(); + } catch (NullPointerException e) { + // Some platforms can fire this event referencing a block whose location no + // longer resolves to a loaded world. Nothing useful can be done, so bail out. + // See EngineHub/WorldGuard#2238 + return; + } + WorldConfiguration wcfg = getWorldConfig(ent.getWorld()); if (ent instanceof FallingBlock) { - Material id = event.getBlock().getType(); + Material id = changedBlock.getType(); if (id == Material.GRAVEL && wcfg.noPhysicsGravel) { event.setCancelled(true); @@ -836,7 +846,7 @@ public void onEntityChangeBlock(EntityChangeBlockEvent event) { return; } if (wcfg.useRegions) { - Location location = event.getBlock().getLocation(); + Location location = changedBlock.getLocation(); if (!StateFlag.test(WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery().queryState(BukkitAdapter.adapt(location), (RegionAssociable) null, Flags.WITHER_DAMAGE))) { event.setCancelled(true); return; From fba010e4544115aa0a1060e745951b2cc85509e1 Mon Sep 17 00:00:00 2001 From: Hypnos Date: Thu, 17 Sep 2026 00:38:12 +0100 Subject: [PATCH 3/6] Fix blacklist log filenames being one month behind Calendar.MONTH is 0-indexed (January = 0); the %m log path token needs it 1-indexed. Fixes EngineHub/WorldGuard#1280 --- .../com/sk89q/worldguard/blacklist/logger/FileHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worldguard-core/src/main/java/com/sk89q/worldguard/blacklist/logger/FileHandler.java b/worldguard-core/src/main/java/com/sk89q/worldguard/blacklist/logger/FileHandler.java index df146c996..d7c4ff26e 100644 --- a/worldguard-core/src/main/java/com/sk89q/worldguard/blacklist/logger/FileHandler.java +++ b/worldguard-core/src/main/java/com/sk89q/worldguard/blacklist/logger/FileHandler.java @@ -121,7 +121,8 @@ public FileHandler(String pathPattern, int cacheSize, String worldName, Logger l } else if (group.matches("%Y")) { rep = String.valueOf(calendar.get(Calendar.YEAR)); } else if (group.matches("%m")) { - rep = String.format("%02d", calendar.get(Calendar.MONTH)); + // Calendar.MONTH is 0-indexed (January = 0), but the %m log path token should be 1-indexed. + rep = String.format("%02d", calendar.get(Calendar.MONTH) + 1); } else if (group.matches("%d")) { rep = String.format("%02d", calendar.get(Calendar.DAY_OF_MONTH)); } else if (group.matches("%W")) { From 3e3d2a3471230b35004cf5be61c8a43b70c7e817 Mon Sep 17 00:00:00 2001 From: Hypnos Date: Thu, 17 Sep 2026 00:38:28 +0100 Subject: [PATCH 4/6] Fix boats destroying item frames/paintings without checking protection RemoveCause.PHYSICS (e.g. a boat colliding with the hanging entity) wasn't handled at all - only EXPLOSION was - so entity-item-frame-destroy, entity-painting-destroy, and their global config equivalents never applied to that removal path. Fixes EngineHub/WorldGuard#1434 --- .../listener/WorldGuardHangingListener.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardHangingListener.java b/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardHangingListener.java index 9d93a5191..517dccf90 100644 --- a/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardHangingListener.java +++ b/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardHangingListener.java @@ -92,13 +92,20 @@ public void onHangingBreak(HangingBreakEvent event) { event.setCancelled(true); } } - } else { - // Explosions from mobs are not covered by HangingBreakByEntity - if (hanging instanceof Painting && wcfg.blockEntityPaintingDestroy - && event.getCause() == RemoveCause.EXPLOSION) { + } else if (event.getCause() == RemoveCause.EXPLOSION || event.getCause() == RemoveCause.PHYSICS) { + // Explosions from mobs, and physics-caused breaks (e.g. a boat colliding + // with the hanging entity), are not covered by HangingBreakByEntityEvent, + // so there's no attacker entity available to check here. + // See EngineHub/WorldGuard#1434 for the PHYSICS case (boats breaking item frames). + if (hanging instanceof Painting + && (wcfg.blockEntityPaintingDestroy + || (wcfg.useRegions + && !StateFlag.test(WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery().queryState(BukkitAdapter.adapt(hanging.getLocation()), (RegionAssociable) null, Flags.ENTITY_PAINTING_DESTROY))))) { event.setCancelled(true); - } else if (hanging instanceof ItemFrame && wcfg.blockEntityItemFrameDestroy - && event.getCause() == RemoveCause.EXPLOSION) { + } else if (hanging instanceof ItemFrame + && (wcfg.blockEntityItemFrameDestroy + || (wcfg.useRegions + && !StateFlag.test(WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery().queryState(BukkitAdapter.adapt(hanging.getLocation()), (RegionAssociable) null, Flags.ENTITY_ITEM_FRAME_DESTROY))))) { event.setCancelled(true); } } From 222442910e933fd11cb6a76f0ddd11a3d0bb6bfe Mon Sep 17 00:00:00 2001 From: Hypnos Date: Thu, 17 Sep 2026 00:39:08 +0100 Subject: [PATCH 5/6] Enforce ender pearl/chorus fruit flags via Canvas's own teleport event Canvas doesn't fire the vanilla PlayerTeleportEvent for entity-driven teleports (confirmed via Canvas's own docs and live testing - zero event delivery for any teleport cause on this platform), so the ENDERPEARL/CHORUS_TELEPORT flags were silently unenforced. Add a listener for Canvas's own EntityTeleportAsyncEvent instead, only registered when that class is actually present at runtime, so it has no effect on non-Canvas platforms. Fixes EngineHub/WorldGuard#2302 --- config/checkstyle/import-control.xml | 1 + worldguard-bukkit/build.gradle.kts | 7 ++ .../libs/canvas-teleport-events.jar | Bin 0 -> 4127 bytes .../worldguard/bukkit/WorldGuardPlugin.java | 26 +++++ .../listener/WorldGuardCanvasListener.java | 108 ++++++++++++++++++ 5 files changed, 142 insertions(+) create mode 100644 worldguard-bukkit/libs/canvas-teleport-events.jar create mode 100644 worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardCanvasListener.java diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index abb251d1c..f51b28042 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -31,6 +31,7 @@ + diff --git a/worldguard-bukkit/build.gradle.kts b/worldguard-bukkit/build.gradle.kts index efa607c52..ad1d211eb 100644 --- a/worldguard-bukkit/build.gradle.kts +++ b/worldguard-bukkit/build.gradle.kts @@ -20,6 +20,13 @@ dependencies { exclude("org.slf4j", "slf4j-api") exclude("junit", "junit") } + // Vendored locally: just the 3 io.canvasmc.canvas.event.*TeleportAsyncEvent* class + // files (extracted from canvas-api), not the whole canvas-api jar - that jar bundles + // its own full copy of org.bukkit.* compiled for a newer JDK, which conflicts with + // paperApi on the compile classpath. CanvasMC doesn't publish canvas-api for this old + // a version line anyway. Only used at compile time - see WorldGuardCanvasListener + // and WorldGuardPlugin#isCanvas(). + "compileOnly"(files("libs/canvas-teleport-events.jar")) "implementation"(libs.paperLib) "implementation"(libs.bstats.bukkit) diff --git a/worldguard-bukkit/libs/canvas-teleport-events.jar b/worldguard-bukkit/libs/canvas-teleport-events.jar new file mode 100644 index 0000000000000000000000000000000000000000..575f094adbabfc2794b7d8a43cf830cefbd0e328 GIT binary patch literal 4127 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 oeV_5@-|S!p9$G$$ canvas = LazyReference.from(() -> { + try { + Class.forName("io.canvasmc.canvas.event.EntityTeleportAsyncEvent"); + return true; + } catch (ClassNotFoundException e) { + return false; + } + }); + + /** + * Whether the server exposes CanvasMC's own teleport event API + * ({@code io.canvasmc.canvas.event.EntityTeleportAsyncEvent}). Canvas (a Folia + * fork) documents that the vanilla {@link org.bukkit.event.player.PlayerTeleportEvent} + * does not reliably fire for entity-driven teleports under region threading, and + * added this replacement instead of fixing the old API. + * + * @see Canvas events docs + */ + public boolean isCanvas() { + return canvas.getValue(); + } + } diff --git a/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardCanvasListener.java b/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardCanvasListener.java new file mode 100644 index 000000000..68db7108e --- /dev/null +++ b/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardCanvasListener.java @@ -0,0 +1,108 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.bukkit.listener; + +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldguard.LocalPlayer; +import com.sk89q.worldguard.WorldGuard; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.config.ConfigurationManager; +import com.sk89q.worldguard.config.WorldConfiguration; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.Flags; +import com.sk89q.worldguard.protection.flags.StateFlag; +import com.sk89q.worldguard.protection.regions.RegionQuery; +import io.canvasmc.canvas.event.EntityTeleportAsyncEvent; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + +/** + * Re-implements the ENDERPEARL/CHORUS_TELEPORT flag checks using Canvas's own + * {@link EntityTeleportAsyncEvent} instead of the vanilla + * {@link org.bukkit.event.player.PlayerTeleportEvent}. + * + *

Canvas (a Folia fork) documents that the vanilla event "doesn't function" for + * entity-driven teleports under region threading, and added this event as a + * replacement rather than fixing the old API. This listener is only registered when + * {@link WorldGuardPlugin#isCanvas()} is true, so it has no effect on other platforms.

+ * + * @see Canvas events docs + */ +public class WorldGuardCanvasListener extends AbstractListener { + + public WorldGuardCanvasListener(WorldGuardPlugin plugin) { + super(plugin); + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onEntityTeleportAsync(EntityTeleportAsyncEvent event) { + if (!(event.getEntity() instanceof Player player)) { + return; + } + if (com.sk89q.worldguard.bukkit.util.Entities.isNPC(player)) { + return; + } + + TeleportCause cause = event.getCause(); + StateFlag flag; + if (cause == TeleportCause.ENDER_PEARL) { + flag = Flags.ENDERPEARL; + } else if (cause == TeleportCause.CHORUS_FRUIT) { + flag = Flags.CHORUS_TELEPORT; + } else { + return; + } + + LocalPlayer localPlayer = getPlugin().wrapPlayer(player); + ConfigurationManager cfg = getConfig(); + WorldConfiguration wcfg = getWorldConfig(player.getWorld()); + + if (!wcfg.useRegions || !cfg.usePlayerTeleports) { + return; + } + if (WorldGuard.getInstance().getPlatform().getSessionManager().hasBypass(localPlayer, localPlayer.getWorld())) { + return; + } + + RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery(); + ApplicableRegionSet setFrom = query.getApplicableRegions(BukkitAdapter.adapt(event.getFrom())); + ApplicableRegionSet setTo = query.getApplicableRegions(BukkitAdapter.adapt(event.getTo())); + + boolean cancel = false; + String message = null; + if (!setFrom.testState(localPlayer, flag)) { + cancel = true; + message = setFrom.queryValue(localPlayer, Flags.EXIT_DENY_MESSAGE); + } else if (!setTo.testState(localPlayer, flag)) { + cancel = true; + message = setTo.queryValue(localPlayer, Flags.ENTRY_DENY_MESSAGE); + } + + if (cancel) { + if (message != null && !message.isEmpty()) { + player.sendMessage(message); + } + event.setCancelled(true); + } + } + +} From b253a5f194d8016ca70ad452a67c61fc4c5ff50b Mon Sep 17 00:00:00 2001 From: Hypnos Date: Thu, 17 Sep 2026 00:39:34 +0100 Subject: [PATCH 6/6] Refund the ender pearl/chorus fruit when a teleport is denied Both are consumed from the player's inventory before the teleport event fires (on throw / on eating respectively), so denying the teleport was leaving the player down an item for nothing. Skipped in creative mode, matching the existing pattern for XP bottles in EventAbstractionListener#onExpBottle. --- .../bukkit/listener/WorldGuardCanvasListener.java | 8 ++++++++ .../bukkit/listener/WorldGuardPlayerListener.java | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardCanvasListener.java b/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardCanvasListener.java index 68db7108e..69adc1bd5 100644 --- a/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardCanvasListener.java +++ b/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardCanvasListener.java @@ -30,10 +30,13 @@ import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.regions.RegionQuery; import io.canvasmc.canvas.event.EntityTeleportAsyncEvent; +import org.bukkit.GameMode; +import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.bukkit.inventory.ItemStack; /** * Re-implements the ENDERPEARL/CHORUS_TELEPORT flag checks using Canvas's own @@ -102,6 +105,11 @@ public void onEntityTeleportAsync(EntityTeleportAsyncEvent event) { player.sendMessage(message); } event.setCancelled(true); + // The pearl/fruit is consumed before this event fires, so give it back. + if (player.getGameMode() != GameMode.CREATIVE) { + Material refund = cause == TeleportCause.ENDER_PEARL ? Material.ENDER_PEARL : Material.CHORUS_FRUIT; + player.getInventory().addItem(new ItemStack(refund, 1)); + } } } diff --git a/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardPlayerListener.java b/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardPlayerListener.java index 1656ab323..da08126d7 100644 --- a/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardPlayerListener.java +++ b/worldguard-bukkit/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardPlayerListener.java @@ -382,6 +382,10 @@ public void onPlayerTeleport(PlayerTeleportEvent event) { player.sendMessage(message); } event.setCancelled(true); + // The pearl is consumed on throw, before this event fires, so give it back. + if (player.getGameMode() != org.bukkit.GameMode.CREATIVE) { + player.getInventory().addItem(new ItemStack(Material.ENDER_PEARL, 1)); + } return; } } @@ -401,6 +405,10 @@ public void onPlayerTeleport(PlayerTeleportEvent event) { player.sendMessage(message); } event.setCancelled(true); + // The fruit is consumed on eating, before this event fires, so give it back. + if (player.getGameMode() != org.bukkit.GameMode.CREATIVE) { + player.getInventory().addItem(new ItemStack(Material.CHORUS_FRUIT, 1)); + } return; } }