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