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