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