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.core.util; 020 021import com.google.common.eventbus.EventBus; 022import com.intellectualsites.annotations.DoNotUse; 023import com.plotsquared.core.PlotSquared; 024import com.plotsquared.core.configuration.Settings; 025import com.plotsquared.core.configuration.caption.TranslatableCaption; 026import com.plotsquared.core.events.PlayerAutoPlotEvent; 027import com.plotsquared.core.events.PlayerAutoPlotsChosenEvent; 028import com.plotsquared.core.events.PlayerBuyPlotEvent; 029import com.plotsquared.core.events.PlayerClaimPlotEvent; 030import com.plotsquared.core.events.PlayerEnterPlotEvent; 031import com.plotsquared.core.events.PlayerLeavePlotEvent; 032import com.plotsquared.core.events.PlayerPlotDeniedEvent; 033import com.plotsquared.core.events.PlayerPlotHelperEvent; 034import com.plotsquared.core.events.PlayerPlotLimitEvent; 035import com.plotsquared.core.events.PlayerPlotTrustedEvent; 036import com.plotsquared.core.events.PlayerTeleportToPlotEvent; 037import com.plotsquared.core.events.PlotAutoMergeEvent; 038import com.plotsquared.core.events.PlotChangeOwnerEvent; 039import com.plotsquared.core.events.PlotClaimedNotifyEvent; 040import com.plotsquared.core.events.PlotClearEvent; 041import com.plotsquared.core.events.PlotComponentSetEvent; 042import com.plotsquared.core.events.PlotDeleteEvent; 043import com.plotsquared.core.events.PlotDoneEvent; 044import com.plotsquared.core.events.PlotEvent; 045import com.plotsquared.core.events.PlotFlagAddEvent; 046import com.plotsquared.core.events.PlotFlagRemoveEvent; 047import com.plotsquared.core.events.PlotMergeEvent; 048import com.plotsquared.core.events.PlotRateEvent; 049import com.plotsquared.core.events.PlotUnlinkEvent; 050import com.plotsquared.core.events.RemoveRoadEntityEvent; 051import com.plotsquared.core.events.TeleportCause; 052import com.plotsquared.core.events.post.PostPlayerAutoPlotEvent; 053import com.plotsquared.core.events.post.PostPlayerBuyPlotEvent; 054import com.plotsquared.core.events.post.PostPlotChangeOwnerEvent; 055import com.plotsquared.core.events.post.PostPlotClearEvent; 056import com.plotsquared.core.events.post.PostPlotDeleteEvent; 057import com.plotsquared.core.events.post.PostPlotMergeEvent; 058import com.plotsquared.core.events.post.PostPlotUnlinkEvent; 059import com.plotsquared.core.listener.PlayerBlockEventType; 060import com.plotsquared.core.location.Direction; 061import com.plotsquared.core.location.Location; 062import com.plotsquared.core.permissions.Permission; 063import com.plotsquared.core.player.OfflinePlotPlayer; 064import com.plotsquared.core.player.PlotPlayer; 065import com.plotsquared.core.plot.Plot; 066import com.plotsquared.core.plot.PlotArea; 067import com.plotsquared.core.plot.PlotId; 068import com.plotsquared.core.plot.Rating; 069import com.plotsquared.core.plot.flag.PlotFlag; 070import com.plotsquared.core.plot.flag.implementations.DeviceInteractFlag; 071import com.plotsquared.core.plot.flag.implementations.EditSignFlag; 072import com.plotsquared.core.plot.flag.implementations.MiscPlaceFlag; 073import com.plotsquared.core.plot.flag.implementations.MobPlaceFlag; 074import com.plotsquared.core.plot.flag.implementations.PlaceFlag; 075import com.plotsquared.core.plot.flag.implementations.UseFlag; 076import com.plotsquared.core.plot.flag.implementations.VehiclePlaceFlag; 077import com.plotsquared.core.plot.flag.types.BlockTypeWrapper; 078import com.plotsquared.core.plot.world.SinglePlotArea; 079import com.plotsquared.core.util.task.TaskManager; 080import com.sk89q.worldedit.WorldEdit; 081import com.sk89q.worldedit.entity.Entity; 082import com.sk89q.worldedit.function.pattern.Pattern; 083import com.sk89q.worldedit.world.block.BlockCategories; 084import com.sk89q.worldedit.world.block.BlockType; 085import com.sk89q.worldedit.world.block.BlockTypes; 086import net.kyori.adventure.text.Component; 087import net.kyori.adventure.text.minimessage.tag.Tag; 088import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; 089import org.checkerframework.checker.nullness.qual.NonNull; 090import org.checkerframework.checker.nullness.qual.Nullable; 091 092import java.util.ArrayList; 093import java.util.List; 094import java.util.UUID; 095 096@DoNotUse 097public class EventDispatcher { 098 099 private final EventBus eventBus = new EventBus("PlotSquaredEvents"); 100 private final List<Object> listeners = new ArrayList<>(); 101 private final WorldEdit worldEdit; 102 103 public EventDispatcher(final @Nullable WorldEdit worldEdit) { 104 this.worldEdit = worldEdit; 105 } 106 107 public void registerListener(Object listener) { 108 eventBus.register(listener); 109 listeners.add(listener); 110 } 111 112 public void unregisterListener(Object listener) { 113 eventBus.unregister(listener); 114 listeners.remove(listener); 115 } 116 117 public void unregisterAll() { 118 for (Object listener : listeners) { 119 eventBus.unregister(listener); 120 } 121 } 122 123 public void callGenericEvent(final @NonNull Object event) { 124 eventBus.post(event); 125 } 126 127 public void callEvent(final @NonNull PlotEvent event) { 128 eventBus.post(event); 129 } 130 131 public PlayerClaimPlotEvent callClaim(PlotPlayer<?> player, Plot plot, String schematic) { 132 PlayerClaimPlotEvent event = new PlayerClaimPlotEvent(player, plot, schematic); 133 callEvent(event); 134 return event; 135 } 136 137 public PlayerAutoPlotEvent callAuto( 138 PlotPlayer<?> player, PlotArea area, String schematic, 139 int size_x, int size_z 140 ) { 141 PlayerAutoPlotEvent event = 142 new PlayerAutoPlotEvent(player, area, schematic, size_x, size_z); 143 callEvent(event); 144 return event; 145 } 146 147 public PostPlayerAutoPlotEvent callPostAuto(PlotPlayer<?> player, Plot plot) { 148 PostPlayerAutoPlotEvent event = new PostPlayerAutoPlotEvent(player, plot); 149 callEvent(event); 150 return event; 151 } 152 153 public PlayerAutoPlotsChosenEvent callAutoPlotsChosen( 154 PlotPlayer<?> player, List<Plot> plots 155 ) { 156 PlayerAutoPlotsChosenEvent event = 157 new PlayerAutoPlotsChosenEvent(player, plots); 158 callEvent(event); 159 return event; 160 } 161 162 public PlotClaimedNotifyEvent callPlotClaimedNotify(Plot plot, boolean auto) { 163 PlotClaimedNotifyEvent event = new PlotClaimedNotifyEvent(plot, auto); 164 callEvent(event); 165 return event; 166 } 167 168 public PlayerTeleportToPlotEvent callTeleport(PlotPlayer<?> player, Location from, Plot plot, TeleportCause cause) { 169 PlayerTeleportToPlotEvent event = new PlayerTeleportToPlotEvent(player, from, plot, cause); 170 callEvent(event); 171 return event; 172 } 173 174 public PlotComponentSetEvent callComponentSet(Plot plot, String component, Pattern pattern) { 175 PlotComponentSetEvent event = new PlotComponentSetEvent(plot, component, pattern); 176 callEvent(event); 177 return event; 178 } 179 180 public PlotClearEvent callClear(Plot plot) { 181 PlotClearEvent event = new PlotClearEvent(plot); 182 callEvent(event); 183 return event; 184 } 185 186 public PostPlotClearEvent callPostPlotClear(PlotPlayer<?> player, Plot plot) { 187 PostPlotClearEvent event = new PostPlotClearEvent(player, plot); 188 callEvent(event); 189 return event; 190 } 191 192 public PlotDeleteEvent callDelete(Plot plot) { 193 PlotDeleteEvent event = new PlotDeleteEvent(plot); 194 callEvent(event); 195 return event; 196 } 197 198 public PostPlotDeleteEvent callPostDelete(Plot plot) { 199 PostPlotDeleteEvent event = new PostPlotDeleteEvent(plot); 200 callEvent(event); 201 return event; 202 } 203 204 public PlotFlagAddEvent callFlagAdd(PlotFlag<?, ?> flag, Plot plot) { 205 PlotFlagAddEvent event = new PlotFlagAddEvent(flag, plot); 206 callEvent(event); 207 return event; 208 } 209 210 public PlotFlagRemoveEvent callFlagRemove(PlotFlag<?, ?> flag, Plot plot) { 211 PlotFlagRemoveEvent event = new PlotFlagRemoveEvent(flag, plot); 212 callEvent(event); 213 return event; 214 } 215 216 public PlotMergeEvent callMerge(Plot plot, Direction dir, int max, PlotPlayer<?> player) { 217 PlotMergeEvent event = new PlotMergeEvent(plot.getWorldName(), plot, dir, max, player); 218 callEvent(event); 219 return event; 220 } 221 222 public PostPlotMergeEvent callPostMerge(PlotPlayer<?> player, Plot plot) { 223 PostPlotMergeEvent event = new PostPlotMergeEvent(player, plot); 224 callEvent(event); 225 return event; 226 } 227 228 public PlotAutoMergeEvent callAutoMerge(Plot plot, List<PlotId> plots) { 229 PlotAutoMergeEvent event = new PlotAutoMergeEvent(plot.getWorldName(), plot, plots); 230 callEvent(event); 231 return event; 232 } 233 234 public PlotUnlinkEvent callUnlink( 235 PlotArea area, Plot plot, boolean createRoad, 236 boolean createSign, PlotUnlinkEvent.REASON reason 237 ) { 238 PlotUnlinkEvent event = new PlotUnlinkEvent(area, plot, createRoad, createSign, reason); 239 callEvent(event); 240 return event; 241 } 242 243 public PostPlotUnlinkEvent callPostUnlink(Plot plot, PlotUnlinkEvent.REASON reason) { 244 PostPlotUnlinkEvent event = new PostPlotUnlinkEvent(plot, reason); 245 callEvent(event); 246 return event; 247 } 248 249 public PlayerEnterPlotEvent callEntry(PlotPlayer<?> player, Plot plot) { 250 PlayerEnterPlotEvent event = new PlayerEnterPlotEvent(player, plot); 251 callEvent(event); 252 return event; 253 } 254 255 public PlayerLeavePlotEvent callLeave(PlotPlayer<?> player, Plot plot) { 256 PlayerLeavePlotEvent event = new PlayerLeavePlotEvent(player, plot); 257 callEvent(event); 258 return event; 259 } 260 261 public PlayerPlotDeniedEvent callDenied( 262 PlotPlayer<?> initiator, Plot plot, UUID player, 263 boolean added 264 ) { 265 PlayerPlotDeniedEvent event = new PlayerPlotDeniedEvent(initiator, plot, player, added); 266 callEvent(event); 267 return event; 268 } 269 270 public PlayerPlotTrustedEvent callTrusted( 271 PlotPlayer<?> initiator, Plot plot, UUID player, 272 boolean added 273 ) { 274 PlayerPlotTrustedEvent event = new PlayerPlotTrustedEvent(initiator, plot, player, added); 275 callEvent(event); 276 return event; 277 } 278 279 public PlayerPlotHelperEvent callMember( 280 PlotPlayer<?> initiator, Plot plot, UUID player, 281 boolean added 282 ) { 283 PlayerPlotHelperEvent event = new PlayerPlotHelperEvent(initiator, plot, player, added); 284 callEvent(event); 285 return event; 286 } 287 288 public PlotChangeOwnerEvent callOwnerChange( 289 PlotPlayer<?> initiator, Plot plot, UUID oldOwner, 290 UUID newOwner, boolean hasOldOwner 291 ) { 292 PlotChangeOwnerEvent event = 293 new PlotChangeOwnerEvent(initiator, plot, oldOwner, newOwner, hasOldOwner); 294 callEvent(event); 295 return event; 296 } 297 298 public PostPlotChangeOwnerEvent callPostOwnerChange(PlotPlayer<?> player, Plot plot, @Nullable UUID oldOwner) { 299 PostPlotChangeOwnerEvent event = new PostPlotChangeOwnerEvent(player, plot, oldOwner); 300 callEvent(event); 301 return event; 302 } 303 304 public PlotRateEvent callRating(PlotPlayer<?> player, Plot plot, Rating rating) { 305 PlotRateEvent event = new PlotRateEvent(player, rating, plot); 306 eventBus.post(event); 307 return event; 308 } 309 310 public PlotDoneEvent callDone(Plot plot) { 311 PlotDoneEvent event = new PlotDoneEvent(plot); 312 callEvent(event); 313 return event; 314 } 315 316 public RemoveRoadEntityEvent callRemoveRoadEntity(Entity entity) { 317 RemoveRoadEntityEvent event = new RemoveRoadEntityEvent(entity); 318 eventBus.post(event); 319 return event; 320 } 321 322 public PlayerPlotLimitEvent callPlayerPlotLimit(PlotPlayer<?> player, int calculatedLimit) { 323 PlayerPlotLimitEvent event = new PlayerPlotLimitEvent(player, calculatedLimit); 324 eventBus.post(event); 325 return event; 326 } 327 328 public PlayerBuyPlotEvent callPlayerBuyPlot(PlotPlayer<?> player, Plot plot, double price) { 329 PlayerBuyPlotEvent event = new PlayerBuyPlotEvent(player, plot, price); 330 eventBus.post(event); 331 return event; 332 } 333 334 public void callPostPlayerBuyPlot(PlotPlayer<?> player, OfflinePlotPlayer previousOwner, Plot plot, 335 double price) { 336 eventBus.post(new PostPlayerBuyPlotEvent(player, previousOwner, plot, price)); 337 } 338 339 public void doJoinTask(final PlotPlayer<?> player) { 340 if (player == null) { 341 return; //possible future warning message to figure out where we are retrieving null 342 } 343 if (PlotSquared.platform().expireManager() != null) { 344 PlotSquared.platform().expireManager().handleJoin(player); 345 } 346 if (this.worldEdit != null) { 347 if (player.getAttribute("worldedit")) { 348 player.sendMessage(TranslatableCaption.of("worldedit.worldedit_bypassed")); 349 } 350 } 351 final Plot plot = player.getCurrentPlot(); 352 if (Settings.Teleport.ON_LOGIN && plot != null && !(plot 353 .getArea() instanceof SinglePlotArea)) { 354 TaskManager.runTask(() -> plot.teleportPlayer(player, TeleportCause.LOGIN, result -> { 355 })); 356 player.sendMessage(TranslatableCaption.of("teleport.teleported_to_road")); 357 } 358 } 359 360 public void doRespawnTask(final PlotPlayer<?> player) { 361 final Plot plot = player.getCurrentPlot(); 362 if (Settings.Teleport.ON_DEATH && plot != null) { 363 TaskManager.runTask(() -> plot.teleportPlayer(player, TeleportCause.DEATH, result -> { 364 })); 365 player.sendMessage(TranslatableCaption.of("teleport.teleported_to_road")); 366 } 367 } 368 369 public boolean checkPlayerBlockEvent( 370 PlotPlayer<?> player, @NonNull PlayerBlockEventType type, 371 Location location, BlockType blockType, boolean notifyPerms 372 ) { 373 PlotArea area = location.getPlotArea(); 374 // the interaction target location might be outside a plot area 375 if (area == null) { 376 return true; 377 } 378 if (!area.buildRangeContainsY(location.getY()) && !player.hasPermission(Permission.PERMISSION_ADMIN_BUILD_HEIGHT_LIMIT)) { 379 player.sendMessage( 380 TranslatableCaption.of("height.height_limit"), 381 TagResolver.builder() 382 .tag("minheight", Tag.inserting(Component.text(area.getMinBuildHeight()))) 383 .tag("maxheight", Tag.inserting(Component.text(area.getMaxBuildHeight()))) 384 .build() 385 ); 386 return false; 387 } 388 Plot plot = area.getPlot(location); 389 if (plot != null) { 390 if (plot.isAdded(player.getUUID())) { 391 return true; 392 } 393 } 394 switch (type) { 395 case TELEPORT_OBJECT -> { 396 return false; 397 } 398 case READ -> { 399 return true; 400 } 401 case INTERACT_BLOCK -> { 402 if (plot == null) { 403 final List<BlockTypeWrapper> use = area.getRoadFlag(UseFlag.class); 404 for (final BlockTypeWrapper blockTypeWrapper : use) { 405 if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper.accepts(blockType)) { 406 return true; 407 } 408 } 409 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_ROAD, notifyPerms); 410 } 411 if (!plot.hasOwner()) { 412 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED, notifyPerms); 413 } 414 final List<BlockTypeWrapper> use = plot.getFlag(UseFlag.class); 415 for (final BlockTypeWrapper blockTypeWrapper : use) { 416 if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper 417 .accepts(blockType)) { 418 return true; 419 } 420 } 421 if (player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER, false)) { 422 return true; 423 } 424 // we check for the EditSignFlag in the PlayerSignOpenEvent again, but we must not cancel the interact event 425 // or send a message if the flag is true 426 if (BlockCategories.ALL_SIGNS != null && BlockCategories.ALL_SIGNS.contains(blockType) 427 && plot.getFlag(EditSignFlag.class)) { 428 return true; 429 } 430 if (notifyPerms) { 431 player.sendMessage( 432 TranslatableCaption.of("commandconfig.flag_tutorial_usage"), 433 TagResolver.resolver("flag", Tag.inserting(PlaceFlag.getFlagNameComponent(UseFlag.class))) 434 ); 435 } 436 return false; 437 } 438 case TRIGGER_PHYSICAL -> { 439 if (plot == null) { 440 final List<BlockTypeWrapper> use = area.getRoadFlag(UseFlag.class); 441 for (final BlockTypeWrapper blockTypeWrapper : use) { 442 if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper.accepts(blockType)) { 443 return true; 444 } 445 } 446 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_ROAD, false); 447 } 448 if (!plot.hasOwner()) { 449 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED, false); 450 } 451 if (plot.getFlag(DeviceInteractFlag.class)) { 452 return true; 453 } 454 List<BlockTypeWrapper> use = plot.getFlag(UseFlag.class); 455 for (final BlockTypeWrapper blockTypeWrapper : use) { 456 if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper 457 .accepts(blockType)) { 458 return true; 459 } 460 } 461 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER, false); 462 } 463 case SPAWN_MOB -> { 464 if (plot == null) { 465 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_ROAD, notifyPerms); 466 } 467 if (!plot.hasOwner()) { 468 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED, notifyPerms); 469 } 470 if (plot.getFlag(MobPlaceFlag.class)) { 471 return true; 472 } 473 List<BlockTypeWrapper> place = plot.getFlag(PlaceFlag.class); 474 for (final BlockTypeWrapper blockTypeWrapper : place) { 475 if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper 476 .accepts(blockType)) { 477 return true; 478 } 479 } 480 if (player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER, false)) { 481 return true; 482 } 483 if (notifyPerms) { 484 player.sendMessage( 485 TranslatableCaption.of("commandconfig.flag_tutorial_usage"), 486 TagResolver.resolver( 487 "flag", 488 Tag.inserting( 489 PlotFlag.getFlagNameComponent(MobPlaceFlag.class) 490 .append(Component.text("/")) 491 .append(PlotFlag.getFlagNameComponent(PlaceFlag.class)) 492 ) 493 ) 494 ); 495 } 496 return false; 497 } 498 case PLACE_MISC -> { 499 if (plot == null) { 500 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_ROAD, notifyPerms); 501 } 502 if (!plot.hasOwner()) { 503 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED, notifyPerms); 504 } 505 if (plot.getFlag(MiscPlaceFlag.class)) { 506 return true; 507 } 508 List<BlockTypeWrapper> place = plot.getFlag(PlaceFlag.class); 509 for (final BlockTypeWrapper blockTypeWrapper : place) { 510 if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper 511 .accepts(blockType)) { 512 return true; 513 } 514 } 515 if (player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER, false)) { 516 return true; 517 } 518 if (notifyPerms) { 519 player.sendMessage( 520 TranslatableCaption.of("commandconfig.flag_tutorial_usage"), 521 TagResolver.resolver( 522 "flag", 523 Tag.inserting( 524 PlotFlag.getFlagNameComponent(MiscPlaceFlag.class) 525 .append(Component.text("/")) 526 .append(PlotFlag.getFlagNameComponent(PlaceFlag.class)) 527 ) 528 ) 529 ); 530 } 531 return false; 532 } 533 case PLACE_VEHICLE -> { 534 if (plot == null) { 535 return player.hasPermission(Permission.PERMISSION_ADMIN_PLACE_VEHICLE_ROAD, notifyPerms); 536 } 537 if (!plot.hasOwner()) { 538 return player.hasPermission(Permission.PERMISSION_ADMIN_PLACE_VEHICLE_UNOWNED, notifyPerms); 539 } 540 if (plot.getFlag(VehiclePlaceFlag.class)) { 541 return true; 542 } 543 if (player.hasPermission(Permission.PERMISSION_ADMIN_PLACE_VEHICLE_OTHER, false)) { 544 return true; 545 } 546 if (notifyPerms) { 547 player.sendMessage( 548 TranslatableCaption.of("commandconfig.flag_tutorial_usage"), 549 TagResolver.resolver( 550 "flag", 551 Tag.inserting( 552 PlotFlag.getFlagNameComponent(VehiclePlaceFlag.class) 553 ) 554 ) 555 ); 556 } 557 return false; 558 } 559 default -> { 560 } 561 } 562 return true; 563 } 564 565}