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