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); + // 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/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; 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); } } 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; } } 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")) { 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()); }