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