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 assert area != null; 375 if (!area.buildRangeContainsY(location.getY()) && !player.hasPermission(Permission.PERMISSION_ADMIN_BUILD_HEIGHT_LIMIT)) { 376 player.sendMessage( 377 TranslatableCaption.of("height.height_limit"), 378 TagResolver.builder() 379 .tag("minheight", Tag.inserting(Component.text(area.getMinBuildHeight()))) 380 .tag("maxheight", Tag.inserting(Component.text(area.getMaxBuildHeight()))) 381 .build() 382 ); 383 return false; 384 } 385 Plot plot = area.getPlot(location); 386 if (plot != null) { 387 if (plot.isAdded(player.getUUID())) { 388 return true; 389 } 390 } 391 switch (type) { 392 case TELEPORT_OBJECT -> { 393 return false; 394 } 395 case READ -> { 396 return true; 397 } 398 case INTERACT_BLOCK -> { 399 if (plot == null) { 400 final List<BlockTypeWrapper> use = area.getRoadFlag(UseFlag.class); 401 for (final BlockTypeWrapper blockTypeWrapper : use) { 402 if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper.accepts(blockType)) { 403 return true; 404 } 405 } 406 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_ROAD, notifyPerms); 407 } 408 if (!plot.hasOwner()) { 409 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED, notifyPerms); 410 } 411 final List<BlockTypeWrapper> use = plot.getFlag(UseFlag.class); 412 for (final BlockTypeWrapper blockTypeWrapper : use) { 413 if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper 414 .accepts(blockType)) { 415 return true; 416 } 417 } 418 if (player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER, false)) { 419 return true; 420 } 421 // we check for the EditSignFlag in the PlayerSignOpenEvent again, but we must not cancel the interact event 422 // or send a message if the flag is true 423 if (BlockCategories.ALL_SIGNS != null && BlockCategories.ALL_SIGNS.contains(blockType) 424 && plot.getFlag(EditSignFlag.class)) { 425 return true; 426 } 427 if (notifyPerms) { 428 player.sendMessage( 429 TranslatableCaption.of("commandconfig.flag_tutorial_usage"), 430 TagResolver.resolver("flag", Tag.inserting(PlaceFlag.getFlagNameComponent(UseFlag.class))) 431 ); 432 } 433 return false; 434 } 435 case TRIGGER_PHYSICAL -> { 436 if (plot == null) { 437 final List<BlockTypeWrapper> use = area.getRoadFlag(UseFlag.class); 438 for (final BlockTypeWrapper blockTypeWrapper : use) { 439 if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper.accepts(blockType)) { 440 return true; 441 } 442 } 443 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_ROAD, false); 444 } 445 if (!plot.hasOwner()) { 446 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED, false); 447 } 448 if (plot.getFlag(DeviceInteractFlag.class)) { 449 return true; 450 } 451 List<BlockTypeWrapper> use = plot.getFlag(UseFlag.class); 452 for (final BlockTypeWrapper blockTypeWrapper : use) { 453 if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper 454 .accepts(blockType)) { 455 return true; 456 } 457 } 458 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER, false); 459 } 460 case SPAWN_MOB -> { 461 if (plot == null) { 462 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_ROAD, notifyPerms); 463 } 464 if (!plot.hasOwner()) { 465 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED, notifyPerms); 466 } 467 if (plot.getFlag(MobPlaceFlag.class)) { 468 return true; 469 } 470 List<BlockTypeWrapper> place = plot.getFlag(PlaceFlag.class); 471 for (final BlockTypeWrapper blockTypeWrapper : place) { 472 if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper 473 .accepts(blockType)) { 474 return true; 475 } 476 } 477 if (player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER, false)) { 478 return true; 479 } 480 if (notifyPerms) { 481 player.sendMessage( 482 TranslatableCaption.of("commandconfig.flag_tutorial_usage"), 483 TagResolver.resolver( 484 "flag", 485 Tag.inserting( 486 PlotFlag.getFlagNameComponent(MobPlaceFlag.class) 487 .append(Component.text("/")) 488 .append(PlotFlag.getFlagNameComponent(PlaceFlag.class)) 489 ) 490 ) 491 ); 492 } 493 return false; 494 } 495 case PLACE_MISC -> { 496 if (plot == null) { 497 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_ROAD, notifyPerms); 498 } 499 if (!plot.hasOwner()) { 500 return player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_UNOWNED, notifyPerms); 501 } 502 if (plot.getFlag(MiscPlaceFlag.class)) { 503 return true; 504 } 505 List<BlockTypeWrapper> place = plot.getFlag(PlaceFlag.class); 506 for (final BlockTypeWrapper blockTypeWrapper : place) { 507 if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper 508 .accepts(blockType)) { 509 return true; 510 } 511 } 512 if (player.hasPermission(Permission.PERMISSION_ADMIN_INTERACT_OTHER, false)) { 513 return true; 514 } 515 if (notifyPerms) { 516 player.sendMessage( 517 TranslatableCaption.of("commandconfig.flag_tutorial_usage"), 518 TagResolver.resolver( 519 "flag", 520 Tag.inserting( 521 PlotFlag.getFlagNameComponent(MiscPlaceFlag.class) 522 .append(Component.text("/")) 523 .append(PlotFlag.getFlagNameComponent(PlaceFlag.class)) 524 ) 525 ) 526 ); 527 } 528 return false; 529 } 530 case PLACE_VEHICLE -> { 531 if (plot == null) { 532 return player.hasPermission(Permission.PERMISSION_ADMIN_PLACE_VEHICLE_ROAD, notifyPerms); 533 } 534 if (!plot.hasOwner()) { 535 return player.hasPermission(Permission.PERMISSION_ADMIN_PLACE_VEHICLE_UNOWNED, notifyPerms); 536 } 537 if (plot.getFlag(VehiclePlaceFlag.class)) { 538 return true; 539 } 540 if (player.hasPermission(Permission.PERMISSION_ADMIN_PLACE_VEHICLE_OTHER, false)) { 541 return true; 542 } 543 if (notifyPerms) { 544 player.sendMessage( 545 TranslatableCaption.of("commandconfig.flag_tutorial_usage"), 546 TagResolver.resolver( 547 "flag", 548 Tag.inserting( 549 PlotFlag.getFlagNameComponent(VehiclePlaceFlag.class) 550 ) 551 ) 552 ); 553 } 554 return false; 555 } 556 default -> { 557 } 558 } 559 return true; 560 } 561 562}