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 BukkitPlayer player = BukkitUtil.adapt(event.getPlayer()); 358 if (plot.isAdded(player.getUUID())) { 359 return; // allow for added players 360 } 361 if (!plot.getFlag(EditSignFlag.class) 362 && !event.getPlayer().hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER.toString())) { 363 plot.debug(event.getPlayer().getName() + " could not color the sign because of edit-sign = false"); 364 event.setCancelled(true); 365 } 366 } 367 } 368 } 369 370 @EventHandler(ignoreCancelled = true) 371 public void onEffect(@NonNull EntityPotionEffectEvent event) { 372 if (Settings.Enabled_Components.DISABLE_BEACON_EFFECT_OVERFLOW || 373 event.getCause() != EntityPotionEffectEvent.Cause.BEACON || 374 !(event.getEntity() instanceof Player player)) { 375 return; 376 } 377 378 UUID uuid = player.getUniqueId(); 379 PotionEffect effect = event.getNewEffect(); 380 if (effect == null) { 381 PotionEffect oldEffect = event.getOldEffect(); 382 if (oldEffect != null) { 383 String name = oldEffect.getType().getName(); 384 plotListener.addEffect(uuid, name, -1); 385 } 386 } else { 387 long expiresAt = System.currentTimeMillis() + effect.getDuration() * 50L; //Convert ticks to milliseconds 388 String name = effect.getType().getName(); 389 plotListener.addEffect(uuid, name, expiresAt); 390 } 391 } 392 393 @EventHandler 394 public void onVehicleEntityCollision(VehicleEntityCollisionEvent e) { 395 if (e.getVehicle() instanceof Boat) { 396 Location location = BukkitUtil.adapt(e.getEntity().getLocation()); 397 if (location.isPlotArea()) { 398 if (e.getEntity() instanceof Player) { 399 PlotPlayer<Player> player = BukkitUtil.adapt((Player) e.getEntity()); 400 Plot plot = player.getCurrentPlot(); 401 if (plot != null) { 402 if (!plot.isAdded(player.getUUID())) { 403 //Here the event is only canceled if the player is not the owner 404 //of the property on which he is located. 405 e.setCancelled(true); 406 } 407 } else { 408 e.setCancelled(true); 409 } 410 } else { 411 //Here the event is cancelled too, otherwise you can move the 412 //boat with EchoPets or other mobs running around on the plot. 413 e.setCancelled(true); 414 } 415 } 416 } 417 } 418 419 @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) 420 public void playerCommand(PlayerCommandPreprocessEvent event) { 421 String msg = event.getMessage().replace("/", "").toLowerCase(Locale.ROOT).trim(); 422 if (msg.isEmpty()) { 423 return; 424 } 425 Player player = event.getPlayer(); 426 PlotPlayer<Player> plotPlayer = BukkitUtil.adapt(player); 427 Location location = plotPlayer.getLocation(); 428 PlotArea area = location.getPlotArea(); 429 if (area == null) { 430 return; 431 } 432 String[] parts = msg.split(" "); 433 Plot plot = plotPlayer.getCurrentPlot(); 434 // Check WorldEdit 435 switch (parts[0]) { 436 case "up", "worldedit:up" -> { 437 if (plot == null || (!plot.isAdded(plotPlayer.getUUID()) && !plotPlayer.hasPermission( 438 Permission.PERMISSION_ADMIN_BUILD_OTHER, 439 true 440 ))) { 441 event.setCancelled(true); 442 return; 443 } 444 } 445 } 446 if (plot == null && !area.isRoadFlags()) { 447 return; 448 } 449 450 List<String> blockedCommands = plot != null ? 451 plot.getFlag(BlockedCmdsFlag.class) : 452 area.getFlag(BlockedCmdsFlag.class); 453 if (blockedCommands.isEmpty()) { 454 return; 455 } 456 if (plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_BLOCKED_CMDS)) { 457 return; 458 } 459 // When using namespaced commands, we're not interested in the namespace 460 String part = parts[0]; 461 if (part.contains(":")) { 462 String[] namespaced = part.split(":"); 463 part = namespaced[1]; 464 msg = msg.substring(namespaced[0].length() + 1); 465 } 466 msg = replaceAliases(msg, part); 467 for (String blocked : blockedCommands) { 468 if (blocked.equalsIgnoreCase(msg)) { 469 String perm; 470 if (plot != null && plot.isAdded(plotPlayer.getUUID())) { 471 perm = "plots.admin.command.blocked-cmds.shared"; 472 } else { 473 perm = "plots.admin.command.blocked-cmds.road"; 474 } 475 if (!plotPlayer.hasPermission(perm)) { 476 plotPlayer.sendMessage(TranslatableCaption.of("blockedcmds.command_blocked")); 477 event.setCancelled(true); 478 } 479 return; 480 } 481 } 482 } 483 484 private String replaceAliases(String msg, String part) { 485 String s1 = part; 486 Set<String> aliases = new HashSet<>(); 487 for (HelpTopic cmdLabel : Bukkit.getServer().getHelpMap().getHelpTopics()) { 488 if (part.equals(cmdLabel.getName())) { 489 break; 490 } 491 String label = cmdLabel.getName().replaceFirst("/", ""); 492 if (aliases.contains(label)) { 493 continue; 494 } 495 PluginCommand p = Bukkit.getPluginCommand(label); 496 if (p != null) { 497 for (String a : p.getAliases()) { 498 if (aliases.contains(a)) { 499 continue; 500 } 501 aliases.add(a); 502 a = a.replaceFirst("/", ""); 503 if (!a.equals(label) && a.equals(part)) { 504 part = label; 505 break; 506 } 507 } 508 } 509 } 510 if (!s1.equals(part)) { 511 msg = msg.replace(s1, part); 512 } 513 return msg; 514 } 515 516 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 517 public void onPreLogin(final AsyncPlayerPreLoginEvent event) { 518 final UUID uuid; 519 if (Settings.UUID.OFFLINE) { 520 if (Settings.UUID.FORCE_LOWERCASE) { 521 uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + event.getName().toLowerCase()).getBytes(Charsets.UTF_8)); 522 } else { 523 uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + event.getName()).getBytes(Charsets.UTF_8)); 524 } 525 } else { 526 uuid = event.getUniqueId(); 527 } 528 PlotSquared.get().getImpromptuUUIDPipeline().storeImmediately(event.getName(), uuid); 529 } 530 531 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 532 @SuppressWarnings("deprecation") // Paper deprecation 533 public void onConnect(PlayerJoinEvent event) { 534 final Player player = event.getPlayer(); 535 PlotSquared.platform().playerManager().removePlayer(player.getUniqueId()); 536 final PlotPlayer<Player> pp = BukkitUtil.adapt(player); 537 538 // we're stripping the country code as we don't want to differ between countries 539 pp.setLocale(Locale.forLanguageTag(player.getLocale().substring(0, 2))); 540 541 Location location = pp.getLocation(); 542 PlotArea area = location.getPlotArea(); 543 if (area != null) { 544 Plot plot = area.getPlot(location); 545 if (plot != null) { 546 plotListener.plotEntry(pp, plot); 547 } 548 } 549 // Delayed 550 551 // Async 552 TaskManager.runTaskLaterAsync( 553 () -> { 554 if (!player.hasPlayedBefore() && player.isOnline()) { 555 player.saveData(); 556 } 557 this.eventDispatcher.doJoinTask(pp); 558 }, TaskTime.seconds(1L) 559 ); 560 561 if (pp.hasPermission(Permission.PERMISSION_ADMIN_UPDATE_NOTIFICATION.toString()) && Settings.Enabled_Components.UPDATE_NOTIFICATIONS 562 && PremiumVerification.isPremium() && UpdateUtility.hasUpdate) { 563 Caption boundary = TranslatableCaption.of("update.update_boundary"); 564 Caption updateNotification = TranslatableCaption.of("update.update_notification"); 565 pp.sendMessage(boundary); 566 pp.sendMessage( 567 updateNotification, 568 TagResolver.builder() 569 .tag("p2version", Tag.inserting(Component.text(UpdateUtility.internalVersion.versionString()))) 570 .tag("spigotversion", Tag.inserting(Component.text(UpdateUtility.spigotVersion))) 571 .tag("downloadurl", Tag.preProcessParsed("https://www.spigotmc.org/resources/77506/updates")) 572 .build() 573 ); 574 pp.sendMessage(boundary); 575 } 576 } 577 578 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 579 public void playerRespawn(PlayerRespawnEvent event) { 580 Player player = event.getPlayer(); 581 PlotPlayer<Player> pp = BukkitUtil.adapt(player); 582 this.eventDispatcher.doRespawnTask(pp); 583 } 584 585 @SuppressWarnings("deprecation") // We explicitly want #getHomeSynchronous here 586 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 587 public void onTeleport(PlayerTeleportEvent event) { 588 Player player = event.getPlayer(); 589 //We need to account for bad plugins like NoCheatPlus that teleports player on/before login -_- 590 if (!player.isOnline()) { 591 return; 592 } 593 BukkitPlayer pp = BukkitUtil.adapt(player); 594 try (final MetaDataAccess<Plot> lastPlotAccess = 595 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { 596 Plot lastPlot = lastPlotAccess.get().orElse(null); 597 org.bukkit.Location to = event.getTo(); 598 //noinspection ConstantConditions 599 if (to != null) { 600 Location location = BukkitUtil.adapt(to); 601 PlotArea area = location.getPlotArea(); 602 if (area == null) { 603 if (lastPlot != null) { 604 plotListener.plotExit(pp, lastPlot, null, null); 605 lastPlotAccess.remove(); 606 } 607 try (final MetaDataAccess<Location> lastLocationAccess = 608 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { 609 lastLocationAccess.remove(); 610 } 611 return; 612 } 613 Plot plot = area.getPlot(location); 614 if (plot != null && !plot.equals(lastPlot)) { 615 final boolean result = DenyTeleportFlag.allowsTeleport(pp, plot); 616 // there is one possibility to still allow teleportation: 617 // to is identical to the plot's home location, and untrusted-visit is true 618 // i.e. untrusted-visit can override deny-teleport 619 // this is acceptable, because otherwise it wouldn't make sense to have both flags set 620 if (result || (plot.getFlag(UntrustedVisitFlag.class) && plot 621 .getHomeSynchronous() 622 .equals(BukkitUtil.adaptComplete(to)))) { 623 // returns false if the player is not allowed to enter the plot (if they are denied, for example) 624 // don't let the move event cancel the entry after teleport, but rather catch and cancel early (#4647) 625 if (!plotListener.plotEntry(pp, plot)) { 626 event.setCancelled(true); 627 } 628 } else { 629 pp.sendMessage( 630 TranslatableCaption.of("deny.no_enter"), 631 TagResolver.resolver("plot", Tag.inserting(Component.text(plot.toString()))) 632 ); 633 event.setCancelled(true); 634 } 635 } 636 } 637 } 638 playerMove(event); 639 } 640 641 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 642 public void onWorldChanged(PlayerChangedWorldEvent event) { 643 Player player = event.getPlayer(); 644 BukkitPlayer pp = BukkitUtil.adapt(player); 645 if (this.worldEdit != null) { 646 if (!pp.hasPermission(Permission.PERMISSION_WORLDEDIT_BYPASS)) { 647 if (pp.getAttribute("worldedit")) { 648 pp.removeAttribute("worldedit"); 649 } 650 } 651 } 652 } 653 654 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 655 public void vehicleMove(VehicleMoveEvent event) 656 throws IllegalAccessException { 657 final org.bukkit.Location from = event.getFrom(); 658 final org.bukkit.Location to = event.getTo(); 659 660 int toX, toZ; 661 if ((toX = MathMan.roundInt(to.getX())) != MathMan.roundInt(from.getX()) | (toZ = MathMan.roundInt(to.getZ())) != MathMan 662 .roundInt(from.getZ())) { 663 Vehicle vehicle = event.getVehicle(); 664 665 // Check allowed 666 if (!vehicle.getPassengers().isEmpty()) { 667 Entity passenger = vehicle.getPassengers().get(0); 668 669 if (passenger instanceof final Player player) { 670 // reset 671 if (moveTmp == null) { 672 moveTmp = new PlayerMoveEvent(null, from, to); 673 } 674 moveTmp.setFrom(from); 675 moveTmp.setTo(to); 676 moveTmp.setCancelled(false); 677 fieldPlayer.set(moveTmp, player); 678 679 List<Entity> passengers = vehicle.getPassengers(); 680 681 this.playerMove(moveTmp); 682 org.bukkit.Location dest; 683 if (moveTmp.isCancelled()) { 684 dest = from; 685 } else if (MathMan.roundInt(moveTmp.getTo().getX()) != toX || MathMan.roundInt(moveTmp 686 .getTo() 687 .getZ()) != toZ) { 688 dest = to; 689 } else { 690 dest = null; 691 } 692 if (dest != null) { 693 vehicle.eject(); 694 vehicle.setVelocity(new Vector(0d, 0d, 0d)); 695 PaperLib.teleportAsync(vehicle, dest); 696 passengers.forEach(vehicle::addPassenger); 697 return; 698 } 699 } 700 if (Settings.Enabled_Components.KILL_ROAD_VEHICLES) { 701 final com.sk89q.worldedit.world.entity.EntityType entityType = BukkitAdapter.adapt(vehicle.getType()); 702 // Horses etc are vehicles, but they're also animals 703 // so this filters out all living entities 704 if (EntityCategories.VEHICLE.contains(entityType) && !EntityCategories.ANIMAL.contains(entityType)) { 705 List<MetadataValue> meta = vehicle.getMetadata("plot"); 706 Plot toPlot = BukkitUtil.adapt(to).getPlot(); 707 if (!meta.isEmpty()) { 708 Plot origin = (Plot) meta.get(0).value(); 709 if (origin != null && !origin.getBasePlot(false).equals(toPlot)) { 710 vehicle.remove(); 711 } 712 } else if (toPlot != null) { 713 vehicle.setMetadata("plot", new FixedMetadataValue((Plugin) PlotSquared.platform(), toPlot)); 714 } 715 } 716 } 717 } 718 719 } 720 } 721 722 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 723 public void playerMove(PlayerMoveEvent event) { 724 org.bukkit.Location from = event.getFrom(); 725 org.bukkit.Location to = event.getTo(); 726 int x2; 727 if (MathMan.roundInt(from.getX()) != (x2 = MathMan.roundInt(to.getX()))) { 728 Player player = event.getPlayer(); 729 BukkitPlayer pp = BukkitUtil.adapt(player); 730 // Cancel teleport 731 if (TaskManager.removeFromTeleportQueue(pp.getName())) { 732 pp.sendMessage(TranslatableCaption.of("teleport.teleport_failed")); 733 } 734 // Set last location 735 Location location = BukkitUtil.adapt(to); 736 try (final MetaDataAccess<Location> lastLocationAccess = 737 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { 738 lastLocationAccess.remove(); 739 } 740 PlotArea area = location.getPlotArea(); 741 if (area == null) { 742 try (final MetaDataAccess<Plot> lastPlotAccess = 743 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { 744 lastPlotAccess.remove(); 745 } 746 return; 747 } 748 Plot now = area.getPlot(location); 749 Plot lastPlot; 750 try (final MetaDataAccess<Plot> lastPlotAccess = 751 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { 752 lastPlot = lastPlotAccess.get().orElse(null); 753 } 754 if (now == null) { 755 try (final MetaDataAccess<Boolean> kickAccess = 756 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_KICK)) { 757 if (lastPlot != null && !plotListener.plotExit(pp, lastPlot, now, area) && this.tmpTeleport && !kickAccess.get().orElse( 758 false)) { 759 pp.sendMessage( 760 TranslatableCaption.of("permission.no_permission_event"), 761 TagResolver.resolver( 762 "node", 763 Tag.inserting(Permission.PERMISSION_ADMIN_EXIT_DENIED) 764 ) 765 ); 766 this.tmpTeleport = false; 767 if (lastPlot.equals(BukkitUtil.adapt(from).getPlot())) { 768 player.teleport(from); 769 } else { 770 player.teleport(player.getWorld().getSpawnLocation()); 771 } 772 this.tmpTeleport = true; 773 event.setCancelled(true); 774 return; 775 } 776 } 777 } else if (now.equals(lastPlot)) { 778 ForceFieldListener.handleForcefield(player, pp, now); 779 } else if (!plotListener.plotEntry(pp, now) && this.tmpTeleport) { 780 pp.sendMessage( 781 TranslatableCaption.of("deny.no_enter"), 782 TagResolver.resolver("plot", Tag.inserting(Component.text(now.toString()))) 783 ); 784 this.tmpTeleport = false; 785 to.setX(from.getBlockX()); 786 to.setY(from.getBlockY()); 787 to.setZ(from.getBlockZ()); 788 player.teleport(event.getTo()); 789 this.tmpTeleport = true; 790 return; 791 } 792 int border = area.getBorder(true); 793 int x1; 794 if (x2 > border && this.tmpTeleport) { 795 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_BORDER)) { 796 to.setX(border - 1); 797 this.tmpTeleport = false; 798 player.teleport(event.getTo()); 799 this.tmpTeleport = true; 800 pp.sendMessage(TranslatableCaption.of("border.denied")); 801 } else if (MathMan.roundInt(from.getX()) <= border) { // Only send if they just moved out of the border 802 pp.sendMessage(TranslatableCaption.of("border.bypass.exited")); 803 } 804 } else if (x2 < -border && this.tmpTeleport) { 805 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_BORDER)) { 806 to.setX(-border + 1); 807 this.tmpTeleport = false; 808 player.teleport(event.getTo()); 809 this.tmpTeleport = true; 810 pp.sendMessage(TranslatableCaption.of("border.denied")); 811 } else if (MathMan.roundInt(from.getX()) >= -border) { // Only send if they just moved out of the border 812 pp.sendMessage(TranslatableCaption.of("border.bypass.exited")); 813 } 814 } else if (((x1 = MathMan.roundInt(from.getX())) >= border && x2 <= border) || (x1 <= -border && x2 >= -border)) { 815 if (pp.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_BORDER)) { 816 pp.sendMessage(TranslatableCaption.of("border.bypass.entered")); 817 } 818 } 819 } 820 int z2; 821 if (MathMan.roundInt(from.getZ()) != (z2 = MathMan.roundInt(to.getZ()))) { 822 Player player = event.getPlayer(); 823 BukkitPlayer pp = BukkitUtil.adapt(player); 824 // Cancel teleport 825 if (TaskManager.removeFromTeleportQueue(pp.getName())) { 826 pp.sendMessage(TranslatableCaption.of("teleport.teleport_failed")); 827 } 828 // Set last location 829 Location location = BukkitUtil.adapt(to); 830 try (final MetaDataAccess<Location> lastLocationAccess = 831 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { 832 lastLocationAccess.set(location); 833 } 834 PlotArea area = location.getPlotArea(); 835 if (area == null) { 836 try (final MetaDataAccess<Plot> lastPlotAccess = 837 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { 838 lastPlotAccess.remove(); 839 } 840 return; 841 } 842 Plot plot = area.getPlot(location); 843 Plot lastPlot; 844 try (final MetaDataAccess<Plot> lastPlotAccess = 845 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { 846 lastPlot = lastPlotAccess.get().orElse(null); 847 } 848 if (plot == null) { 849 try (final MetaDataAccess<Boolean> kickAccess = 850 pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_KICK)) { 851 if (lastPlot != null && !plotListener.plotExit(pp, lastPlot, null, area) && this.tmpTeleport && !kickAccess.get().orElse( 852 false)) { 853 pp.sendMessage( 854 TranslatableCaption.of("permission.no_permission_event"), 855 TagResolver.resolver( 856 "node", 857 Tag.inserting(Permission.PERMISSION_ADMIN_EXIT_DENIED) 858 ) 859 ); 860 this.tmpTeleport = false; 861 if (lastPlot.equals(BukkitUtil.adapt(from).getPlot())) { 862 player.teleport(from); 863 } else { 864 player.teleport(player.getWorld().getSpawnLocation()); 865 } 866 this.tmpTeleport = true; 867 event.setCancelled(true); 868 return; 869 } 870 } 871 } else if (plot.equals(lastPlot)) { 872 ForceFieldListener.handleForcefield(player, pp, plot); 873 } else if (!plotListener.plotEntry(pp, plot) && this.tmpTeleport) { 874 pp.sendMessage( 875 TranslatableCaption.of("deny.no_enter"), 876 TagResolver.resolver("plot", Tag.inserting(Component.text(plot.toString()))) 877 ); 878 this.tmpTeleport = false; 879 player.teleport(from); 880 to.setX(from.getBlockX()); 881 to.setY(from.getBlockY()); 882 to.setZ(from.getBlockZ()); 883 player.teleport(event.getTo()); 884 this.tmpTeleport = true; 885 return; 886 } 887 int border = area.getBorder(true); 888 int z1; 889 if (z2 > border && this.tmpTeleport) { 890 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_BORDER)) { 891 to.setZ(border - 1); 892 this.tmpTeleport = false; 893 player.teleport(event.getTo()); 894 this.tmpTeleport = true; 895 pp.sendMessage(TranslatableCaption.of("border.denied")); 896 } else if (MathMan.roundInt(from.getZ()) <= border) { // Only send if they just moved out of the border 897 pp.sendMessage(TranslatableCaption.of("border.bypass.exited")); 898 } 899 } else if (z2 < -border && this.tmpTeleport) { 900 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_BORDER)) { 901 to.setZ(-border + 1); 902 this.tmpTeleport = false; 903 player.teleport(event.getTo()); 904 this.tmpTeleport = true; 905 pp.sendMessage(TranslatableCaption.of("border.denied")); 906 } else if (MathMan.roundInt(from.getZ()) >= -border) { // Only send if they just moved out of the border 907 pp.sendMessage(TranslatableCaption.of("border.bypass.exited")); 908 } 909 } else if (((z1 = MathMan.roundInt(from.getZ())) >= border && z2 <= border) || (z1 <= -border && z2 >= -border)) { 910 if (pp.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_BORDER)) { 911 pp.sendMessage(TranslatableCaption.of("border.bypass.entered")); 912 } 913 } 914 } 915 } 916 917 @EventHandler(priority = EventPriority.LOW) 918 @SuppressWarnings("deprecation") // Paper deprecation 919 public void onChat(AsyncPlayerChatEvent event) { 920 if (event.isCancelled()) { 921 return; 922 } 923 924 BukkitPlayer plotPlayer = BukkitUtil.adapt(event.getPlayer()); 925 Location location = plotPlayer.getLocation(); 926 PlotArea area = location.getPlotArea(); 927 if (area == null) { 928 return; 929 } 930 Plot plot = area.getPlot(location); 931 if (plot == null) { 932 return; 933 } 934 if (!((plot.getFlag(ChatFlag.class) && area.isPlotChat() && plotPlayer.getAttribute("chat")) 935 || area.isForcingPlotChat())) { 936 return; 937 } 938 if (plot.isDenied(plotPlayer.getUUID()) && !plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_CHAT_BYPASS)) { 939 return; 940 } 941 event.setCancelled(true); 942 Set<Player> recipients = event.getRecipients(); 943 recipients.clear(); 944 Set<PlotPlayer<?>> spies = new HashSet<>(); 945 Set<PlotPlayer<?>> plotRecipients = new HashSet<>(); 946 for (final PlotPlayer<?> pp : PlotSquared.platform().playerManager().getPlayers()) { 947 if (pp.getAttribute("chatspy")) { 948 spies.add(pp); 949 } else { 950 Plot current = pp.getCurrentPlot(); 951 if (current != null && current.getBasePlot(false).equals(plot)) { 952 plotRecipients.add(pp); 953 } 954 } 955 } 956 String message = event.getMessage(); 957 String sender = event.getPlayer().getDisplayName(); 958 PlotId id = plot.getId(); 959 String worldName = plot.getWorldName(); 960 Caption msg = TranslatableCaption.of("chat.plot_chat_format"); 961 TagResolver.Builder builder = TagResolver.builder(); 962 builder.tag("world", Tag.inserting(Component.text(worldName))); 963 builder.tag("plot_id", Tag.inserting(Component.text(id.toString()))); 964 builder.tag("sender", Tag.inserting(Component.text(sender))); 965 if (plotPlayer.hasPermission("plots.chat.color")) { 966 builder.tag( 967 "msg", Tag.inserting(MiniMessage.miniMessage().deserialize( 968 message, 969 TagResolver.resolver( 970 StandardTags.color(), StandardTags.gradient(), 971 StandardTags.rainbow(), StandardTags.decorations() 972 ) 973 )) 974 ); 975 } else { 976 builder.tag("msg", Tag.inserting(Component.text(message))); 977 } 978 for (PlotPlayer<?> receiver : plotRecipients) { 979 receiver.sendMessage(msg, builder.build()); 980 } 981 if (!spies.isEmpty()) { 982 Caption spymsg = TranslatableCaption.of("chat.plot_chat_spy_format"); 983 for (PlotPlayer<?> player : spies) { 984 player.sendMessage(spymsg, builder.tag("message", Tag.inserting(Component.text(message))).build()); 985 } 986 } 987 if (Settings.Chat.LOG_PLOTCHAT_TO_CONSOLE) { 988 Caption spymsg = TranslatableCaption.of("chat.plot_chat_spy_format"); 989 ConsolePlayer.getConsole().sendMessage( 990 spymsg, 991 builder.tag("message", Tag.inserting(Component.text(message))).build() 992 ); 993 } 994 } 995 996 @SuppressWarnings("deprecation") 997 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 998 public void onInventoryClick(InventoryClickEvent event) { 999 /*if (!event.isLeftClick() || (event.getAction() != InventoryAction.PLACE_ALL) || event 1000 .isShiftClick()) { 1001 return; 1002 }*/ 1003 HumanEntity entity = event.getWhoClicked(); 1004 if (!(entity instanceof Player) || !this.plotAreaManager 1005 .hasPlotArea(entity.getWorld().getName())) { 1006 return; 1007 } 1008 1009 HumanEntity clicker = event.getWhoClicked(); 1010 if (!(clicker instanceof Player player)) { 1011 return; 1012 } 1013 BukkitPlayer pp = BukkitUtil.adapt(player); 1014 final PlotInventory inventory = PlotInventory.getOpenPlotInventory(pp); 1015 if (inventory != null && event.getRawSlot() == event.getSlot()) { 1016 if (!inventory.onClick(event.getSlot())) { 1017 event.setResult(Event.Result.DENY); 1018 event.setCancelled(true); 1019 inventory.close(); 1020 } 1021 } 1022 PlayerInventory inv = player.getInventory(); 1023 int slot = inv.getHeldItemSlot(); 1024 if ((slot > 8) || !event.getEventName().equals("InventoryCreativeEvent")) { 1025 return; 1026 } 1027 ItemStack oldItem = inv.getItemInHand(); 1028 ItemMeta oldMeta = oldItem.getItemMeta(); 1029 ItemStack newItem = event.getCursor(); 1030 ItemMeta newMeta = newItem.getItemMeta(); 1031 1032 if (event.getClick() == ClickType.CREATIVE) { 1033 final Plot plot = pp.getCurrentPlot(); 1034 if (plot != null) { 1035 if (plot.getFlag(PreventCreativeCopyFlag.class) && !plot 1036 .isAdded(player.getUniqueId()) && !pp.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER)) { 1037 final ItemStack newStack = 1038 new ItemStack(newItem.getType(), newItem.getAmount()); 1039 event.setCursor(newStack); 1040 plot.debug(player.getName() 1041 + " could not creative-copy an item because prevent-creative-copy = true"); 1042 } 1043 } else { 1044 PlotArea area = pp.getPlotAreaAbs(); 1045 if (area != null && PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, PreventCreativeCopyFlag.class, true)) { 1046 final ItemStack newStack = 1047 new ItemStack(newItem.getType(), newItem.getAmount()); 1048 event.setCursor(newStack); 1049 } 1050 } 1051 return; 1052 } 1053 1054 String newLore = ""; 1055 if (newMeta != null) { 1056 List<String> lore = newMeta.getLore(); 1057 if (lore != null) { 1058 newLore = lore.toString(); 1059 } 1060 } 1061 String oldLore = ""; 1062 if (oldMeta != null) { 1063 List<String> lore = oldMeta.getLore(); 1064 if (lore != null) { 1065 oldLore = lore.toString(); 1066 } 1067 } 1068 Material itemType = newItem.getType(); 1069 if (!"[(+NBT)]".equals(newLore) || (oldItem.equals(newItem) && newLore.equals(oldLore))) { 1070 if (newMeta == null || (itemType != Material.LEGACY_BANNER && itemType != Material.PLAYER_HEAD)) { 1071 return; 1072 } 1073 } 1074 Block block = player.getTargetBlock(null, 7); 1075 org.bukkit.block.BlockState state = block.getState(); 1076 Material stateType = state.getType(); 1077 if (stateType != itemType) { 1078 if (stateType == Material.LEGACY_WALL_BANNER || stateType == Material.LEGACY_STANDING_BANNER) { 1079 if (itemType != Material.LEGACY_BANNER) { 1080 return; 1081 } 1082 } else if (stateType == Material.LEGACY_SKULL) { 1083 if (itemType != Material.LEGACY_SKULL_ITEM) { 1084 return; 1085 } 1086 } else { 1087 return; 1088 } 1089 } 1090 Location location = BukkitUtil.adapt(state.getLocation()); 1091 PlotArea area = location.getPlotArea(); 1092 if (area == null) { 1093 return; 1094 } 1095 Plot plot = area.getPlotAbs(location); 1096 boolean cancelled = false; 1097 if (plot == null) { 1098 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_ROAD)) { 1099 pp.sendMessage( 1100 TranslatableCaption.of("permission.no_permission_event"), 1101 TagResolver.resolver( 1102 "node", 1103 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_ROAD) 1104 ) 1105 ); 1106 cancelled = true; 1107 } 1108 } else if (!plot.hasOwner()) { 1109 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED)) { 1110 pp.sendMessage( 1111 TranslatableCaption.of("permission.no_permission_event"), 1112 TagResolver.resolver( 1113 "node", 1114 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED) 1115 ) 1116 ); 1117 cancelled = true; 1118 } 1119 } else { 1120 UUID uuid = pp.getUUID(); 1121 if (!plot.isAdded(uuid)) { 1122 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER)) { 1123 pp.sendMessage( 1124 TranslatableCaption.of("permission.no_permission_event"), 1125 TagResolver.resolver( 1126 "node", 1127 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_OTHER) 1128 ) 1129 ); 1130 cancelled = true; 1131 } 1132 } 1133 } 1134 if (cancelled) { 1135 if ((oldItem.getType() == newItem.getType()) && (oldItem.getDurability() == newItem 1136 .getDurability())) { 1137 event.setCursor( 1138 new ItemStack(newItem.getType(), newItem.getAmount(), newItem.getDurability())); 1139 event.setCancelled(true); 1140 return; 1141 } 1142 event.setCursor( 1143 new ItemStack(newItem.getType(), newItem.getAmount(), newItem.getDurability())); 1144 } 1145 } 1146 1147 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 1148 public void onInteract(PlayerInteractAtEntityEvent e) { 1149 Entity entity = e.getRightClicked(); 1150 if (!(entity instanceof ArmorStand) && !(entity instanceof ItemFrame)) { 1151 return; 1152 } 1153 Location location = BukkitUtil.adapt(e.getRightClicked().getLocation()); 1154 PlotArea area = location.getPlotArea(); 1155 if (area == null) { 1156 return; 1157 } 1158 EntitySpawnListener.testNether(entity); 1159 Plot plot = location.getPlotAbs(); 1160 BukkitPlayer pp = BukkitUtil.adapt(e.getPlayer()); 1161 if (plot == null) { 1162 if (!PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, MiscInteractFlag.class, true) && !pp.hasPermission( 1163 Permission.PERMISSION_ADMIN_INTERACT_ROAD 1164 )) { 1165 pp.sendMessage( 1166 TranslatableCaption.of("permission.no_permission_event"), 1167 TagResolver.resolver( 1168 "node", 1169 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_ROAD) 1170 ) 1171 ); 1172 e.setCancelled(true); 1173 } 1174 } else { 1175 if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { 1176 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER)) { 1177 pp.sendMessage(TranslatableCaption.of("done.building_restricted")); 1178 e.setCancelled(true); 1179 return; 1180 } 1181 } 1182 if (!plot.hasOwner()) { 1183 if (!pp.hasPermission("plots.admin.interact.unowned")) { 1184 pp.sendMessage( 1185 TranslatableCaption.of("permission.no_permission_event"), 1186 TagResolver.resolver( 1187 "node", 1188 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED) 1189 ) 1190 ); 1191 e.setCancelled(true); 1192 } 1193 } else { 1194 UUID uuid = pp.getUUID(); 1195 if (plot.isAdded(uuid)) { 1196 return; 1197 } 1198 if (plot.getFlag(MiscInteractFlag.class)) { 1199 return; 1200 } 1201 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER)) { 1202 pp.sendMessage( 1203 TranslatableCaption.of("permission.no_permission_event"), 1204 TagResolver.resolver( 1205 "node", 1206 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_OTHER) 1207 ) 1208 ); 1209 e.setCancelled(true); 1210 plot.debug(pp.getName() + " could not interact with " + entity.getType() 1211 + " because misc-interact = false"); 1212 } 1213 } 1214 } 1215 } 1216 1217 @EventHandler(priority = EventPriority.LOW) 1218 @SuppressWarnings("deprecation") // Paper deprecation 1219 public void onCancelledInteract(PlayerInteractEvent event) { 1220 if (event.isCancelled() && event.getAction() == Action.RIGHT_CLICK_AIR) { 1221 Player player = event.getPlayer(); 1222 BukkitPlayer pp = BukkitUtil.adapt(player); 1223 PlotArea area = pp.getPlotAreaAbs(); 1224 if (area == null) { 1225 return; 1226 } 1227 if (event.getAction() == Action.RIGHT_CLICK_AIR) { 1228 Material item = event.getMaterial(); 1229 if (item.toString().toLowerCase().endsWith("_egg")) { 1230 event.setCancelled(true); 1231 event.setUseItemInHand(Event.Result.DENY); 1232 } 1233 } 1234 ItemStack hand = player.getInventory().getItemInMainHand(); 1235 ItemStack offHand = player.getInventory().getItemInOffHand(); 1236 Material type = hand.getType(); 1237 Material offType = offHand.getType(); 1238 if (type == Material.AIR) { 1239 type = offType; 1240 } 1241 if (type.toString().toLowerCase().endsWith("_egg")) { 1242 Block block = player.getTargetBlockExact(5, FluidCollisionMode.SOURCE_ONLY); 1243 if (block != null && block.getType() != Material.AIR) { 1244 Location location = BukkitUtil.adapt(block.getLocation()); 1245 if (!this.eventDispatcher.checkPlayerBlockEvent(pp, PlayerBlockEventType.SPAWN_MOB, location, null, true)) { 1246 event.setCancelled(true); 1247 event.setUseItemInHand(Event.Result.DENY); 1248 } 1249 } 1250 } 1251 } 1252 } 1253 1254 @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) 1255 public void onInteract(PlayerInteractEvent event) { 1256 Player player = event.getPlayer(); 1257 BukkitPlayer pp = BukkitUtil.adapt(player); 1258 PlotArea area = pp.getPlotAreaAbs(); 1259 if (area == null) { 1260 return; 1261 } 1262 PlayerBlockEventType eventType; 1263 BlockType blocktype1; 1264 Block block = event.getClickedBlock(); 1265 if (block == null) { 1266 // We do not care in this case, the player is likely interacting with air ("nothing"). 1267 return; 1268 } 1269 Location location = BukkitUtil.adapt(block.getLocation()); 1270 Action action = event.getAction(); 1271 switch (action) { 1272 case PHYSICAL -> { 1273 eventType = PlayerBlockEventType.TRIGGER_PHYSICAL; 1274 blocktype1 = BukkitAdapter.asBlockType(block.getType()); 1275 } 1276 1277 //todo rearrange the right click code. it is all over the place. 1278 case RIGHT_CLICK_BLOCK -> { 1279 Material blockType = block.getType(); 1280 eventType = PlayerBlockEventType.INTERACT_BLOCK; 1281 blocktype1 = BukkitAdapter.asBlockType(block.getType()); 1282 1283 if (INTERACTABLE_MATERIALS != null 1284 ? INTERACTABLE_MATERIALS.contains(blockType.name()) 1285 : blockType.isInteractable()) { 1286 if (!player.isSneaking()) { 1287 break; 1288 } 1289 ItemStack hand = player.getInventory().getItemInMainHand(); 1290 ItemStack offHand = player.getInventory().getItemInOffHand(); 1291 1292 // sneaking players interact with blocks if both hands are empty 1293 if (hand.getType() == Material.AIR && offHand.getType() == Material.AIR) { 1294 break; 1295 } 1296 } 1297 1298 Material type = event.getMaterial(); 1299 1300 // in the following, lb needs to have the material of the item in hand i.e. type 1301 switch (type.toString()) { 1302 case "REDSTONE", "STRING", "PUMPKIN_SEEDS", "MELON_SEEDS", "COCOA_BEANS", "WHEAT_SEEDS", "BEETROOT_SEEDS", 1303 "SWEET_BERRIES", "GLOW_BERRIES" -> { 1304 return; 1305 } 1306 default -> { 1307 //eventType = PlayerBlockEventType.PLACE_BLOCK; 1308 if (type.isBlock()) { 1309 return; 1310 } 1311 } 1312 } 1313 if (PaperLib.isPaper()) { 1314 if (MaterialTags.SPAWN_EGGS.isTagged(type) || Material.EGG.equals(type)) { 1315 eventType = PlayerBlockEventType.SPAWN_MOB; 1316 break; 1317 } 1318 } else { 1319 if (type.toString().toLowerCase().endsWith("egg")) { 1320 eventType = PlayerBlockEventType.SPAWN_MOB; 1321 break; 1322 } 1323 } 1324 if (type.isEdible()) { 1325 //Allow all players to eat while also allowing the block place event to be fired 1326 return; 1327 } 1328 // Process creature spawning of armor stands & end crystals here if spawned by the player in order to be able to 1329 // reset the player's hand item if spawning needs to be cancelled. 1330 if (type == Material.ARMOR_STAND || type == Material.END_CRYSTAL) { 1331 Plot plot = location.getOwnedPlotAbs(); 1332 EntityType entityType = type == Material.ARMOR_STAND ? EntityType.ARMOR_STAND : END_CRYSTAL_ENTITY_TYPE; 1333 if (BukkitEntityUtil.checkEntity(entityType, plot)) { 1334 event.setCancelled(true); 1335 break; 1336 } 1337 } 1338 // Continue with normal place event checks 1339 if (type == Material.ARMOR_STAND) { 1340 location = BukkitUtil.adapt(block.getRelative(event.getBlockFace()).getLocation()); 1341 eventType = PlayerBlockEventType.PLACE_MISC; 1342 } 1343 if (org.bukkit.Tag.ITEMS_BOATS.isTagged(type) || MINECARTS.contains(type)) { 1344 eventType = PlayerBlockEventType.PLACE_VEHICLE; 1345 break; 1346 } 1347 if (type == Material.FIREWORK_ROCKET || type == Material.FIREWORK_STAR) { 1348 eventType = PlayerBlockEventType.SPAWN_MOB; 1349 break; 1350 } 1351 if (BOOKS.contains(type)) { 1352 eventType = PlayerBlockEventType.READ; 1353 break; 1354 } 1355 } 1356 case LEFT_CLICK_BLOCK -> { 1357 Material blockType = block.getType(); 1358 1359 // todo: when the code above is rearranged, it would be great to beautify this as well. 1360 // will code this as a temporary, specific bug fix (for dragon eggs) 1361 if (blockType != Material.DRAGON_EGG) { 1362 return; 1363 } 1364 1365 eventType = PlayerBlockEventType.INTERACT_BLOCK; 1366 blocktype1 = BukkitAdapter.asBlockType(block.getType()); 1367 } 1368 default -> { 1369 return; 1370 } 1371 } 1372 if (this.worldEdit != null && pp.getAttribute("worldedit")) { 1373 if (event.getMaterial() == Material.getMaterial(this.worldEdit.getConfiguration().wandItem)) { 1374 return; 1375 } 1376 } 1377 if (!this.eventDispatcher.checkPlayerBlockEvent(pp, eventType, location, blocktype1, true)) { 1378 event.setCancelled(true); 1379 event.setUseInteractedBlock(Event.Result.DENY); 1380 } 1381 } 1382 1383 // Boats can sometimes be placed on interactable blocks such as levers, 1384 // see PS-175. Armor stands, minecarts and end crystals (the other entities 1385 // supported by this event) don't have this issue. 1386 @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) 1387 public void onBoatPlace(EntityPlaceEvent event) { 1388 Player player = event.getPlayer(); 1389 if (player == null) { 1390 return; 1391 } 1392 Entity placed = event.getEntity(); 1393 if (!(placed instanceof Boat)) { 1394 return; 1395 } 1396 BukkitPlayer pp = BukkitUtil.adapt(event.getPlayer()); 1397 PlotArea area = pp.getPlotAreaAbs(); 1398 if (area == null) { 1399 return; 1400 } 1401 PlayerBlockEventType eventType = PlayerBlockEventType.PLACE_VEHICLE; 1402 Block block = event.getBlock(); 1403 BlockType blockType = BukkitAdapter.asBlockType(block.getType()); 1404 Location location = BukkitUtil.adapt(block.getLocation()); 1405 if (!PlotSquared.get().getEventDispatcher() 1406 .checkPlayerBlockEvent(pp, eventType, location, blockType, true)) { 1407 event.setCancelled(true); 1408 } 1409 } 1410 1411 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 1412 public void onBucketEmpty(PlayerBucketEmptyEvent event) { 1413 final Block block = event.getBlock(); 1414 Location location = BukkitUtil.adapt(block.getLocation()); 1415 PlotArea area = location.getPlotArea(); 1416 if (area == null) { 1417 return; 1418 } 1419 BukkitPlayer pp = BukkitUtil.adapt(event.getPlayer()); 1420 Plot plot = area.getPlot(location); 1421 final List<BlockTypeWrapper> use = 1422 Optional.ofNullable(plot).map(p -> p.getFlag(UseFlag.class)).orElse(area.isRoadFlags() ? 1423 area.getFlag(UseFlag.class) : Collections.emptyList()); 1424 BlockType type = BukkitAdapter.asBlockType(block.getType()); 1425 for (final BlockTypeWrapper blockTypeWrapper : use) { 1426 if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper 1427 .accepts(type)) { 1428 return; 1429 } 1430 } 1431 if (plot == null) { 1432 if (pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_ROAD)) { 1433 return; 1434 } 1435 pp.sendMessage( 1436 TranslatableCaption.of("permission.no_permission_event"), 1437 TagResolver.resolver("node", Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_ROAD)) 1438 ); 1439 event.setCancelled(true); 1440 } else if (!plot.hasOwner()) { 1441 if (pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_UNOWNED)) { 1442 return; 1443 } 1444 pp.sendMessage( 1445 TranslatableCaption.of("permission.no_permission_event"), 1446 TagResolver.resolver( 1447 "node", 1448 Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_UNOWNED) 1449 ) 1450 ); 1451 event.setCancelled(true); 1452 } else if (!plot.isAdded(pp.getUUID())) { 1453 if (pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER)) { 1454 return; 1455 } 1456 pp.sendMessage( 1457 TranslatableCaption.of("permission.no_permission_event"), 1458 TagResolver.resolver( 1459 "node", 1460 Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_OTHER) 1461 ) 1462 ); 1463 event.setCancelled(true); 1464 } else if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { 1465 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER)) { 1466 pp.sendMessage( 1467 TranslatableCaption.of("done.building_restricted") 1468 ); 1469 event.setCancelled(true); 1470 } 1471 } 1472 } 1473 1474 @EventHandler(priority = EventPriority.HIGHEST) 1475 public void onInventoryClose(InventoryCloseEvent event) { 1476 HumanEntity closer = event.getPlayer(); 1477 if (!(closer instanceof Player player)) { 1478 return; 1479 } 1480 PlotInventory.removePlotInventoryOpen(BukkitUtil.adapt(player)); 1481 } 1482 1483 @EventHandler(priority = EventPriority.MONITOR) 1484 public void onLeave(PlayerQuitEvent event) { 1485 TaskManager.removeFromTeleportQueue(event.getPlayer().getName()); 1486 BukkitPlayer pp = BukkitUtil.adapt(event.getPlayer()); 1487 pp.unregister(); 1488 plotListener.logout(pp.getUUID()); 1489 } 1490 1491 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 1492 public void onBucketFill(PlayerBucketFillEvent event) { 1493 Block blockClicked = event.getBlockClicked(); 1494 Location location = BukkitUtil.adapt(blockClicked.getLocation()); 1495 PlotArea area = location.getPlotArea(); 1496 if (area == null) { 1497 return; 1498 } 1499 Player player = event.getPlayer(); 1500 BukkitPlayer plotPlayer = BukkitUtil.adapt(player); 1501 Plot plot = area.getPlot(location); 1502 final List<BlockTypeWrapper> use = 1503 Optional.ofNullable(plot).map(p -> p.getFlag(UseFlag.class)).orElse(area.isRoadFlags() ? 1504 area.getFlag(UseFlag.class) : Collections.emptyList()); 1505 BlockType type = BukkitAdapter.asBlockType(blockClicked.getType()); 1506 for (final BlockTypeWrapper blockTypeWrapper : use) { 1507 if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper 1508 .accepts(type)) { 1509 return; 1510 } 1511 } 1512 if (plot == null) { 1513 if (plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_BUILD_ROAD)) { 1514 return; 1515 } 1516 plotPlayer.sendMessage( 1517 TranslatableCaption.of("permission.no_permission_event"), 1518 TagResolver.resolver("node", Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_ROAD)) 1519 ); 1520 event.setCancelled(true); 1521 } else if (!plot.hasOwner()) { 1522 if (plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_BUILD_UNOWNED)) { 1523 return; 1524 } 1525 plotPlayer.sendMessage( 1526 TranslatableCaption.of("permission.no_permission_event"), 1527 TagResolver.resolver( 1528 "node", 1529 Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_UNOWNED) 1530 ) 1531 ); 1532 event.setCancelled(true); 1533 } else if (!plot.isAdded(plotPlayer.getUUID())) { 1534 if (plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER)) { 1535 return; 1536 } 1537 plotPlayer.sendMessage( 1538 TranslatableCaption.of("permission.no_permission_event"), 1539 TagResolver.resolver( 1540 "node", 1541 Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_OTHER) 1542 ) 1543 ); 1544 event.setCancelled(true); 1545 } else if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { 1546 if (!plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER)) { 1547 plotPlayer.sendMessage( 1548 TranslatableCaption.of("done.building_restricted") 1549 ); 1550 event.setCancelled(true); 1551 } 1552 } 1553 } 1554 1555 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 1556 public void onHangingPlace(HangingPlaceEvent event) { 1557 Block block = event.getBlock().getRelative(event.getBlockFace()); 1558 Location location = BukkitUtil.adapt(block.getLocation()); 1559 PlotArea area = location.getPlotArea(); 1560 if (area == null) { 1561 return; 1562 } 1563 Player p = event.getPlayer(); 1564 if (p == null) { 1565 event.setCancelled(true); 1566 return; 1567 } 1568 BukkitPlayer pp = BukkitUtil.adapt(p); 1569 Plot plot = area.getPlot(location); 1570 if (plot == null) { 1571 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_ROAD)) { 1572 pp.sendMessage( 1573 TranslatableCaption.of("permission.no_permission_event"), 1574 TagResolver.resolver( 1575 "node", 1576 Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_ROAD) 1577 ) 1578 ); 1579 event.setCancelled(true); 1580 } 1581 } else { 1582 if (!plot.hasOwner()) { 1583 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_UNOWNED)) { 1584 pp.sendMessage( 1585 TranslatableCaption.of("permission.no_permission_event"), 1586 TagResolver.resolver( 1587 "node", 1588 Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_UNOWNED) 1589 ) 1590 ); 1591 event.setCancelled(true); 1592 } 1593 return; 1594 } 1595 if (!plot.isAdded(pp.getUUID())) { 1596 if (!plot.getFlag(HangingPlaceFlag.class)) { 1597 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER)) { 1598 pp.sendMessage( 1599 TranslatableCaption.of("permission.no_permission_event"), 1600 TagResolver.resolver( 1601 "node", 1602 Tag.inserting(Permission.PERMISSION_ADMIN_BUILD_OTHER) 1603 ) 1604 ); 1605 event.setCancelled(true); 1606 } 1607 return; 1608 } 1609 } 1610 if (BukkitEntityUtil.checkEntity(event.getEntity(), plot)) { 1611 event.setCancelled(true); 1612 } 1613 1614 } 1615 } 1616 1617 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 1618 public void onHangingBreakByEntity(HangingBreakByEntityEvent event) { 1619 Entity remover = event.getRemover(); 1620 if (remover instanceof Player p) { 1621 Location location = BukkitUtil.adapt(event.getEntity().getLocation()); 1622 PlotArea area = location.getPlotArea(); 1623 if (area == null) { 1624 return; 1625 } 1626 BukkitPlayer pp = BukkitUtil.adapt(p); 1627 Plot plot = area.getPlot(location); 1628 if (plot == null) { 1629 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_ROAD)) { 1630 pp.sendMessage( 1631 TranslatableCaption.of("permission.no_permission_event"), 1632 TagResolver.resolver( 1633 "node", 1634 Tag.inserting(Permission.PERMISSION_ADMIN_DESTROY_ROAD) 1635 ) 1636 ); 1637 event.setCancelled(true); 1638 } 1639 } else if (!plot.hasOwner()) { 1640 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_UNOWNED)) { 1641 pp.sendMessage( 1642 TranslatableCaption.of("permission.no_permission_event"), 1643 TagResolver.resolver( 1644 "node", 1645 Tag.inserting(Permission.PERMISSION_ADMIN_DESTROY_UNOWNED) 1646 ) 1647 ); 1648 event.setCancelled(true); 1649 } 1650 } else if (!plot.isAdded(pp.getUUID())) { 1651 if (plot.getFlag(HangingBreakFlag.class)) { 1652 return; 1653 } 1654 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_OTHER)) { 1655 pp.sendMessage( 1656 TranslatableCaption.of("permission.no_permission_event"), 1657 TagResolver.resolver( 1658 "node", 1659 Tag.inserting(Permission.PERMISSION_ADMIN_DESTROY_OTHER) 1660 ) 1661 ); 1662 event.setCancelled(true); 1663 plot.debug(p.getName() 1664 + " could not break hanging entity because hanging-break = false"); 1665 } 1666 } 1667 } else if (remover instanceof Projectile p) { 1668 if (p.getShooter() instanceof Player shooter) { 1669 Location location = BukkitUtil.adapt(event.getEntity().getLocation()); 1670 PlotArea area = location.getPlotArea(); 1671 if (area == null) { 1672 return; 1673 } 1674 BukkitPlayer player = BukkitUtil.adapt(shooter); 1675 Plot plot = area.getPlot(BukkitUtil.adapt(event.getEntity().getLocation())); 1676 if (plot != null) { 1677 if (!plot.hasOwner()) { 1678 if (!player.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_UNOWNED)) { 1679 player.sendMessage( 1680 TranslatableCaption.of("permission.no_permission_event"), 1681 TagResolver.resolver( 1682 "node", 1683 Tag.inserting(Permission.PERMISSION_ADMIN_DESTROY_UNOWNED) 1684 ) 1685 ); 1686 event.setCancelled(true); 1687 } 1688 } else if (!plot.isAdded(player.getUUID())) { 1689 if (!plot.getFlag(HangingBreakFlag.class)) { 1690 if (!player.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_OTHER)) { 1691 player.sendMessage( 1692 TranslatableCaption.of("permission.no_permission_event"), 1693 TagResolver.resolver( 1694 "node", 1695 Tag.inserting(Permission.PERMISSION_ADMIN_DESTROY_OTHER) 1696 ) 1697 ); 1698 event.setCancelled(true); 1699 plot.debug(player.getName() 1700 + " could not break hanging entity because hanging-break = false"); 1701 } 1702 } 1703 } 1704 } 1705 } 1706 } else { 1707 event.setCancelled(true); 1708 } 1709 } 1710 1711 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 1712 public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { 1713 if (event.getRightClicked().getType() == EntityType.UNKNOWN) { 1714 return; 1715 } 1716 Location location = BukkitUtil.adapt(event.getRightClicked().getLocation()); 1717 PlotArea area = location.getPlotArea(); 1718 if (area == null) { 1719 return; 1720 } 1721 Player p = event.getPlayer(); 1722 BukkitPlayer pp = BukkitUtil.adapt(p); 1723 Plot plot = area.getPlot(location); 1724 if (plot == null && !area.isRoadFlags()) { 1725 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_ROAD)) { 1726 pp.sendMessage( 1727 TranslatableCaption.of("permission.no_permission_event"), 1728 TagResolver.resolver( 1729 "node", 1730 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_ROAD) 1731 ) 1732 ); 1733 event.setCancelled(true); 1734 } 1735 } else if (plot != null && !plot.hasOwner()) { 1736 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED)) { 1737 pp.sendMessage( 1738 TranslatableCaption.of("permission.no_permission_event"), 1739 TagResolver.resolver( 1740 "node", 1741 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED) 1742 ) 1743 ); 1744 event.setCancelled(true); 1745 } 1746 } else if ((plot != null && !plot.isAdded(pp.getUUID())) || (plot == null && area 1747 .isRoadFlags())) { 1748 final Entity entity = event.getRightClicked(); 1749 final com.sk89q.worldedit.world.entity.EntityType entityType = 1750 BukkitAdapter.adapt(entity.getType()); 1751 1752 FlagContainer flagContainer; 1753 if (plot == null) { 1754 flagContainer = area.getRoadFlagContainer(); 1755 } else { 1756 flagContainer = plot.getFlagContainer(); 1757 } 1758 1759 if (EntityCategories.HOSTILE.contains(entityType) && flagContainer 1760 .getFlag(HostileInteractFlag.class).getValue()) { 1761 return; 1762 } 1763 1764 if (EntityCategories.ANIMAL.contains(entityType) && flagContainer 1765 .getFlag(AnimalInteractFlag.class).getValue()) { 1766 return; 1767 } 1768 1769 // This actually makes use of the interface, so we don't use the 1770 // category 1771 if (entity instanceof Tameable && ((Tameable) entity).isTamed() && flagContainer 1772 .getFlag(TamedInteractFlag.class).getValue()) { 1773 return; 1774 } 1775 1776 if (EntityCategories.VEHICLE.contains(entityType) && flagContainer 1777 .getFlag(VehicleUseFlag.class).getValue()) { 1778 return; 1779 } 1780 1781 if (EntityCategories.PLAYER.contains(entityType) && flagContainer 1782 .getFlag(PlayerInteractFlag.class).getValue()) { 1783 return; 1784 } 1785 1786 if (EntityCategories.INTERACTION.contains(entityType) && flagContainer 1787 .getFlag(InteractionInteractFlag.class).getValue()) { 1788 return; 1789 } 1790 1791 if (EntityCategories.VILLAGER.contains(entityType) && flagContainer 1792 .getFlag(VillagerInteractFlag.class).getValue()) { 1793 return; 1794 } 1795 1796 if ((EntityCategories.HANGING.contains(entityType) || EntityCategories.OTHER 1797 .contains(entityType)) && flagContainer.getFlag(MiscInteractFlag.class) 1798 .getValue()) { 1799 return; 1800 } 1801 1802 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER)) { 1803 pp.sendMessage( 1804 TranslatableCaption.of("permission.no_permission_event"), 1805 TagResolver.resolver( 1806 "node", 1807 Tag.inserting(Permission.PERMISSION_ADMIN_INTERACT_OTHER) 1808 ) 1809 ); 1810 event.setCancelled(true); 1811 } 1812 } 1813 } 1814 1815 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 1816 public void onVehicleDestroy(VehicleDestroyEvent event) { 1817 Location location = BukkitUtil.adapt(event.getVehicle().getLocation()); 1818 PlotArea area = location.getPlotArea(); 1819 if (area == null) { 1820 return; 1821 } 1822 Entity attacker = event.getAttacker(); 1823 if (attacker instanceof Player p) { 1824 BukkitPlayer pp = BukkitUtil.adapt(p); 1825 Plot plot = area.getPlot(location); 1826 if (plot == null) { 1827 if (!PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, VehicleBreakFlag.class, true) && !pp.hasPermission( 1828 Permission.PERMISSION_ADMIN_DESTROY_VEHICLE_ROAD 1829 )) { 1830 pp.sendMessage( 1831 TranslatableCaption.of("permission.no_permission_event"), 1832 TagResolver.resolver( 1833 "node", 1834 Tag.inserting(Permission.PERMISSION_ADMIN_DESTROY_VEHICLE_ROAD) 1835 ) 1836 ); 1837 event.setCancelled(true); 1838 } 1839 } else { 1840 if (!plot.hasOwner()) { 1841 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_VEHICLE_UNOWNED)) { 1842 pp.sendMessage( 1843 TranslatableCaption.of("permission.no_permission_event"), 1844 TagResolver.resolver( 1845 "node", 1846 Tag.inserting(Permission.PERMISSION_ADMIN_DESTROY_VEHICLE_UNOWNED) 1847 ) 1848 ); 1849 event.setCancelled(true); 1850 return; 1851 } 1852 return; 1853 } 1854 if (!plot.isAdded(pp.getUUID())) { 1855 if (plot.getFlag(VehicleBreakFlag.class)) { 1856 return; 1857 } 1858 if (!pp.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_VEHICLE_OTHER)) { 1859 pp.sendMessage( 1860 TranslatableCaption.of("permission.no_permission_event"), 1861 TagResolver.resolver( 1862 "node", 1863 Tag.inserting(Permission.PERMISSION_ADMIN_DESTROY_VEHICLE_OTHER) 1864 ) 1865 ); 1866 event.setCancelled(true); 1867 plot.debug(pp.getName() 1868 + " could not break vehicle because vehicle-break = false"); 1869 } 1870 } 1871 } 1872 } 1873 } 1874 1875 @EventHandler 1876 public void onItemDrop(PlayerDropItemEvent event) { 1877 Player player = event.getPlayer(); 1878 BukkitPlayer pp = BukkitUtil.adapt(player); 1879 Location location = pp.getLocation(); 1880 PlotArea area = location.getPlotArea(); 1881 if (area == null) { 1882 return; 1883 } 1884 Plot plot = location.getOwnedPlot(); 1885 if (plot == null) { 1886 if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, ItemDropFlag.class, false)) { 1887 event.setCancelled(true); 1888 } 1889 return; 1890 } 1891 UUID uuid = pp.getUUID(); 1892 if (!plot.isAdded(uuid)) { 1893 if (!plot.getFlag(ItemDropFlag.class)) { 1894 plot.debug(player.getName() + " could not drop item because of item-drop = false"); 1895 event.setCancelled(true); 1896 } 1897 } 1898 } 1899 1900 @EventHandler 1901 public void onItemPickup(EntityPickupItemEvent event) { 1902 LivingEntity ent = event.getEntity(); 1903 if (ent instanceof Player player) { 1904 BukkitPlayer pp = BukkitUtil.adapt(player); 1905 Location location = pp.getLocation(); 1906 PlotArea area = location.getPlotArea(); 1907 if (area == null) { 1908 return; 1909 } 1910 Plot plot = location.getOwnedPlot(); 1911 if (plot == null) { 1912 if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, DropProtectionFlag.class, true)) { 1913 event.setCancelled(true); 1914 } 1915 return; 1916 } 1917 UUID uuid = pp.getUUID(); 1918 if (!plot.isAdded(uuid) && plot.getFlag(DropProtectionFlag.class)) { 1919 plot.debug(player.getName() + " could not pick up item because of drop-protection = true"); 1920 event.setCancelled(true); 1921 } 1922 } 1923 } 1924 1925 @EventHandler 1926 public void onDeath(final PlayerDeathEvent event) { 1927 Location location = BukkitUtil.adapt(event.getEntity().getLocation()); 1928 PlotArea area = location.getPlotArea(); 1929 if (area == null) { 1930 return; 1931 } 1932 Plot plot = location.getOwnedPlot(); 1933 if (plot == null) { 1934 if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, KeepInventoryFlag.class, true)) { 1935 event.setCancelled(true); 1936 } 1937 return; 1938 } 1939 if (plot.getFlag(KeepInventoryFlag.class)) { 1940 plot.debug(event.getEntity().getName() + " kept their inventory because of keep-inventory = true"); 1941 event.getDrops().clear(); 1942 event.setKeepInventory(true); 1943 } 1944 } 1945 1946 @SuppressWarnings("deprecation") // #getLocate is needed for Spigot compatibility 1947 @EventHandler 1948 public void onLocaleChange(final PlayerLocaleChangeEvent event) { 1949 // The event is fired before the player is deemed online upon login 1950 if (!event.getPlayer().isOnline()) { 1951 return; 1952 } 1953 BukkitPlayer player = BukkitUtil.adapt(event.getPlayer()); 1954 // we're stripping the country code as we don't want to differ between countries 1955 player.setLocale(Locale.forLanguageTag(event.getLocale().substring(0, 2))); 1956 } 1957 1958 @EventHandler 1959 public void onPortalEnter(PlayerPortalEvent event) { 1960 Location location = BukkitUtil.adapt(event.getPlayer().getLocation()); 1961 PlotArea area = location.getPlotArea(); 1962 if (area == null) { 1963 return; 1964 } 1965 Plot plot = location.getOwnedPlot(); 1966 if (plot == null) { 1967 if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, DenyPortalTravelFlag.class, true)) { 1968 event.setCancelled(true); 1969 } 1970 return; 1971 } 1972 if (plot.getFlag(DenyPortalTravelFlag.class)) { 1973 plot.debug(event.getPlayer().getName() + " did not travel thru a portal because of deny-portal-travel = true"); 1974 event.setCancelled(true); 1975 } 1976 } 1977 1978 @EventHandler 1979 public void onPortalCreation(PortalCreateEvent event) { 1980 String world = event.getWorld().getName(); 1981 if (PlotSquared.get().getPlotAreaManager().getPlotAreasSet(world).size() == 0) { 1982 return; 1983 } 1984 BukkitPlayer pp = (event.getEntity() instanceof Player player) ? BukkitUtil.adapt(player) : null; 1985 int minX = Integer.MAX_VALUE; 1986 int maxX = Integer.MIN_VALUE; 1987 int minZ = Integer.MAX_VALUE; 1988 int maxZ = Integer.MIN_VALUE; 1989 for (BlockState state : event.getBlocks()) { 1990 minX = Math.min(state.getX(), minX); 1991 maxX = Math.max(state.getX(), maxX); 1992 minZ = Math.min(state.getZ(), minZ); 1993 maxZ = Math.max(state.getZ(), maxZ); 1994 } 1995 int y = event.getBlocks().get(0).getY(); // Don't need to worry about this too much 1996 for (Location location : List.of( // We don't care about duplicate locations 1997 Location.at(world, minX, y, minZ), 1998 Location.at(world, minX, y, maxZ), 1999 Location.at(world, maxX, y, minZ), 2000 Location.at(world, maxX, y, maxZ) 2001 )) { 2002 PlotArea area = location.getPlotArea(); 2003 if (area == null) { 2004 continue; 2005 } 2006 if (area.notifyIfOutsideBuildArea(pp, location.getY())) { 2007 event.setCancelled(true); 2008 return; 2009 } 2010 Plot plot = location.getOwnedPlot(); 2011 if (plot == null) { 2012 if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, DenyPortalsFlag.class, true)) { 2013 event.setCancelled(true); 2014 return; 2015 } 2016 continue; 2017 } 2018 if (plot.getFlag(DenyPortalsFlag.class)) { 2019 StringBuilder builder = new StringBuilder(); 2020 if (event.getEntity() != null) { 2021 builder.append(event.getEntity().getName()).append(" did not create a portal"); 2022 } else { 2023 builder.append("Portal creation cancelled"); 2024 } 2025 plot.debug(builder.append(" because of deny-portals = true").toString()); 2026 event.setCancelled(true); 2027 return; 2028 } 2029 } 2030 } 2031 2032 @EventHandler 2033 public void onPlayerTakeLecternBook(PlayerTakeLecternBookEvent event) { 2034 Player player = event.getPlayer(); 2035 BukkitPlayer pp = BukkitUtil.adapt(player); 2036 Location location = pp.getLocation(); 2037 PlotArea area = location.getPlotArea(); 2038 if (area == null) { 2039 return; 2040 } 2041 Plot plot = location.getOwnedPlot(); 2042 if (plot == null) { 2043 if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, LecternReadBookFlag.class, true)) { 2044 event.setCancelled(true); 2045 } 2046 return; 2047 } 2048 if (!plot.isAdded(pp.getUUID())) { 2049 if (plot.getFlag(LecternReadBookFlag.class)) { 2050 plot.debug(event.getPlayer().getName() + " could not take the book because of lectern-read-book = true"); 2051 event.setCancelled(true); 2052 } 2053 } 2054 } 2055 2056}