001/* 002 * PlotSquared, a land and world management plugin for Minecraft. 003 * Copyright (C) IntellectualSites <https://intellectualsites.com> 004 * Copyright (C) IntellectualSites team and contributors 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 018 */ 019package com.plotsquared.bukkit.listener; 020 021import com.destroystokyo.paper.MaterialTags; 022import com.google.common.base.Charsets; 023import com.google.inject.Inject; 024import com.plotsquared.bukkit.player.BukkitPlayer; 025import com.plotsquared.bukkit.util.BukkitEntityUtil; 026import com.plotsquared.bukkit.util.BukkitUtil; 027import com.plotsquared.bukkit.util.UpdateUtility; 028import com.plotsquared.core.PlotSquared; 029import com.plotsquared.core.configuration.Settings; 030import com.plotsquared.core.configuration.caption.Caption; 031import com.plotsquared.core.configuration.caption.TranslatableCaption; 032import com.plotsquared.core.listener.PlayerBlockEventType; 033import com.plotsquared.core.listener.PlotListener; 034import com.plotsquared.core.location.Location; 035import com.plotsquared.core.permissions.Permission; 036import com.plotsquared.core.player.ConsolePlayer; 037import com.plotsquared.core.player.MetaDataAccess; 038import com.plotsquared.core.player.PlayerMetaDataKeys; 039import com.plotsquared.core.player.PlotPlayer; 040import com.plotsquared.core.plot.Plot; 041import com.plotsquared.core.plot.PlotArea; 042import com.plotsquared.core.plot.PlotId; 043import com.plotsquared.core.plot.PlotInventory; 044import com.plotsquared.core.plot.flag.FlagContainer; 045import com.plotsquared.core.plot.flag.implementations.AnimalInteractFlag; 046import com.plotsquared.core.plot.flag.implementations.BlockedCmdsFlag; 047import com.plotsquared.core.plot.flag.implementations.ChatFlag; 048import com.plotsquared.core.plot.flag.implementations.DenyPortalTravelFlag; 049import com.plotsquared.core.plot.flag.implementations.DenyPortalsFlag; 050import com.plotsquared.core.plot.flag.implementations.DenyTeleportFlag; 051import com.plotsquared.core.plot.flag.implementations.DoneFlag; 052import com.plotsquared.core.plot.flag.implementations.DropProtectionFlag; 053import com.plotsquared.core.plot.flag.implementations.EditSignFlag; 054import com.plotsquared.core.plot.flag.implementations.HangingBreakFlag; 055import com.plotsquared.core.plot.flag.implementations.HangingPlaceFlag; 056import com.plotsquared.core.plot.flag.implementations.HostileInteractFlag; 057import com.plotsquared.core.plot.flag.implementations.InteractionInteractFlag; 058import com.plotsquared.core.plot.flag.implementations.ItemDropFlag; 059import com.plotsquared.core.plot.flag.implementations.KeepInventoryFlag; 060import com.plotsquared.core.plot.flag.implementations.LecternReadBookFlag; 061import com.plotsquared.core.plot.flag.implementations.MiscInteractFlag; 062import com.plotsquared.core.plot.flag.implementations.PlayerInteractFlag; 063import com.plotsquared.core.plot.flag.implementations.PreventCreativeCopyFlag; 064import com.plotsquared.core.plot.flag.implementations.TamedInteractFlag; 065import com.plotsquared.core.plot.flag.implementations.TileDropFlag; 066import com.plotsquared.core.plot.flag.implementations.UntrustedVisitFlag; 067import com.plotsquared.core.plot.flag.implementations.UseFlag; 068import com.plotsquared.core.plot.flag.implementations.VehicleBreakFlag; 069import com.plotsquared.core.plot.flag.implementations.VehicleUseFlag; 070import com.plotsquared.core.plot.flag.implementations.VillagerInteractFlag; 071import com.plotsquared.core.plot.flag.types.BlockTypeWrapper; 072import com.plotsquared.core.plot.world.PlotAreaManager; 073import com.plotsquared.core.util.EventDispatcher; 074import com.plotsquared.core.util.MathMan; 075import com.plotsquared.core.util.PlotFlagUtil; 076import com.plotsquared.core.util.PremiumVerification; 077import com.plotsquared.core.util.entity.EntityCategories; 078import com.plotsquared.core.util.task.TaskManager; 079import com.plotsquared.core.util.task.TaskTime; 080import com.sk89q.worldedit.WorldEdit; 081import com.sk89q.worldedit.bukkit.BukkitAdapter; 082import com.sk89q.worldedit.util.Enums; 083import com.sk89q.worldedit.world.block.BlockType; 084import com.sk89q.worldedit.world.block.BlockTypes; 085import io.papermc.lib.PaperLib; 086import net.kyori.adventure.text.Component; 087import net.kyori.adventure.text.minimessage.MiniMessage; 088import net.kyori.adventure.text.minimessage.tag.Tag; 089import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; 090import net.kyori.adventure.text.minimessage.tag.standard.StandardTags; 091import org.bukkit.Bukkit; 092import org.bukkit.FluidCollisionMode; 093import org.bukkit.Material; 094import org.bukkit.block.Block; 095import org.bukkit.block.BlockState; 096import org.bukkit.block.Sign; 097import org.bukkit.command.PluginCommand; 098import org.bukkit.entity.ArmorStand; 099import org.bukkit.entity.Boat; 100import org.bukkit.entity.Entity; 101import org.bukkit.entity.EntityType; 102import org.bukkit.entity.HumanEntity; 103import org.bukkit.entity.ItemFrame; 104import org.bukkit.entity.LivingEntity; 105import org.bukkit.entity.Player; 106import org.bukkit.entity.Projectile; 107import org.bukkit.entity.Tameable; 108import org.bukkit.entity.Vehicle; 109import org.bukkit.event.Event; 110import org.bukkit.event.EventHandler; 111import org.bukkit.event.EventPriority; 112import org.bukkit.event.Listener; 113import org.bukkit.event.block.Action; 114import org.bukkit.event.block.BlockBreakEvent; 115import org.bukkit.event.entity.EntityPickupItemEvent; 116import org.bukkit.event.entity.EntityPlaceEvent; 117import org.bukkit.event.entity.EntityPotionEffectEvent; 118import org.bukkit.event.entity.PlayerDeathEvent; 119import org.bukkit.event.hanging.HangingBreakByEntityEvent; 120import org.bukkit.event.hanging.HangingPlaceEvent; 121import org.bukkit.event.inventory.ClickType; 122import org.bukkit.event.inventory.InventoryClickEvent; 123import org.bukkit.event.inventory.InventoryCloseEvent; 124import org.bukkit.event.player.AsyncPlayerChatEvent; 125import org.bukkit.event.player.AsyncPlayerPreLoginEvent; 126import org.bukkit.event.player.PlayerBucketEmptyEvent; 127import org.bukkit.event.player.PlayerBucketFillEvent; 128import org.bukkit.event.player.PlayerChangedWorldEvent; 129import org.bukkit.event.player.PlayerCommandPreprocessEvent; 130import org.bukkit.event.player.PlayerDropItemEvent; 131import org.bukkit.event.player.PlayerEvent; 132import org.bukkit.event.player.PlayerInteractAtEntityEvent; 133import org.bukkit.event.player.PlayerInteractEntityEvent; 134import org.bukkit.event.player.PlayerInteractEvent; 135import org.bukkit.event.player.PlayerJoinEvent; 136import org.bukkit.event.player.PlayerLocaleChangeEvent; 137import org.bukkit.event.player.PlayerMoveEvent; 138import org.bukkit.event.player.PlayerPortalEvent; 139import org.bukkit.event.player.PlayerQuitEvent; 140import org.bukkit.event.player.PlayerRespawnEvent; 141import org.bukkit.event.player.PlayerTakeLecternBookEvent; 142import org.bukkit.event.player.PlayerTeleportEvent; 143import org.bukkit.event.vehicle.VehicleDestroyEvent; 144import org.bukkit.event.vehicle.VehicleEntityCollisionEvent; 145import org.bukkit.event.vehicle.VehicleMoveEvent; 146import org.bukkit.event.world.PortalCreateEvent; 147import org.bukkit.help.HelpTopic; 148import org.bukkit.inventory.ItemStack; 149import org.bukkit.inventory.PlayerInventory; 150import org.bukkit.inventory.meta.ItemMeta; 151import org.bukkit.metadata.FixedMetadataValue; 152import org.bukkit.metadata.MetadataValue; 153import org.bukkit.plugin.Plugin; 154import org.bukkit.potion.PotionEffect; 155import org.bukkit.util.Vector; 156import org.checkerframework.checker.nullness.qual.NonNull; 157 158import java.lang.reflect.Field; 159import java.util.Collections; 160import java.util.HashSet; 161import java.util.List; 162import java.util.Locale; 163import java.util.Objects; 164import java.util.Optional; 165import java.util.Set; 166import java.util.UUID; 167 168/** 169 * Player Events involving plots. 170 */ 171@SuppressWarnings("unused") 172public class PlayerEventListener implements Listener { 173 174 private static final Set<Material> MINECARTS = Set.of( 175 Material.MINECART, 176 Material.TNT_MINECART, 177 Material.CHEST_MINECART, 178 Material.COMMAND_BLOCK_MINECART, 179 Material.FURNACE_MINECART, 180 Material.HOPPER_MINECART 181 ); 182 private static final Set<Material> BOOKS = Set.of( 183 Material.BOOK, 184 Material.KNOWLEDGE_BOOK, 185 Material.WRITABLE_BOOK, 186 Material.WRITTEN_BOOK 187 ); 188 189 /** 190 * The correct EntityType for End Crystal, determined once at class loading time. 191 * Tries END_CRYSTAL first (1.21+), falls back to ENDER_CRYSTAL (1.20.4 and older). 192 */ 193 private static final EntityType END_CRYSTAL_ENTITY_TYPE = Objects.requireNonNull( 194 Enums.findByValue(EntityType.class, "END_CRYSTAL", "ENDER_CRYSTAL") 195 ); 196 197 private static final Set<String> DYES; 198 199 static { 200 Set<String> mutableDyes = new HashSet<>(Set.of( 201 "WHITE_DYE", 202 "LIGHT_GRAY_DYE", 203 "GRAY_DYE", 204 "BLACK_DYE", 205 "BROWN_DYE", 206 "RED_DYE", 207 "ORANGE_DYE", 208 "YELLOW_DYE", 209 "LIME_DYE", 210 "GREEN_DYE", 211 "CYAN_DYE", 212 "LIGHT_BLUE_DYE", 213 "BLUE_DYE", 214 "PURPLE_DYE", 215 "MAGENTA_DYE", 216 "PINK_DYE", 217 "GLOW_INK_SAC" 218 )); 219 int[] version = PlotSquared.platform().serverVersion(); 220 if (version[1] >= 20) { 221 mutableDyes.add("HONEYCOMB"); 222 } 223 DYES = Set.copyOf(mutableDyes); 224 } 225 226 private static final Set<String> INTERACTABLE_MATERIALS; 227 228 static { 229 // @formatter:off 230 // "temporary" fix for https://hub.spigotmc.org/jira/browse/SPIGOT-7813 231 // can (and should) be removed when 1.21 support is dropped 232 // List of all interactable 1.21 materials 233 INTERACTABLE_MATERIALS = Material.CHEST.isInteractable() ? null : Set.of( 234 "REDSTONE_ORE", "DEEPSLATE_REDSTONE_ORE", "CHISELED_BOOKSHELF", "DECORATED_POT", "CHEST", "CRAFTING_TABLE", 235 "FURNACE", "JUKEBOX", "OAK_FENCE", "SPRUCE_FENCE", "BIRCH_FENCE", "JUNGLE_FENCE", "ACACIA_FENCE", "CHERRY_FENCE", 236 "DARK_OAK_FENCE", "MANGROVE_FENCE", "BAMBOO_FENCE", "CRIMSON_FENCE", "WARPED_FENCE", "PUMPKIN", 237 "NETHER_BRICK_FENCE", "ENCHANTING_TABLE", "DRAGON_EGG", "ENDER_CHEST", "COMMAND_BLOCK", "BEACON", "ANVIL", 238 "CHIPPED_ANVIL", "DAMAGED_ANVIL", "LIGHT", "REPEATING_COMMAND_BLOCK", "CHAIN_COMMAND_BLOCK", "SHULKER_BOX", 239 "WHITE_SHULKER_BOX", "ORANGE_SHULKER_BOX", "MAGENTA_SHULKER_BOX", "LIGHT_BLUE_SHULKER_BOX", "YELLOW_SHULKER_BOX", 240 "LIME_SHULKER_BOX", "PINK_SHULKER_BOX", "GRAY_SHULKER_BOX", "LIGHT_GRAY_SHULKER_BOX", "CYAN_SHULKER_BOX", 241 "PURPLE_SHULKER_BOX", "BLUE_SHULKER_BOX", "BROWN_SHULKER_BOX", "GREEN_SHULKER_BOX", "RED_SHULKER_BOX", 242 "BLACK_SHULKER_BOX", "REPEATER", "COMPARATOR", "HOPPER", "DISPENSER", "DROPPER", "LECTERN", "LEVER", 243 "DAYLIGHT_DETECTOR", "TRAPPED_CHEST", "TNT", "NOTE_BLOCK", "STONE_BUTTON", "POLISHED_BLACKSTONE_BUTTON", 244 "OAK_BUTTON", "SPRUCE_BUTTON", "BIRCH_BUTTON", "JUNGLE_BUTTON", "ACACIA_BUTTON", "CHERRY_BUTTON", 245 "DARK_OAK_BUTTON", "MANGROVE_BUTTON", "BAMBOO_BUTTON", "CRIMSON_BUTTON", "WARPED_BUTTON", "IRON_DOOR", "OAK_DOOR", 246 "SPRUCE_DOOR", "BIRCH_DOOR", "JUNGLE_DOOR", "ACACIA_DOOR", "CHERRY_DOOR", "DARK_OAK_DOOR", "MANGROVE_DOOR", 247 "BAMBOO_DOOR", "CRIMSON_DOOR", "WARPED_DOOR", "COPPER_DOOR", "EXPOSED_COPPER_DOOR", "WEATHERED_COPPER_DOOR", 248 "OXIDIZED_COPPER_DOOR", "WAXED_COPPER_DOOR", "WAXED_EXPOSED_COPPER_DOOR", "WAXED_WEATHERED_COPPER_DOOR", 249 "WAXED_OXIDIZED_COPPER_DOOR", "IRON_TRAPDOOR", "OAK_TRAPDOOR", "SPRUCE_TRAPDOOR", "BIRCH_TRAPDOOR", 250 "JUNGLE_TRAPDOOR", "ACACIA_TRAPDOOR", "CHERRY_TRAPDOOR", "DARK_OAK_TRAPDOOR", "MANGROVE_TRAPDOOR", 251 "BAMBOO_TRAPDOOR", "CRIMSON_TRAPDOOR", "WARPED_TRAPDOOR", "COPPER_TRAPDOOR", "EXPOSED_COPPER_TRAPDOOR", 252 "WEATHERED_COPPER_TRAPDOOR", "OXIDIZED_COPPER_TRAPDOOR", "WAXED_COPPER_TRAPDOOR", "WAXED_EXPOSED_COPPER_TRAPDOOR", 253 "WAXED_WEATHERED_COPPER_TRAPDOOR", "WAXED_OXIDIZED_COPPER_TRAPDOOR", "OAK_FENCE_GATE", "SPRUCE_FENCE_GATE", 254 "BIRCH_FENCE_GATE", "JUNGLE_FENCE_GATE", "ACACIA_FENCE_GATE", "CHERRY_FENCE_GATE", "DARK_OAK_FENCE_GATE", 255 "MANGROVE_FENCE_GATE", "BAMBOO_FENCE_GATE", "CRIMSON_FENCE_GATE", "WARPED_FENCE_GATE", "STRUCTURE_BLOCK", 256 "JIGSAW", "OAK_SIGN", "SPRUCE_SIGN", "BIRCH_SIGN", "JUNGLE_SIGN", "ACACIA_SIGN", "CHERRY_SIGN", "DARK_OAK_SIGN", 257 "MANGROVE_SIGN", "BAMBOO_SIGN", "CRIMSON_SIGN", "WARPED_SIGN", "OAK_HANGING_SIGN", "SPRUCE_HANGING_SIGN", 258 "BIRCH_HANGING_SIGN", "JUNGLE_HANGING_SIGN", "ACACIA_HANGING_SIGN", "CHERRY_HANGING_SIGN", 259 "DARK_OAK_HANGING_SIGN", "MANGROVE_HANGING_SIGN", "BAMBOO_HANGING_SIGN", "CRIMSON_HANGING_SIGN", 260 "WARPED_HANGING_SIGN", "CAKE", "WHITE_BED", "ORANGE_BED", "MAGENTA_BED", "LIGHT_BLUE_BED", "YELLOW_BED", 261 "LIME_BED", "PINK_BED", "GRAY_BED", "LIGHT_GRAY_BED", "CYAN_BED", "PURPLE_BED", "BLUE_BED", "BROWN_BED", 262 "GREEN_BED", "RED_BED", "BLACK_BED", "CRAFTER", "BREWING_STAND", "CAULDRON", "FLOWER_POT", "LOOM", "COMPOSTER", 263 "BARREL", "SMOKER", "BLAST_FURNACE", "CARTOGRAPHY_TABLE", "FLETCHING_TABLE", "GRINDSTONE", "SMITHING_TABLE", 264 "STONECUTTER", "BELL", "CAMPFIRE", "SOUL_CAMPFIRE", "BEE_NEST", "BEEHIVE", "RESPAWN_ANCHOR", "CANDLE", 265 "WHITE_CANDLE", "ORANGE_CANDLE", "MAGENTA_CANDLE", "LIGHT_BLUE_CANDLE", "YELLOW_CANDLE", "LIME_CANDLE", 266 "PINK_CANDLE", "GRAY_CANDLE", "LIGHT_GRAY_CANDLE", "CYAN_CANDLE", "PURPLE_CANDLE", "BLUE_CANDLE", "BROWN_CANDLE", 267 "GREEN_CANDLE", "RED_CANDLE", "BLACK_CANDLE", "VAULT", "MOVING_PISTON", "REDSTONE_WIRE", "OAK_WALL_SIGN", 268 "SPRUCE_WALL_SIGN", "BIRCH_WALL_SIGN", "ACACIA_WALL_SIGN", "CHERRY_WALL_SIGN", "JUNGLE_WALL_SIGN", 269 "DARK_OAK_WALL_SIGN", "MANGROVE_WALL_SIGN", "BAMBOO_WALL_SIGN", "OAK_WALL_HANGING_SIGN", 270 "SPRUCE_WALL_HANGING_SIGN", "BIRCH_WALL_HANGING_SIGN", "ACACIA_WALL_HANGING_SIGN", 271 "CHERRY_WALL_HANGING_SIGN", "JUNGLE_WALL_HANGING_SIGN", "DARK_OAK_WALL_HANGING_SIGN", 272 "MANGROVE_WALL_HANGING_SIGN", "CRIMSON_WALL_HANGING_SIGN", "WARPED_WALL_HANGING_SIGN", "BAMBOO_WALL_HANGING_SIGN", 273 "WATER_CAULDRON", "LAVA_CAULDRON", "POWDER_SNOW_CAULDRON", "POTTED_TORCHFLOWER", "POTTED_OAK_SAPLING", 274 "POTTED_SPRUCE_SAPLING", "POTTED_BIRCH_SAPLING", "POTTED_JUNGLE_SAPLING", "POTTED_ACACIA_SAPLING", 275 "POTTED_CHERRY_SAPLING", "POTTED_DARK_OAK_SAPLING", "POTTED_MANGROVE_PROPAGULE", "POTTED_FERN", 276 "POTTED_DANDELION", "POTTED_POPPY", "POTTED_BLUE_ORCHID", "POTTED_ALLIUM", "POTTED_AZURE_BLUET", 277 "POTTED_RED_TULIP", "POTTED_ORANGE_TULIP", "POTTED_WHITE_TULIP", "POTTED_PINK_TULIP", "POTTED_OXEYE_DAISY", 278 "POTTED_CORNFLOWER", "POTTED_LILY_OF_THE_VALLEY", "POTTED_WITHER_ROSE", "POTTED_RED_MUSHROOM", 279 "POTTED_BROWN_MUSHROOM", "POTTED_DEAD_BUSH", "POTTED_CACTUS", "POTTED_BAMBOO", "SWEET_BERRY_BUSH", 280 "CRIMSON_WALL_SIGN", "WARPED_WALL_SIGN", "POTTED_CRIMSON_FUNGUS", "POTTED_WARPED_FUNGUS", "POTTED_CRIMSON_ROOTS", 281 "POTTED_WARPED_ROOTS", "CANDLE_CAKE", "WHITE_CANDLE_CAKE", "ORANGE_CANDLE_CAKE", "MAGENTA_CANDLE_CAKE", 282 "LIGHT_BLUE_CANDLE_CAKE", "YELLOW_CANDLE_CAKE", "LIME_CANDLE_CAKE", "PINK_CANDLE_CAKE", "GRAY_CANDLE_CAKE", 283 "LIGHT_GRAY_CANDLE_CAKE", "CYAN_CANDLE_CAKE", "PURPLE_CANDLE_CAKE", "BLUE_CANDLE_CAKE", "BROWN_CANDLE_CAKE", 284 "GREEN_CANDLE_CAKE", "RED_CANDLE_CAKE", "BLACK_CANDLE_CAKE", "CAVE_VINES", "CAVE_VINES_PLANT", 285 "POTTED_AZALEA_BUSH", "POTTED_FLOWERING_AZALEA_BUSH" 286 ); 287 // @formatter:on 288 } 289 290 private final EventDispatcher eventDispatcher; 291 private final WorldEdit worldEdit; 292 private final PlotAreaManager plotAreaManager; 293 private final PlotListener plotListener; 294 // To prevent recursion 295 private boolean tmpTeleport = true; 296 private Field fieldPlayer; 297 private PlayerMoveEvent moveTmp; 298 private String internalVersion; 299 300 { 301 try { 302 fieldPlayer = PlayerEvent.class.getDeclaredField("player"); 303 fieldPlayer.setAccessible(true); 304 } catch (NoSuchFieldException e) { 305 e.printStackTrace(); 306 } 307 } 308 309 @Inject 310 public PlayerEventListener( 311 final @NonNull PlotAreaManager plotAreaManager, 312 final @NonNull EventDispatcher eventDispatcher, 313 final @NonNull WorldEdit worldEdit, 314 final @NonNull PlotListener plotListener 315 ) { 316 this.eventDispatcher = eventDispatcher; 317 this.worldEdit = worldEdit; 318 this.plotAreaManager = plotAreaManager; 319 this.plotListener = plotListener; 320 } 321 322 @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) 323 public void onBlockBreak(final BlockBreakEvent event) { 324 Location location = BukkitUtil.adapt(event.getBlock().getLocation()); 325 PlotArea area = location.getPlotArea(); 326 if (area == null) { 327 return; 328 } 329 Plot plot = area.getPlot(location); 330 if (plot != null) { 331 event.setDropItems(plot.getFlag(TileDropFlag.class)); 332 } 333 } 334 335 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 336 public void onPlayerDyeSign(PlayerInteractEvent event) { 337 ItemStack itemStack = event.getItem(); 338 if (itemStack == null) { 339 return; 340 } 341 Block block = event.getClickedBlock(); 342 if (block != null && block.getState() instanceof Sign) { 343 if (DYES.contains(itemStack.getType().toString())) { 344 Location location = BukkitUtil.adapt(block.getLocation()); 345 PlotArea area = location.getPlotArea(); 346 if (area == null) { 347 return; 348 } 349 Plot plot = location.getOwnedPlot(); 350 if (plot == null) { 351 if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, EditSignFlag.class, false) 352 && !event.getPlayer().hasPermission(Permission.PERMISSION_ADMIN_INTERACT_ROAD.toString())) { 353 event.setCancelled(true); 354 } 355 return; 356 } 357 if (plot.isAdded(event.getPlayer().getUniqueId())) { 358 return; // allow for added players 359 } 360 if (!plot.getFlag(EditSignFlag.class) 361 && !event.getPlayer().hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER.toString())) { 362 plot.debug(event.getPlayer().getName() + " could not color the sign because of edit-sign = false"); 363 event.setCancelled(true); 364 } 365 } 366 } 367 } 368 369 @EventHandler(ignoreCancelled = true) 370 public void onEffect(@NonNull EntityPotionEffectEvent event) { 371 if (Settings.Enabled_Components.DISABLE_BEACON_EFFECT_OVERFLOW || 372 event.getCause() != EntityPotionEffectEvent.Cause.BEACON || 373 !(event.getEntity() instanceof Player player)) { 374 return; 375 } 376 377 UUID uuid = player.getUniqueId(); 378 PotionEffect effect = event.getNewEffect(); 379 if (effect == null) { 380 PotionEffect oldEffect = event.getOldEffect(); 381 if (oldEffect != null) { 382 String name = oldEffect.getType().getName(); 383 plotListener.addEffect(uuid, name, -1); 384 } 385 } else { 386 long expiresAt = System.currentTimeMillis() + effect.getDuration() * 50L; //Convert ticks to milliseconds 387 String name = effect.getType().getName(); 388 plotListener.addEffect(uuid, name, expiresAt); 389 } 390 } 391 392 @EventHandler 393 public void onVehicleEntityCollision(VehicleEntityCollisionEvent e) { 394 if (e.getVehicle() instanceof Boat) { 395 Location location = BukkitUtil.adapt(e.getEntity().getLocation()); 396 if (location.isPlotArea()) { 397 if (e.getEntity() instanceof Player) { 398 PlotPlayer<Player> player = BukkitUtil.adapt((Player) e.getEntity()); 399 Plot plot = player.getCurrentPlot(); 400 if (plot != null) { 401 if (!plot.isAdded(player.getUUID())) { 402 //Here the event is only canceled if the player is not the owner 403 //of the property on which he is located. 404 e.setCancelled(true); 405 } 406 } else { 407 e.setCancelled(true); 408 } 409 } else { 410 //Here the event is cancelled too, otherwise you can move the 411 //boat with EchoPets or other mobs running around on the plot. 412 e.setCancelled(true); 413 } 414 } 415 } 416 } 417 418 @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) 419 public void playerCommand(PlayerCommandPreprocessEvent event) { 420 String msg = event.getMessage().replace("/", "").toLowerCase(Locale.ROOT).trim(); 421 if (msg.isEmpty()) { 422 return; 423 } 424 Player player = event.getPlayer(); 425 PlotPlayer<Player> plotPlayer = BukkitUtil.adapt(player); 426 Location location = plotPlayer.getLocation(); 427 PlotArea area = location.getPlotArea(); 428 if (area == null) { 429 return; 430 } 431 String[] parts = msg.split(" "); 432 Plot plot = plotPlayer.getCurrentPlot(); 433 // Check WorldEdit 434 switch (parts[0]) { 435 case "up", "worldedit:up" -> { 436 if (plot == null || (!plot.isAdded(plotPlayer.getUUID()) && !plotPlayer.hasPermission( 437 Permission.PERMISSION_ADMIN_BUILD_OTHER, 438 true 439 ))) { 440 event.setCancelled(true); 441 return; 442 } 443 } 444 } 445 if (plot == null && !area.isRoadFlags()) { 446 return; 447 } 448 449 List<String> blockedCommands = plot != null ? 450 plot.getFlag(BlockedCmdsFlag.class) : 451 area.getFlag(BlockedCmdsFlag.class); 452 if (blockedCommands.isEmpty()) { 453 return; 454 } 455 if (plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_BLOCKED_CMDS)) { 456 return; 457 } 458 // When using namespaced commands, we're not interested in the namespace 459 String part = parts[0]; 460 if (part.contains(":")) { 461 String[] namespaced = part.split(":"); 462 part = namespaced[1]; 463 msg = msg.substring(namespaced[0].length() + 1); 464 } 465 msg = replaceAliases(msg, part); 466 for (String blocked : blockedCommands) { 467 if (blocked.equalsIgnoreCase(msg)) { 468 String perm; 469 if (plot != null && plot.isAdded(plotPlayer.getUUID())) { 470 perm = "plots.admin.command.blocked-cmds.shared"; 471 } else { 472 perm = "plots.admin.command.blocked-cmds.road"; 473 } 474 if (!plotPlayer.hasPermission(perm)) { 475 plotPlayer.sendMessage(TranslatableCaption.of("blockedcmds.command_blocked")); 476 event.setCancelled(true); 477 } 478 return; 479 } 480 } 481 } 482 483 private String replaceAliases(String msg, String part) { 484 String s1 = part; 485 Set<String> aliases = new HashSet<>(); 486 for (HelpTopic cmdLabel : Bukkit.getServer().getHelpMap().getHelpTopics()) { 487 if (part.equals(cmdLabel.getName())) { 488 break; 489 } 490 String label = cmdLabel.getName().replaceFirst("/", ""); 491 if (aliases.contains(label)) { 492 continue; 493 } 494 PluginCommand p = Bukkit.getPluginCommand(label); 495 if (p != null) { 496 for (String a : p.getAliases()) { 497 if (aliases.contains(a)) { 498 continue; 499 } 500 aliases.add(a); 501 a = a.replaceFirst("/", ""); 502 if (!a.equals(label) && a.equals(part)) { 503 part = label; 504 break; 505 } 506 } 507 } 508 } 509 if (!s1.equals(part)) { 510 msg = msg.replace(s1, part); 511 } 512 return msg; 513 } 514 515 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 516 public void onPreLogin(final AsyncPlayerPreLoginEvent event) { 517 final UUID uuid; 518 if (Settings.UUID.OFFLINE) { 519 if (Settings.UUID.FORCE_LOWERCASE) { 520 uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + event.getName().toLowerCase()).getBytes(Charsets.UTF_8)); 521 } else { 522 uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + event.getName()).getBytes(Charsets.UTF_8)); 523 } 524 } else { 525 uuid = event.getUniqueId(); 526 } 527 PlotSquared.get().getImpromptuUUIDPipeline().storeImmediately(event.getName(), uuid); 528 } 529 530 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 531 @SuppressWarnings("deprecation") // Paper deprecation 532 public void onConnect(PlayerJoinEvent event) { 533 final Player player = event.getPlayer(); 534 PlotSquared.platform().playerManager().removePlayer(player.getUniqueId()); 535 final PlotPlayer<Player> pp = BukkitUtil.adapt(player); 536 537 // we're stripping the country code as we don't want to differ between countries 538 pp.setLocale(Locale.forLanguageTag(player.getLocale().substring(0, 2))); 539 540 Location location = pp.getLocation(); 541 PlotArea area = location.getPlotArea(); 542 if (area != null) { 543 Plot plot = area.getPlot(location); 544 if (plot != null) { 545 plotListener.plotEntry(pp, plot); 546 } 547 } 548 // Delayed 549 550 // Async 551 TaskManager.runTaskLaterAsync( 552 () -> { 553 if (!player.hasPlayedBefore() && player.isOnline()) { 554 player.saveData(); 555 } 556 this.eventDispatcher.doJoinTask(pp); 557 }, TaskTime.seconds(1L) 558 ); 559 560 if (pp.hasPermission(Permission.PERMISSION_ADMIN_UPDATE_NOTIFICATION.toString()) && Settings.Enabled_Components.UPDATE_NOTIFICATIONS 561 && PremiumVerification.isPremium() && UpdateUtility.hasUpdate) { 562 Caption boundary = TranslatableCaption.of("update.update_boundary"); 563 Caption updateNotification = TranslatableCaption.of("update.update_notification"); 564 pp.sendMessage(boundary); 565 pp.sendMessage( 566 updateNotification, 567 TagResolver.builder() 568 .tag("p2version", Tag.inserting(Component.text(UpdateUtility.internalVersion.versionString()))) 569 .tag("spigotversion", Tag.inserting(Component.text(UpdateUtility.spigotVersion))) 570 .tag("downloadurl", Tag.preProcessParsed("https://www.spigotmc.org/resources/77506/updates")) 571 .build() 572 ); 573 pp.sendMessage(boundary); 574 } 575 } 576 577 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 578 public void playerRespawn(PlayerRespawnEvent event) { 579 Player player = event.getPlayer(); 580 PlotPlayer<Player> pp = BukkitUtil.adapt(player); 581 this.eventDispatcher.doRespawnTask(pp); 582 } 583 584 @SuppressWarnings("deprecation") // We explicitly want #getHomeSynchronous here 585 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 586 public void onTeleport(PlayerTeleportEvent event) { 587 Player player = event.getPlayer(); 588 //We need to account for bad plugins like NoCheatPlus that teleports player on/before login -_- 589 if (!player.isOnline()) { 590 return; 591 } 592 BukkitPlayer pp = BukkitUtil.adapt(player); 593 try (final MetaDataAccess<Plot> lastPlotAccess = 594 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { 595 Plot lastPlot = lastPlotAccess.get().orElse(null); 596 org.bukkit.Location to = event.getTo(); 597 //noinspection ConstantConditions 598 if (to != null) { 599 Location location = BukkitUtil.adapt(to); 600 PlotArea area = location.getPlotArea(); 601 if (area == null) { 602 if (lastPlot != null) { 603 plotListener.plotExit(pp, lastPlot); 604 lastPlotAccess.remove(); 605 } 606 try (final MetaDataAccess<Location> lastLocationAccess = 607 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { 608 lastLocationAccess.remove(); 609 } 610 return; 611 } 612 Plot plot = area.getPlot(location); 613 if (plot != null && !plot.equals(lastPlot)) { 614 final boolean result = DenyTeleportFlag.allowsTeleport(pp, plot); 615 // there is one possibility to still allow teleportation: 616 // to is identical to the plot's home location, and untrusted-visit is true 617 // i.e. untrusted-visit can override deny-teleport 618 // this is acceptable, because otherwise it wouldn't make sense to have both flags set 619 if (result || (plot.getFlag(UntrustedVisitFlag.class) && plot 620 .getHomeSynchronous() 621 .equals(BukkitUtil.adaptComplete(to)))) { 622 // returns false if the player is not allowed to enter the plot (if they are denied, for example) 623 // don't let the move event cancel the entry after teleport, but rather catch and cancel early (#4647) 624 if (!plotListener.plotEntry(pp, plot)) { 625 event.setCancelled(true); 626 } 627 } else { 628 pp.sendMessage( 629 TranslatableCaption.of("deny.no_enter"), 630 TagResolver.resolver("plot", Tag.inserting(Component.text(plot.toString()))) 631 ); 632 event.setCancelled(true); 633 } 634 } 635 } 636 } 637 playerMove(event); 638 } 639 640 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 641 public void onWorldChanged(PlayerChangedWorldEvent event) { 642 Player player = event.getPlayer(); 643 BukkitPlayer pp = BukkitUtil.adapt(player); 644 if (this.worldEdit != null) { 645 if (!pp.hasPermission(Permission.PERMISSION_WORLDEDIT_BYPASS)) { 646 if (pp.getAttribute("worldedit")) { 647 pp.removeAttribute("worldedit"); 648 } 649 } 650 } 651 } 652 653 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 654 public void vehicleMove(VehicleMoveEvent event) 655 throws IllegalAccessException { 656 final org.bukkit.Location from = event.getFrom(); 657 final org.bukkit.Location to = event.getTo(); 658 659 int toX, toZ; 660 if ((toX = MathMan.roundInt(to.getX())) != MathMan.roundInt(from.getX()) | (toZ = MathMan.roundInt(to.getZ())) != MathMan 661 .roundInt(from.getZ())) { 662 Vehicle vehicle = event.getVehicle(); 663 664 // Check allowed 665 if (!vehicle.getPassengers().isEmpty()) { 666 Entity passenger = vehicle.getPassengers().get(0); 667 668 if (passenger instanceof final Player player) { 669 // reset 670 if (moveTmp == null) { 671 moveTmp = new PlayerMoveEvent(null, from, to); 672 } 673 moveTmp.setFrom(from); 674 moveTmp.setTo(to); 675 moveTmp.setCancelled(false); 676 fieldPlayer.set(moveTmp, player); 677 678 List<Entity> passengers = vehicle.getPassengers(); 679 680 this.playerMove(moveTmp); 681 org.bukkit.Location dest; 682 if (moveTmp.isCancelled()) { 683 dest = from; 684 } else if (MathMan.roundInt(moveTmp.getTo().getX()) != toX || MathMan.roundInt(moveTmp 685 .getTo() 686 .getZ()) != toZ) { 687 dest = to; 688 } else { 689 dest = null; 690 } 691 if (dest != null) { 692 vehicle.eject(); 693 vehicle.setVelocity(new Vector(0d, 0d, 0d)); 694 PaperLib.teleportAsync(vehicle, dest); 695 passengers.forEach(vehicle::addPassenger); 696 return; 697 } 698 } 699 if (Settings.Enabled_Components.KILL_ROAD_VEHICLES) { 700 final com.sk89q.worldedit.world.entity.EntityType entityType = BukkitAdapter.adapt(vehicle.getType()); 701 // Horses etc are vehicles, but they're also animals 702 // so this filters out all living entities 703 if (EntityCategories.VEHICLE.contains(entityType) && !EntityCategories.ANIMAL.contains(entityType)) { 704 List<MetadataValue> meta = vehicle.getMetadata("plot"); 705 Plot toPlot = BukkitUtil.adapt(to).getPlot(); 706 if (!meta.isEmpty()) { 707 Plot origin = (Plot) meta.get(0).value(); 708 if (origin != null && !origin.getBasePlot(false).equals(toPlot)) { 709 vehicle.remove(); 710 } 711 } else if (toPlot != null) { 712 vehicle.setMetadata("plot", new FixedMetadataValue((Plugin) PlotSquared.platform(), toPlot)); 713 } 714 } 715 } 716 } 717 718 } 719 } 720 721 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 722 public void playerMove(PlayerMoveEvent event) { 723 org.bukkit.Location from = event.getFrom(); 724 org.bukkit.Location to = event.getTo(); 725 int x2; 726 if (MathMan.roundInt(from.getX()) != (x2 = MathMan.roundInt(to.getX()))) { 727 Player player = event.getPlayer(); 728 BukkitPlayer pp = BukkitUtil.adapt(player); 729 // Cancel teleport 730 if (TaskManager.removeFromTeleportQueue(pp.getName())) { 731 pp.sendMessage(TranslatableCaption.of("teleport.teleport_failed")); 732 } 733 // Set last location 734 Location location = BukkitUtil.adapt(to); 735 try (final MetaDataAccess<Location> lastLocationAccess = 736 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { 737 lastLocationAccess.remove(); 738 } 739 PlotArea area = location.getPlotArea(); 740 if (area == null) { 741 try (final MetaDataAccess<Plot> lastPlotAccess = 742 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { 743 lastPlotAccess.remove(); 744 } 745 return; 746 } 747 Plot now = area.getPlot(location); 748 Plot lastPlot; 749 try (final MetaDataAccess<Plot> lastPlotAccess = 750 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { 751 lastPlot = lastPlotAccess.get().orElse(null); 752 } 753 if (now == null) { 754 try (final MetaDataAccess<Boolean> kickAccess = 755 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_KICK)) { 756 if (lastPlot != null && !plotListener.plotExit(pp, lastPlot) && this.tmpTeleport && !kickAccess.get().orElse( 757 false)) { 758 pp.sendMessage( 759 TranslatableCaption.of("permission.no_permission_event"), 760 TagResolver.resolver( 761 "node", 762 Tag.inserting(Permission.PERMISSION_ADMIN_EXIT_DENIED) 763 ) 764 ); 765 this.tmpTeleport = false; 766 if (lastPlot.equals(BukkitUtil.adapt(from).getPlot())) { 767 player.teleport(from); 768 } else { 769 player.teleport(player.getWorld().getSpawnLocation()); 770 } 771 this.tmpTeleport = true; 772 event.setCancelled(true); 773 return; 774 } 775 } 776 } else if (now.equals(lastPlot)) { 777 ForceFieldListener.handleForcefield(player, pp, now); 778 } else if (!plotListener.plotEntry(pp, now) && this.tmpTeleport) { 779 pp.sendMessage( 780 TranslatableCaption.of("deny.no_enter"), 781 TagResolver.resolver("plot", Tag.inserting(Component.text(now.toString()))) 782 ); 783 this.tmpTeleport = false; 784 to.setX(from.getBlockX()); 785 to.setY(from.getBlockY()); 786 to.setZ(from.getBlockZ()); 787 player.teleport(event.getTo()); 788 this.tmpTeleport = true; 789 return; 790 } 791 int border = area.getBorder(true); 792 int x1; 793 if (x2 > border && this.tmpTeleport) { 794 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_BORDER)) { 795 to.setX(border - 1); 796 this.tmpTeleport = false; 797 player.teleport(event.getTo()); 798 this.tmpTeleport = true; 799 pp.sendMessage(TranslatableCaption.of("border.denied")); 800 } else if (MathMan.roundInt(from.getX()) <= border) { // Only send if they just moved out of the border 801 pp.sendMessage(TranslatableCaption.of("border.bypass.exited")); 802 } 803 } else if (x2 < -border && this.tmpTeleport) { 804 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_BORDER)) { 805 to.setX(-border + 1); 806 this.tmpTeleport = false; 807 player.teleport(event.getTo()); 808 this.tmpTeleport = true; 809 pp.sendMessage(TranslatableCaption.of("border.denied")); 810 } else if (MathMan.roundInt(from.getX()) >= -border) { // Only send if they just moved out of the border 811 pp.sendMessage(TranslatableCaption.of("border.bypass.exited")); 812 } 813 } else if (((x1 = MathMan.roundInt(from.getX())) >= border && x2 <= border) || (x1 <= -border && x2 >= -border)) { 814 if (pp.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_BORDER)) { 815 pp.sendMessage(TranslatableCaption.of("border.bypass.entered")); 816 } 817 } 818 } 819 int z2; 820 if (MathMan.roundInt(from.getZ()) != (z2 = MathMan.roundInt(to.getZ()))) { 821 Player player = event.getPlayer(); 822 BukkitPlayer pp = BukkitUtil.adapt(player); 823 // Cancel teleport 824 if (TaskManager.removeFromTeleportQueue(pp.getName())) { 825 pp.sendMessage(TranslatableCaption.of("teleport.teleport_failed")); 826 } 827 // Set last location 828 Location location = BukkitUtil.adapt(to); 829 try (final MetaDataAccess<Location> lastLocationAccess = 830 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { 831 lastLocationAccess.set(location); 832 } 833 PlotArea area = location.getPlotArea(); 834 if (area == null) { 835 try (final MetaDataAccess<Plot> lastPlotAccess = 836 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { 837 lastPlotAccess.remove(); 838 } 839 return; 840 } 841 Plot plot = area.getPlot(location); 842 Plot lastPlot; 843 try (final MetaDataAccess<Plot> lastPlotAccess = 844 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { 845 lastPlot = lastPlotAccess.get().orElse(null); 846 } 847 if (plot == null) { 848 try (final MetaDataAccess<Boolean> kickAccess = 849 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_KICK)) { 850 if (lastPlot != null && !plotListener.plotExit(pp, lastPlot) && this.tmpTeleport && !kickAccess.get().orElse( 851 false)) { 852 pp.sendMessage( 853 TranslatableCaption.of("permission.no_permission_event"), 854 TagResolver.resolver( 855 "node", 856 Tag.inserting(Permission.PERMISSION_ADMIN_EXIT_DENIED) 857 ) 858 ); 859 this.tmpTeleport = false; 860 if (lastPlot.equals(BukkitUtil.adapt(from).getPlot())) { 861 player.teleport(from); 862 } else { 863 player.teleport(player.getWorld().getSpawnLocation()); 864 } 865 this.tmpTeleport = true; 866 event.setCancelled(true); 867 return; 868 } 869 } 870 } else if (plot.equals(lastPlot)) { 871 ForceFieldListener.handleForcefield(player, pp, plot); 872 } else if (!plotListener.plotEntry(pp, plot) && this.tmpTeleport) { 873 pp.sendMessage( 874 TranslatableCaption.of("deny.no_enter"), 875 TagResolver.resolver("plot", Tag.inserting(Component.text(plot.toString()))) 876 ); 877 this.tmpTeleport = false; 878 player.teleport(from); 879 to.setX(from.getBlockX()); 880 to.setY(from.getBlockY()); 881 to.setZ(from.getBlockZ()); 882 player.teleport(event.getTo()); 883 this.tmpTeleport = true; 884 return; 885 } 886 int border = area.getBorder(true); 887 int z1; 888 if (z2 > border && this.tmpTeleport) { 889 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_BORDER)) { 890 to.setZ(border - 1); 891 this.tmpTeleport = false; 892 player.teleport(event.getTo()); 893 this.tmpTeleport = true; 894 pp.sendMessage(TranslatableCaption.of("border.denied")); 895 } else if (MathMan.roundInt(from.getZ()) <= border) { // Only send if they just moved out of the border 896 pp.sendMessage(TranslatableCaption.of("border.bypass.exited")); 897 } 898 } else if (z2 < -border && this.tmpTeleport) { 899 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_BORDER)) { 900 to.setZ(-border + 1); 901 this.tmpTeleport = false; 902 player.teleport(event.getTo()); 903 this.tmpTeleport = true; 904 pp.sendMessage(TranslatableCaption.of("border.denied")); 905 } else if (MathMan.roundInt(from.getZ()) >= -border) { // Only send if they just moved out of the border 906 pp.sendMessage(TranslatableCaption.of("border.bypass.exited")); 907 } 908 } else if (((z1 = MathMan.roundInt(from.getZ())) >= border && z2 <= border) || (z1 <= -border && z2 >= -border)) { 909 if (pp.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_BORDER)) { 910 pp.sendMessage(TranslatableCaption.of("border.bypass.entered")); 911 } 912 } 913 } 914 } 915 916 @EventHandler(priority = EventPriority.LOW) 917 @SuppressWarnings("deprecation") // Paper deprecation 918 public void onChat(AsyncPlayerChatEvent event) { 919 if (event.isCancelled()) { 920 return; 921 } 922 923 BukkitPlayer plotPlayer = BukkitUtil.adapt(event.getPlayer()); 924 Location location = plotPlayer.getLocation(); 925 PlotArea area = location.getPlotArea(); 926 if (area == null) { 927 return; 928 } 929 Plot plot = area.getPlot(location); 930 if (plot == null) { 931 return; 932 } 933 if (!((plot.getFlag(ChatFlag.class) && area.isPlotChat() && plotPlayer.getAttribute("chat")) 934 || area.isForcingPlotChat())) { 935 return; 936 } 937 if (plot.isDenied(plotPlayer.getUUID()) && !plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_CHAT_BYPASS)) { 938 return; 939 } 940 event.setCancelled(true); 941 Set<Player> recipients = event.getRecipients(); 942 recipients.clear(); 943 Set<PlotPlayer<?>> spies = new HashSet<>(); 944 Set<PlotPlayer<?>> plotRecipients = new HashSet<>(); 945 for (final PlotPlayer<?> pp : PlotSquared.platform().playerManager().getPlayers()) { 946 if (pp.getAttribute("chatspy")) { 947 spies.add(pp); 948 } else { 949 Plot current = pp.getCurrentPlot(); 950 if (current != null && current.getBasePlot(false).equals(plot)) { 951 plotRecipients.add(pp); 952 } 953 } 954 } 955 String message = event.getMessage(); 956 String sender = event.getPlayer().getDisplayName(); 957 PlotId id = plot.getId(); 958 String worldName = plot.getWorldName(); 959 Caption msg = TranslatableCaption.of("chat.plot_chat_format"); 960 TagResolver.Builder builder = TagResolver.builder(); 961 builder.tag("world", Tag.inserting(Component.text(worldName))); 962 builder.tag("plot_id", Tag.inserting(Component.text(id.toString()))); 963 builder.tag("sender", Tag.inserting(Component.text(sender))); 964 if (plotPlayer.hasPermission("plots.chat.color")) { 965 builder.tag( 966 "msg", Tag.inserting(MiniMessage.miniMessage().deserialize( 967 message, 968 TagResolver.resolver( 969 StandardTags.color(), StandardTags.gradient(), 970 StandardTags.rainbow(), StandardTags.decorations() 971 ) 972 )) 973 ); 974 } else { 975 builder.tag("msg", Tag.inserting(Component.text(message))); 976 } 977 for (PlotPlayer<?> receiver : plotRecipients) { 978 receiver.sendMessage(msg, builder.build()); 979 } 980 if (!spies.isEmpty()) { 981 Caption spymsg = TranslatableCaption.of("chat.plot_chat_spy_format"); 982 for (PlotPlayer<?> player : spies) { 983 player.sendMessage(spymsg, builder.tag("message", Tag.inserting(Component.text(message))).build()); 984 } 985 } 986 if (Settings.Chat.LOG_PLOTCHAT_TO_CONSOLE) { 987 Caption spymsg = TranslatableCaption.of("chat.plot_chat_spy_format"); 988 ConsolePlayer.getConsole().sendMessage( 989 spymsg, 990 builder.tag("message", Tag.inserting(Component.text(message))).build() 991 ); 992 } 993 } 994 995 @SuppressWarnings("deprecation") 996 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 997 public void onInventoryClick(InventoryClickEvent event) { 998 /*if (!event.isLeftClick() || (event.getAction() != InventoryAction.PLACE_ALL) || event 999 .isShiftClick()) { 1000 return; 1001 }*/ 1002 HumanEntity entity = event.getWhoClicked(); 1003 if (!(entity instanceof Player) || !this.plotAreaManager 1004 .hasPlotArea(entity.getWorld().getName())) { 1005 return; 1006 } 1007 1008 HumanEntity clicker = event.getWhoClicked(); 1009 if (!(clicker instanceof Player player)) { 1010 return; 1011 } 1012 BukkitPlayer pp = BukkitUtil.adapt(player); 1013 final PlotInventory inventory = PlotInventory.getOpenPlotInventory(pp); 1014 if (inventory != null && event.getRawSlot() == event.getSlot()) { 1015 if (!inventory.onClick(event.getSlot())) { 1016 event.setResult(Event.Result.DENY); 1017 event.setCancelled(true); 1018 inventory.close(); 1019 } 1020 } 1021 PlayerInventory inv = player.getInventory(); 1022 int slot = inv.getHeldItemSlot(); 1023 if ((slot > 8) || !event.getEventName().equals("InventoryCreativeEvent")) { 1024 return; 1025 } 1026 ItemStack oldItem = inv.getItemInHand(); 1027 ItemMeta oldMeta = oldItem.getItemMeta(); 1028 ItemStack newItem = event.getCursor(); 1029 ItemMeta newMeta = newItem.getItemMeta(); 1030 1031 if (event.getClick() == ClickType.CREATIVE) { 1032 final Plot plot = pp.getCurrentPlot(); 1033 if (plot != null) { 1034 if (plot.getFlag(PreventCreativeCopyFlag.class) && !plot 1035 .isAdded(player.getUniqueId()) && !pp.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER)) { 1036 final ItemStack newStack = 1037 new ItemStack(newItem.getType(), newItem.getAmount()); 1038 event.setCursor(newStack); 1039 plot.debug(player.getName() 1040 + " could not creative-copy an item because prevent-creative-copy = true"); 1041 } 1042 } else { 1043 PlotArea area = pp.getPlotAreaAbs(); 1044 if (area != null && PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, PreventCreativeCopyFlag.class, true)) { 1045 final ItemStack newStack = 1046 new ItemStack(newItem.getType(), newItem.getAmount()); 1047 event.setCursor(newStack); 1048 } 1049 } 1050 return; 1051 } 1052 1053 String newLore = ""; 1054 if (newMeta != null) { 1055 List<String> lore = newMeta.getLore(); 1056 if (lore != null) { 1057 newLore = lore.toString(); 1058 } 1059 } 1060 String oldLore = ""; 1061 if (oldMeta != null) { 1062 List<String> lore = oldMeta.getLore(); 1063 if (lore != null) { 1064 oldLore = lore.toString(); 1065 } 1066 } 1067 Material itemType = newItem.getType(); 1068 if (!"[(+NBT)]".equals(newLore) || (oldItem.equals(newItem) && newLore.equals(oldLore))) { 1069 if (newMeta == null || (itemType != Material.LEGACY_BANNER && itemType != Material.PLAYER_HEAD)) { 1070 return; 1071 } 1072 } 1073 Block block = player.getTargetBlock(null, 7); 1074 org.bukkit.block.BlockState state = block.getState(); 1075 Material stateType = state.getType(); 1076 if (stateType != itemType) { 1077 if (stateType == Material.LEGACY_WALL_BANNER || stateType == Material.LEGACY_STANDING_BANNER) { 1078 if (itemType != Material.LEGACY_BANNER) { 1079 return; 1080 } 1081 } else if (stateType == Material.LEGACY_SKULL) { 1082 if (itemType != Material.LEGACY_SKULL_ITEM) { 1083 return; 1084 } 1085 } else { 1086 return; 1087 } 1088 } 1089 Location location = BukkitUtil.adapt(state.getLocation()); 1090 PlotArea area = location.getPlotArea(); 1091 if (area == null) { 1092 return; 1093 } 1094 Plot plot = area.getPlotAbs(location); 1095 boolean cancelled = false; 1096 if (plot == null) { 1097 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_ROAD)) { 1098 pp.sendMessage( 1099 TranslatableCaption.of("permission.no_permission_event"), 1100 TagResolver.resolver( 1101 "node", 1102 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_ROAD) 1103 ) 1104 ); 1105 cancelled = true; 1106 } 1107 } else if (!plot.hasOwner()) { 1108 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED)) { 1109 pp.sendMessage( 1110 TranslatableCaption.of("permission.no_permission_event"), 1111 TagResolver.resolver( 1112 "node", 1113 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED) 1114 ) 1115 ); 1116 cancelled = true; 1117 } 1118 } else { 1119 UUID uuid = pp.getUUID(); 1120 if (!plot.isAdded(uuid)) { 1121 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER)) { 1122 pp.sendMessage( 1123 TranslatableCaption.of("permission.no_permission_event"), 1124 TagResolver.resolver( 1125 "node", 1126 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_OTHER) 1127 ) 1128 ); 1129 cancelled = true; 1130 } 1131 } 1132 } 1133 if (cancelled) { 1134 if ((oldItem.getType() == newItem.getType()) && (oldItem.getDurability() == newItem 1135 .getDurability())) { 1136 event.setCursor( 1137 new ItemStack(newItem.getType(), newItem.getAmount(), newItem.getDurability())); 1138 event.setCancelled(true); 1139 return; 1140 } 1141 event.setCursor( 1142 new ItemStack(newItem.getType(), newItem.getAmount(), newItem.getDurability())); 1143 } 1144 } 1145 1146 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 1147 public void onInteract(PlayerInteractAtEntityEvent e) { 1148 Entity entity = e.getRightClicked(); 1149 if (!(entity instanceof ArmorStand) && !(entity instanceof ItemFrame)) { 1150 return; 1151 } 1152 Location location = BukkitUtil.adapt(e.getRightClicked().getLocation()); 1153 PlotArea area = location.getPlotArea(); 1154 if (area == null) { 1155 return; 1156 } 1157 EntitySpawnListener.testNether(entity); 1158 Plot plot = location.getPlotAbs(); 1159 BukkitPlayer pp = BukkitUtil.adapt(e.getPlayer()); 1160 if (plot == null) { 1161 if (!PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, MiscInteractFlag.class, true) && !pp.hasPermission( 1162 Permission.PERMISSION_ADMIN_INTERACT_ROAD 1163 )) { 1164 pp.sendMessage( 1165 TranslatableCaption.of("permission.no_permission_event"), 1166 TagResolver.resolver( 1167 "node", 1168 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_ROAD) 1169 ) 1170 ); 1171 e.setCancelled(true); 1172 } 1173 } else { 1174 if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { 1175 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER)) { 1176 pp.sendMessage(TranslatableCaption.of("done.building_restricted")); 1177 e.setCancelled(true); 1178 return; 1179 } 1180 } 1181 if (!plot.hasOwner()) { 1182 if (!pp.hasPermission("plots.admin.interact.unowned")) { 1183 pp.sendMessage( 1184 TranslatableCaption.of("permission.no_permission_event"), 1185 TagResolver.resolver( 1186 "node", 1187 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED) 1188 ) 1189 ); 1190 e.setCancelled(true); 1191 } 1192 } else { 1193 UUID uuid = pp.getUUID(); 1194 if (plot.isAdded(uuid)) { 1195 return; 1196 } 1197 if (plot.getFlag(MiscInteractFlag.class)) { 1198 return; 1199 } 1200 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER)) { 1201 pp.sendMessage( 1202 TranslatableCaption.of("permission.no_permission_event"), 1203 TagResolver.resolver( 1204 "node", 1205 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_OTHER) 1206 ) 1207 ); 1208 e.setCancelled(true); 1209 plot.debug(pp.getName() + " could not interact with " + entity.getType() 1210 + " because misc-interact = false"); 1211 } 1212 } 1213 } 1214 } 1215 1216 @EventHandler(priority = EventPriority.LOW) 1217 @SuppressWarnings("deprecation") // Paper deprecation 1218 public void onCancelledInteract(PlayerInteractEvent event) { 1219 if (event.isCancelled() && event.getAction() == Action.RIGHT_CLICK_AIR) { 1220 Player player = event.getPlayer(); 1221 BukkitPlayer pp = BukkitUtil.adapt(player); 1222 PlotArea area = pp.getPlotAreaAbs(); 1223 if (area == null) { 1224 return; 1225 } 1226 if (event.getAction() == Action.RIGHT_CLICK_AIR) { 1227 Material item = event.getMaterial(); 1228 if (item.toString().toLowerCase().endsWith("_egg")) { 1229 event.setCancelled(true); 1230 event.setUseItemInHand(Event.Result.DENY); 1231 } 1232 } 1233 ItemStack hand = player.getInventory().getItemInMainHand(); 1234 ItemStack offHand = player.getInventory().getItemInOffHand(); 1235 Material type = hand.getType(); 1236 Material offType = offHand.getType(); 1237 if (type == Material.AIR) { 1238 type = offType; 1239 } 1240 if (type.toString().toLowerCase().endsWith("_egg")) { 1241 Block block = player.getTargetBlockExact(5, FluidCollisionMode.SOURCE_ONLY); 1242 if (block != null && block.getType() != Material.AIR) { 1243 Location location = BukkitUtil.adapt(block.getLocation()); 1244 if (!this.eventDispatcher.checkPlayerBlockEvent(pp, PlayerBlockEventType.SPAWN_MOB, location, null, true)) { 1245 event.setCancelled(true); 1246 event.setUseItemInHand(Event.Result.DENY); 1247 } 1248 } 1249 } 1250 } 1251 } 1252 1253 @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) 1254 public void onInteract(PlayerInteractEvent event) { 1255 Player player = event.getPlayer(); 1256 BukkitPlayer pp = BukkitUtil.adapt(player); 1257 PlotArea area = pp.getPlotAreaAbs(); 1258 if (area == null) { 1259 return; 1260 } 1261 PlayerBlockEventType eventType; 1262 BlockType blocktype1; 1263 Block block = event.getClickedBlock(); 1264 if (block == null) { 1265 // We do not care in this case, the player is likely interacting with air ("nothing"). 1266 return; 1267 } 1268 Location location = BukkitUtil.adapt(block.getLocation()); 1269 Action action = event.getAction(); 1270 switch (action) { 1271 case PHYSICAL -> { 1272 eventType = PlayerBlockEventType.TRIGGER_PHYSICAL; 1273 blocktype1 = BukkitAdapter.asBlockType(block.getType()); 1274 } 1275 1276 //todo rearrange the right click code. it is all over the place. 1277 case RIGHT_CLICK_BLOCK -> { 1278 Material blockType = block.getType(); 1279 eventType = PlayerBlockEventType.INTERACT_BLOCK; 1280 blocktype1 = BukkitAdapter.asBlockType(block.getType()); 1281 1282 if (INTERACTABLE_MATERIALS != null 1283 ? INTERACTABLE_MATERIALS.contains(blockType.name()) 1284 : blockType.isInteractable()) { 1285 if (!player.isSneaking()) { 1286 break; 1287 } 1288 ItemStack hand = player.getInventory().getItemInMainHand(); 1289 ItemStack offHand = player.getInventory().getItemInOffHand(); 1290 1291 // sneaking players interact with blocks if both hands are empty 1292 if (hand.getType() == Material.AIR && offHand.getType() == Material.AIR) { 1293 break; 1294 } 1295 } 1296 1297 Material type = event.getMaterial(); 1298 1299 // in the following, lb needs to have the material of the item in hand i.e. type 1300 switch (type.toString()) { 1301 case "REDSTONE", "STRING", "PUMPKIN_SEEDS", "MELON_SEEDS", "COCOA_BEANS", "WHEAT_SEEDS", "BEETROOT_SEEDS", 1302 "SWEET_BERRIES", "GLOW_BERRIES" -> { 1303 return; 1304 } 1305 default -> { 1306 //eventType = PlayerBlockEventType.PLACE_BLOCK; 1307 if (type.isBlock()) { 1308 return; 1309 } 1310 } 1311 } 1312 if (PaperLib.isPaper()) { 1313 if (MaterialTags.SPAWN_EGGS.isTagged(type) || Material.EGG.equals(type)) { 1314 eventType = PlayerBlockEventType.SPAWN_MOB; 1315 break; 1316 } 1317 } else { 1318 if (type.toString().toLowerCase().endsWith("egg")) { 1319 eventType = PlayerBlockEventType.SPAWN_MOB; 1320 break; 1321 } 1322 } 1323 if (type.isEdible()) { 1324 //Allow all players to eat while also allowing the block place event to be fired 1325 return; 1326 } 1327 // Process creature spawning of armor stands & end crystals here if spawned by the player in order to be able to 1328 // reset the player's hand item if spawning needs to be cancelled. 1329 if (type == Material.ARMOR_STAND || type == Material.END_CRYSTAL) { 1330 Plot plot = location.getOwnedPlotAbs(); 1331 EntityType entityType = type == Material.ARMOR_STAND ? EntityType.ARMOR_STAND : END_CRYSTAL_ENTITY_TYPE; 1332 if (BukkitEntityUtil.checkEntity(entityType, plot)) { 1333 event.setCancelled(true); 1334 break; 1335 } 1336 } 1337 // Continue with normal place event checks 1338 if (type == Material.ARMOR_STAND) { 1339 location = BukkitUtil.adapt(block.getRelative(event.getBlockFace()).getLocation()); 1340 eventType = PlayerBlockEventType.PLACE_MISC; 1341 } 1342 if (org.bukkit.Tag.ITEMS_BOATS.isTagged(type) || MINECARTS.contains(type)) { 1343 eventType = PlayerBlockEventType.PLACE_VEHICLE; 1344 break; 1345 } 1346 if (type == Material.FIREWORK_ROCKET || type == Material.FIREWORK_STAR) { 1347 eventType = PlayerBlockEventType.SPAWN_MOB; 1348 break; 1349 } 1350 if (BOOKS.contains(type)) { 1351 eventType = PlayerBlockEventType.READ; 1352 break; 1353 } 1354 } 1355 case LEFT_CLICK_BLOCK -> { 1356 Material blockType = block.getType(); 1357 1358 // todo: when the code above is rearranged, it would be great to beautify this as well. 1359 // will code this as a temporary, specific bug fix (for dragon eggs) 1360 if (blockType != Material.DRAGON_EGG) { 1361 return; 1362 } 1363 1364 eventType = PlayerBlockEventType.INTERACT_BLOCK; 1365 blocktype1 = BukkitAdapter.asBlockType(block.getType()); 1366 } 1367 default -> { 1368 return; 1369 } 1370 } 1371 if (this.worldEdit != null && pp.getAttribute("worldedit")) { 1372 if (event.getMaterial() == Material.getMaterial(this.worldEdit.getConfiguration().wandItem)) { 1373 return; 1374 } 1375 } 1376 if (!this.eventDispatcher.checkPlayerBlockEvent(pp, eventType, location, blocktype1, true)) { 1377 event.setCancelled(true); 1378 event.setUseInteractedBlock(Event.Result.DENY); 1379 } 1380 } 1381 1382 // Boats can sometimes be placed on interactable blocks such as levers, 1383 // see PS-175. Armor stands, minecarts and end crystals (the other entities 1384 // supported by this event) don't have this issue. 1385 @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) 1386 public void onBoatPlace(EntityPlaceEvent event) { 1387 Player player = event.getPlayer(); 1388 if (player == null) { 1389 return; 1390 } 1391 Entity placed = event.getEntity(); 1392 if (!(placed instanceof Boat)) { 1393 return; 1394 } 1395 BukkitPlayer pp = BukkitUtil.adapt(event.getPlayer()); 1396 PlotArea area = pp.getPlotAreaAbs(); 1397 if (area == null) { 1398 return; 1399 } 1400 PlayerBlockEventType eventType = PlayerBlockEventType.PLACE_VEHICLE; 1401 Block block = event.getBlock(); 1402 BlockType blockType = BukkitAdapter.asBlockType(block.getType()); 1403 Location location = BukkitUtil.adapt(block.getLocation()); 1404 if (!PlotSquared.get().getEventDispatcher() 1405 .checkPlayerBlockEvent(pp, eventType, location, blockType, true)) { 1406 event.setCancelled(true); 1407 } 1408 } 1409 1410 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 1411 public void onBucketEmpty(PlayerBucketEmptyEvent event) { 1412 final Block block = event.getBlock(); 1413 Location location = BukkitUtil.adapt(block.getLocation()); 1414 PlotArea area = location.getPlotArea(); 1415 if (area == null) { 1416 return; 1417 } 1418 BukkitPlayer pp = BukkitUtil.adapt(event.getPlayer()); 1419 Plot plot = area.getPlot(location); 1420 final List<BlockTypeWrapper> use = 1421 Optional.ofNullable(plot).map(p -> p.getFlag(UseFlag.class)).orElse(area.isRoadFlags() ? 1422 area.getFlag(UseFlag.class) : Collections.emptyList()); 1423 BlockType type = BukkitAdapter.asBlockType(block.getType()); 1424 for (final BlockTypeWrapper blockTypeWrapper : use) { 1425 if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper 1426 .accepts(type)) { 1427 return; 1428 } 1429 } 1430 if (plot == null) { 1431 if (pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_ROAD)) { 1432 return; 1433 } 1434 pp.sendMessage( 1435 TranslatableCaption.of("permission.no_permission_event"), 1436 TagResolver.resolver("node", Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_ROAD)) 1437 ); 1438 event.setCancelled(true); 1439 } else if (!plot.hasOwner()) { 1440 if (pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_UNOWNED)) { 1441 return; 1442 } 1443 pp.sendMessage( 1444 TranslatableCaption.of("permission.no_permission_event"), 1445 TagResolver.resolver( 1446 "node", 1447 Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_UNOWNED) 1448 ) 1449 ); 1450 event.setCancelled(true); 1451 } else if (!plot.isAdded(pp.getUUID())) { 1452 if (pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER)) { 1453 return; 1454 } 1455 pp.sendMessage( 1456 TranslatableCaption.of("permission.no_permission_event"), 1457 TagResolver.resolver( 1458 "node", 1459 Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_OTHER) 1460 ) 1461 ); 1462 event.setCancelled(true); 1463 } else if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { 1464 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER)) { 1465 pp.sendMessage( 1466 TranslatableCaption.of("done.building_restricted") 1467 ); 1468 event.setCancelled(true); 1469 } 1470 } 1471 } 1472 1473 @EventHandler(priority = EventPriority.HIGHEST) 1474 public void onInventoryClose(InventoryCloseEvent event) { 1475 HumanEntity closer = event.getPlayer(); 1476 if (!(closer instanceof Player player)) { 1477 return; 1478 } 1479 PlotInventory.removePlotInventoryOpen(BukkitUtil.adapt(player)); 1480 } 1481 1482 @EventHandler(priority = EventPriority.MONITOR) 1483 public void onLeave(PlayerQuitEvent event) { 1484 TaskManager.removeFromTeleportQueue(event.getPlayer().getName()); 1485 BukkitPlayer pp = BukkitUtil.adapt(event.getPlayer()); 1486 pp.unregister(); 1487 plotListener.logout(pp.getUUID()); 1488 } 1489 1490 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 1491 public void onBucketFill(PlayerBucketFillEvent event) { 1492 Block blockClicked = event.getBlockClicked(); 1493 Location location = BukkitUtil.adapt(blockClicked.getLocation()); 1494 PlotArea area = location.getPlotArea(); 1495 if (area == null) { 1496 return; 1497 } 1498 Player player = event.getPlayer(); 1499 BukkitPlayer plotPlayer = BukkitUtil.adapt(player); 1500 Plot plot = area.getPlot(location); 1501 final List<BlockTypeWrapper> use = 1502 Optional.ofNullable(plot).map(p -> p.getFlag(UseFlag.class)).orElse(area.isRoadFlags() ? 1503 area.getFlag(UseFlag.class) : Collections.emptyList()); 1504 BlockType type = BukkitAdapter.asBlockType(blockClicked.getType()); 1505 for (final BlockTypeWrapper blockTypeWrapper : use) { 1506 if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper 1507 .accepts(type)) { 1508 return; 1509 } 1510 } 1511 if (plot == null) { 1512 if (plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_BUILD_ROAD)) { 1513 return; 1514 } 1515 plotPlayer.sendMessage( 1516 TranslatableCaption.of("permission.no_permission_event"), 1517 TagResolver.resolver("node", Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_ROAD)) 1518 ); 1519 event.setCancelled(true); 1520 } else if (!plot.hasOwner()) { 1521 if (plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_BUILD_UNOWNED)) { 1522 return; 1523 } 1524 plotPlayer.sendMessage( 1525 TranslatableCaption.of("permission.no_permission_event"), 1526 TagResolver.resolver( 1527 "node", 1528 Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_UNOWNED) 1529 ) 1530 ); 1531 event.setCancelled(true); 1532 } else if (!plot.isAdded(plotPlayer.getUUID())) { 1533 if (plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER)) { 1534 return; 1535 } 1536 plotPlayer.sendMessage( 1537 TranslatableCaption.of("permission.no_permission_event"), 1538 TagResolver.resolver( 1539 "node", 1540 Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_OTHER) 1541 ) 1542 ); 1543 event.setCancelled(true); 1544 } else if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { 1545 if (!plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER)) { 1546 plotPlayer.sendMessage( 1547 TranslatableCaption.of("done.building_restricted") 1548 ); 1549 event.setCancelled(true); 1550 } 1551 } 1552 } 1553 1554 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 1555 public void onHangingPlace(HangingPlaceEvent event) { 1556 Block block = event.getBlock().getRelative(event.getBlockFace()); 1557 Location location = BukkitUtil.adapt(block.getLocation()); 1558 PlotArea area = location.getPlotArea(); 1559 if (area == null) { 1560 return; 1561 } 1562 Player p = event.getPlayer(); 1563 if (p == null) { 1564 event.setCancelled(true); 1565 return; 1566 } 1567 BukkitPlayer pp = BukkitUtil.adapt(p); 1568 Plot plot = area.getPlot(location); 1569 if (plot == null) { 1570 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_ROAD)) { 1571 pp.sendMessage( 1572 TranslatableCaption.of("permission.no_permission_event"), 1573 TagResolver.resolver( 1574 "node", 1575 Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_ROAD) 1576 ) 1577 ); 1578 event.setCancelled(true); 1579 } 1580 } else { 1581 if (!plot.hasOwner()) { 1582 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_UNOWNED)) { 1583 pp.sendMessage( 1584 TranslatableCaption.of("permission.no_permission_event"), 1585 TagResolver.resolver( 1586 "node", 1587 Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_UNOWNED) 1588 ) 1589 ); 1590 event.setCancelled(true); 1591 } 1592 return; 1593 } 1594 if (!plot.isAdded(pp.getUUID())) { 1595 if (!plot.getFlag(HangingPlaceFlag.class)) { 1596 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER)) { 1597 pp.sendMessage( 1598 TranslatableCaption.of("permission.no_permission_event"), 1599 TagResolver.resolver( 1600 "node", 1601 Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_OTHER) 1602 ) 1603 ); 1604 event.setCancelled(true); 1605 } 1606 return; 1607 } 1608 } 1609 if (BukkitEntityUtil.checkEntity(event.getEntity(), plot)) { 1610 event.setCancelled(true); 1611 } 1612 1613 } 1614 } 1615 1616 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 1617 public void onHangingBreakByEntity(HangingBreakByEntityEvent event) { 1618 Entity remover = event.getRemover(); 1619 if (remover instanceof Player p) { 1620 Location location = BukkitUtil.adapt(event.getEntity().getLocation()); 1621 PlotArea area = location.getPlotArea(); 1622 if (area == null) { 1623 return; 1624 } 1625 BukkitPlayer pp = BukkitUtil.adapt(p); 1626 Plot plot = area.getPlot(location); 1627 if (plot == null) { 1628 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_ROAD)) { 1629 pp.sendMessage( 1630 TranslatableCaption.of("permission.no_permission_event"), 1631 TagResolver.resolver( 1632 "node", 1633 Tag.inserting(Permission.PERMISSION_ADMIN_DESTROY_ROAD) 1634 ) 1635 ); 1636 event.setCancelled(true); 1637 } 1638 } else if (!plot.hasOwner()) { 1639 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_UNOWNED)) { 1640 pp.sendMessage( 1641 TranslatableCaption.of("permission.no_permission_event"), 1642 TagResolver.resolver( 1643 "node", 1644 Tag.inserting(Permission.PERMISSION_ADMIN_DESTROY_UNOWNED) 1645 ) 1646 ); 1647 event.setCancelled(true); 1648 } 1649 } else if (!plot.isAdded(pp.getUUID())) { 1650 if (plot.getFlag(HangingBreakFlag.class)) { 1651 return; 1652 } 1653 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_OTHER)) { 1654 pp.sendMessage( 1655 TranslatableCaption.of("permission.no_permission_event"), 1656 TagResolver.resolver( 1657 "node", 1658 Tag.inserting(Permission.PERMISSION_ADMIN_DESTROY_OTHER) 1659 ) 1660 ); 1661 event.setCancelled(true); 1662 plot.debug(p.getName() 1663 + " could not break hanging entity because hanging-break = false"); 1664 } 1665 } 1666 } else if (remover instanceof Projectile p) { 1667 if (p.getShooter() instanceof Player shooter) { 1668 Location location = BukkitUtil.adapt(event.getEntity().getLocation()); 1669 PlotArea area = location.getPlotArea(); 1670 if (area == null) { 1671 return; 1672 } 1673 BukkitPlayer player = BukkitUtil.adapt(shooter); 1674 Plot plot = area.getPlot(BukkitUtil.adapt(event.getEntity().getLocation())); 1675 if (plot != null) { 1676 if (!plot.hasOwner()) { 1677 if (!player.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_UNOWNED)) { 1678 player.sendMessage( 1679 TranslatableCaption.of("permission.no_permission_event"), 1680 TagResolver.resolver( 1681 "node", 1682 Tag.inserting(Permission.PERMISSION_ADMIN_DESTROY_UNOWNED) 1683 ) 1684 ); 1685 event.setCancelled(true); 1686 } 1687 } else if (!plot.isAdded(player.getUUID())) { 1688 if (!plot.getFlag(HangingBreakFlag.class)) { 1689 if (!player.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_OTHER)) { 1690 player.sendMessage( 1691 TranslatableCaption.of("permission.no_permission_event"), 1692 TagResolver.resolver( 1693 "node", 1694 Tag.inserting(Permission.PERMISSION_ADMIN_DESTROY_OTHER) 1695 ) 1696 ); 1697 event.setCancelled(true); 1698 plot.debug(player.getName() 1699 + " could not break hanging entity because hanging-break = false"); 1700 } 1701 } 1702 } 1703 } 1704 } 1705 } else { 1706 event.setCancelled(true); 1707 } 1708 } 1709 1710 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 1711 public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { 1712 if (event.getRightClicked().getType() == EntityType.UNKNOWN) { 1713 return; 1714 } 1715 Location location = BukkitUtil.adapt(event.getRightClicked().getLocation()); 1716 PlotArea area = location.getPlotArea(); 1717 if (area == null) { 1718 return; 1719 } 1720 Player p = event.getPlayer(); 1721 BukkitPlayer pp = BukkitUtil.adapt(p); 1722 Plot plot = area.getPlot(location); 1723 if (plot == null && !area.isRoadFlags()) { 1724 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_ROAD)) { 1725 pp.sendMessage( 1726 TranslatableCaption.of("permission.no_permission_event"), 1727 TagResolver.resolver( 1728 "node", 1729 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_ROAD) 1730 ) 1731 ); 1732 event.setCancelled(true); 1733 } 1734 } else if (plot != null && !plot.hasOwner()) { 1735 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED)) { 1736 pp.sendMessage( 1737 TranslatableCaption.of("permission.no_permission_event"), 1738 TagResolver.resolver( 1739 "node", 1740 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED) 1741 ) 1742 ); 1743 event.setCancelled(true); 1744 } 1745 } else if ((plot != null && !plot.isAdded(pp.getUUID())) || (plot == null && area 1746 .isRoadFlags())) { 1747 final Entity entity = event.getRightClicked(); 1748 final com.sk89q.worldedit.world.entity.EntityType entityType = 1749 BukkitAdapter.adapt(entity.getType()); 1750 1751 FlagContainer flagContainer; 1752 if (plot == null) { 1753 flagContainer = area.getRoadFlagContainer(); 1754 } else { 1755 flagContainer = plot.getFlagContainer(); 1756 } 1757 1758 if (EntityCategories.HOSTILE.contains(entityType) && flagContainer 1759 .getFlag(HostileInteractFlag.class).getValue()) { 1760 return; 1761 } 1762 1763 if (EntityCategories.ANIMAL.contains(entityType) && flagContainer 1764 .getFlag(AnimalInteractFlag.class).getValue()) { 1765 return; 1766 } 1767 1768 // This actually makes use of the interface, so we don't use the 1769 // category 1770 if (entity instanceof Tameable && ((Tameable) entity).isTamed() && flagContainer 1771 .getFlag(TamedInteractFlag.class).getValue()) { 1772 return; 1773 } 1774 1775 if (EntityCategories.VEHICLE.contains(entityType) && flagContainer 1776 .getFlag(VehicleUseFlag.class).getValue()) { 1777 return; 1778 } 1779 1780 if (EntityCategories.PLAYER.contains(entityType) && flagContainer 1781 .getFlag(PlayerInteractFlag.class).getValue()) { 1782 return; 1783 } 1784 1785 if (EntityCategories.INTERACTION.contains(entityType) && flagContainer 1786 .getFlag(InteractionInteractFlag.class).getValue()) { 1787 return; 1788 } 1789 1790 if (EntityCategories.VILLAGER.contains(entityType) && flagContainer 1791 .getFlag(VillagerInteractFlag.class).getValue()) { 1792 return; 1793 } 1794 1795 if ((EntityCategories.HANGING.contains(entityType) || EntityCategories.OTHER 1796 .contains(entityType)) && flagContainer.getFlag(MiscInteractFlag.class) 1797 .getValue()) { 1798 return; 1799 } 1800 1801 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER)) { 1802 pp.sendMessage( 1803 TranslatableCaption.of("permission.no_permission_event"), 1804 TagResolver.resolver( 1805 "node", 1806 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_OTHER) 1807 ) 1808 ); 1809 event.setCancelled(true); 1810 } 1811 } 1812 } 1813 1814 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 1815 public void onVehicleDestroy(VehicleDestroyEvent event) { 1816 Location location = BukkitUtil.adapt(event.getVehicle().getLocation()); 1817 PlotArea area = location.getPlotArea(); 1818 if (area == null) { 1819 return; 1820 } 1821 Entity attacker = event.getAttacker(); 1822 if (attacker instanceof Player p) { 1823 BukkitPlayer pp = BukkitUtil.adapt(p); 1824 Plot plot = area.getPlot(location); 1825 if (plot == null) { 1826 if (!PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, VehicleBreakFlag.class, true) && !pp.hasPermission( 1827 Permission.PERMISSION_ADMIN_DESTROY_VEHICLE_ROAD 1828 )) { 1829 pp.sendMessage( 1830 TranslatableCaption.of("permission.no_permission_event"), 1831 TagResolver.resolver( 1832 "node", 1833 Tag.inserting(Permission.PERMISSION_ADMIN_DESTROY_VEHICLE_ROAD) 1834 ) 1835 ); 1836 event.setCancelled(true); 1837 } 1838 } else { 1839 if (!plot.hasOwner()) { 1840 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_VEHICLE_UNOWNED)) { 1841 pp.sendMessage( 1842 TranslatableCaption.of("permission.no_permission_event"), 1843 TagResolver.resolver( 1844 "node", 1845 Tag.inserting(Permission.PERMISSION_ADMIN_DESTROY_VEHICLE_UNOWNED) 1846 ) 1847 ); 1848 event.setCancelled(true); 1849 return; 1850 } 1851 return; 1852 } 1853 if (!plot.isAdded(pp.getUUID())) { 1854 if (plot.getFlag(VehicleBreakFlag.class)) { 1855 return; 1856 } 1857 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_VEHICLE_OTHER)) { 1858 pp.sendMessage( 1859 TranslatableCaption.of("permission.no_permission_event"), 1860 TagResolver.resolver( 1861 "node", 1862 Tag.inserting(Permission.PERMISSION_ADMIN_DESTROY_VEHICLE_OTHER) 1863 ) 1864 ); 1865 event.setCancelled(true); 1866 plot.debug(pp.getName() 1867 + " could not break vehicle because vehicle-break = false"); 1868 } 1869 } 1870 } 1871 } 1872 } 1873 1874 @EventHandler 1875 public void onItemDrop(PlayerDropItemEvent event) { 1876 Player player = event.getPlayer(); 1877 BukkitPlayer pp = BukkitUtil.adapt(player); 1878 Location location = pp.getLocation(); 1879 PlotArea area = location.getPlotArea(); 1880 if (area == null) { 1881 return; 1882 } 1883 Plot plot = location.getOwnedPlot(); 1884 if (plot == null) { 1885 if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, ItemDropFlag.class, false)) { 1886 event.setCancelled(true); 1887 } 1888 return; 1889 } 1890 UUID uuid = pp.getUUID(); 1891 if (!plot.isAdded(uuid)) { 1892 if (!plot.getFlag(ItemDropFlag.class)) { 1893 plot.debug(player.getName() + " could not drop item because of item-drop = false"); 1894 event.setCancelled(true); 1895 } 1896 } 1897 } 1898 1899 @EventHandler 1900 public void onItemPickup(EntityPickupItemEvent event) { 1901 LivingEntity ent = event.getEntity(); 1902 if (ent instanceof Player player) { 1903 BukkitPlayer pp = BukkitUtil.adapt(player); 1904 Location location = pp.getLocation(); 1905 PlotArea area = location.getPlotArea(); 1906 if (area == null) { 1907 return; 1908 } 1909 Plot plot = location.getOwnedPlot(); 1910 if (plot == null) { 1911 if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, DropProtectionFlag.class, true)) { 1912 event.setCancelled(true); 1913 } 1914 return; 1915 } 1916 UUID uuid = pp.getUUID(); 1917 if (!plot.isAdded(uuid) && plot.getFlag(DropProtectionFlag.class)) { 1918 plot.debug(player.getName() + " could not pick up item because of drop-protection = true"); 1919 event.setCancelled(true); 1920 } 1921 } 1922 } 1923 1924 @EventHandler 1925 public void onDeath(final PlayerDeathEvent event) { 1926 Location location = BukkitUtil.adapt(event.getEntity().getLocation()); 1927 PlotArea area = location.getPlotArea(); 1928 if (area == null) { 1929 return; 1930 } 1931 Plot plot = location.getOwnedPlot(); 1932 if (plot == null) { 1933 if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, KeepInventoryFlag.class, true)) { 1934 event.setCancelled(true); 1935 } 1936 return; 1937 } 1938 if (plot.getFlag(KeepInventoryFlag.class)) { 1939 plot.debug(event.getEntity().getName() + " kept their inventory because of keep-inventory = true"); 1940 event.getDrops().clear(); 1941 event.setKeepInventory(true); 1942 } 1943 } 1944 1945 @SuppressWarnings("deprecation") // #getLocate is needed for Spigot compatibility 1946 @EventHandler 1947 public void onLocaleChange(final PlayerLocaleChangeEvent event) { 1948 // The event is fired before the player is deemed online upon login 1949 if (!event.getPlayer().isOnline()) { 1950 return; 1951 } 1952 BukkitPlayer player = BukkitUtil.adapt(event.getPlayer()); 1953 // we're stripping the country code as we don't want to differ between countries 1954 player.setLocale(Locale.forLanguageTag(event.getLocale().substring(0, 2))); 1955 } 1956 1957 @EventHandler 1958 public void onPortalEnter(PlayerPortalEvent event) { 1959 Location location = BukkitUtil.adapt(event.getPlayer().getLocation()); 1960 PlotArea area = location.getPlotArea(); 1961 if (area == null) { 1962 return; 1963 } 1964 Plot plot = location.getOwnedPlot(); 1965 if (plot == null) { 1966 if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, DenyPortalTravelFlag.class, true)) { 1967 event.setCancelled(true); 1968 } 1969 return; 1970 } 1971 if (plot.getFlag(DenyPortalTravelFlag.class)) { 1972 plot.debug(event.getPlayer().getName() + " did not travel thru a portal because of deny-portal-travel = true"); 1973 event.setCancelled(true); 1974 } 1975 } 1976 1977 @EventHandler 1978 public void onPortalCreation(PortalCreateEvent event) { 1979 String world = event.getWorld().getName(); 1980 if (PlotSquared.get().getPlotAreaManager().getPlotAreasSet(world).size() == 0) { 1981 return; 1982 } 1983 BukkitPlayer pp = (event.getEntity() instanceof Player player) ? BukkitUtil.adapt(player) : null; 1984 int minX = Integer.MAX_VALUE; 1985 int maxX = Integer.MIN_VALUE; 1986 int minZ = Integer.MAX_VALUE; 1987 int maxZ = Integer.MIN_VALUE; 1988 for (BlockState state : event.getBlocks()) { 1989 minX = Math.min(state.getX(), minX); 1990 maxX = Math.max(state.getX(), maxX); 1991 minZ = Math.min(state.getZ(), minZ); 1992 maxZ = Math.max(state.getZ(), maxZ); 1993 } 1994 int y = event.getBlocks().get(0).getY(); // Don't need to worry about this too much 1995 for (Location location : List.of( // We don't care about duplicate locations 1996 Location.at(world, minX, y, minZ), 1997 Location.at(world, minX, y, maxZ), 1998 Location.at(world, maxX, y, minZ), 1999 Location.at(world, maxX, y, maxZ) 2000 )) { 2001 PlotArea area = location.getPlotArea(); 2002 if (area == null) { 2003 continue; 2004 } 2005 if (area.notifyIfOutsideBuildArea(pp, location.getY())) { 2006 event.setCancelled(true); 2007 return; 2008 } 2009 Plot plot = location.getOwnedPlot(); 2010 if (plot == null) { 2011 if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, DenyPortalsFlag.class, true)) { 2012 event.setCancelled(true); 2013 return; 2014 } 2015 continue; 2016 } 2017 if (plot.getFlag(DenyPortalsFlag.class)) { 2018 StringBuilder builder = new StringBuilder(); 2019 if (event.getEntity() != null) { 2020 builder.append(event.getEntity().getName()).append(" did not create a portal"); 2021 } else { 2022 builder.append("Portal creation cancelled"); 2023 } 2024 plot.debug(builder.append(" because of deny-portals = true").toString()); 2025 event.setCancelled(true); 2026 return; 2027 } 2028 } 2029 } 2030 2031 @EventHandler 2032 public void onPlayerTakeLecternBook(PlayerTakeLecternBookEvent event) { 2033 Player player = event.getPlayer(); 2034 BukkitPlayer pp = BukkitUtil.adapt(player); 2035 Location location = pp.getLocation(); 2036 PlotArea area = location.getPlotArea(); 2037 if (area == null) { 2038 return; 2039 } 2040 Plot plot = location.getOwnedPlot(); 2041 if (plot == null) { 2042 if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, LecternReadBookFlag.class, true)) { 2043 event.setCancelled(true); 2044 } 2045 return; 2046 } 2047 if (!plot.isAdded(pp.getUUID())) { 2048 if (plot.getFlag(LecternReadBookFlag.class)) { 2049 plot.debug(event.getPlayer().getName() + " could not take the book because of lectern-read-book = true"); 2050 event.setCancelled(true); 2051 } 2052 } 2053 } 2054 2055}