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