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.command; 020 021import com.plotsquared.core.PlotSquared; 022import com.plotsquared.core.configuration.Settings; 023import com.plotsquared.core.configuration.caption.Caption; 024import com.plotsquared.core.configuration.caption.TranslatableCaption; 025import com.plotsquared.core.database.DBFunc; 026import com.plotsquared.core.events.TeleportCause; 027import com.plotsquared.core.location.BlockLoc; 028import com.plotsquared.core.location.Location; 029import com.plotsquared.core.permissions.Permission; 030import com.plotsquared.core.player.PlotPlayer; 031import com.plotsquared.core.plot.Plot; 032import com.plotsquared.core.plot.PlotArea; 033import com.plotsquared.core.plot.PlotCluster; 034import com.plotsquared.core.plot.PlotId; 035import com.plotsquared.core.util.ComponentHelper; 036import com.plotsquared.core.util.TabCompletions; 037import com.plotsquared.core.util.query.PlotQuery; 038import net.kyori.adventure.text.Component; 039import net.kyori.adventure.text.format.NamedTextColor; 040import net.kyori.adventure.text.format.Style; 041import net.kyori.adventure.text.minimessage.tag.Tag; 042import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; 043 044import java.util.Collection; 045import java.util.Collections; 046import java.util.HashSet; 047import java.util.LinkedList; 048import java.util.List; 049import java.util.Objects; 050import java.util.Set; 051import java.util.UUID; 052import java.util.concurrent.TimeoutException; 053import java.util.stream.Collectors; 054import java.util.stream.Stream; 055 056@CommandDeclaration(command = "cluster", 057 aliases = "clusters", 058 category = CommandCategory.ADMINISTRATION, 059 requiredType = RequiredType.NONE, 060 permission = "plots.cluster") 061public class Cluster extends SubCommand { 062 063 private static final Component[] AVAILABLE_ARGS = Stream.of( 064 "list", "create", "delete", "resize", "invite", "kick", "leave", "helpers", "tp", "sethome" 065 ).map(s -> Component.text(s).style(Style.style(NamedTextColor.DARK_AQUA))).toArray(Component[]::new); 066 private static final Component SEPARATOR = Component.text(", ").style(Style.style(NamedTextColor.GRAY)); 067 068 // list, create, delete, resize, invite, kick, leave, helpers, tp, sethome 069 @Override 070 public boolean onCommand(PlotPlayer<?> player, String[] args) { 071 if (args.length == 0) { 072 // return arguments 073 player.sendMessage( 074 TranslatableCaption.of("cluster.cluster_available_args"), 075 TagResolver.resolver("list", Tag.inserting(ComponentHelper.join(AVAILABLE_ARGS, SEPARATOR))) 076 ); 077 return false; 078 } 079 String sub = args[0].toLowerCase(); 080 switch (sub) { 081 case "l", "list" -> { 082 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_LIST)) { 083 player.sendMessage( 084 TranslatableCaption.of("permission.no_permission"), 085 TagResolver.resolver( 086 "node", 087 Tag.inserting(Permission.PERMISSION_CLUSTER_LIST) 088 ) 089 ); 090 return false; 091 } 092 if (args.length != 1) { 093 player.sendMessage( 094 TranslatableCaption.of("commandconfig.command_syntax"), 095 TagResolver.resolver("value", Tag.inserting(Component.text("/plot cluster list"))) 096 ); 097 return false; 098 } 099 PlotArea area = player.getApplicablePlotArea(); 100 if (area == null) { 101 player.sendMessage(TranslatableCaption.of("errors.not_in_plot_world")); 102 return false; 103 } 104 Set<PlotCluster> clusters = area.getClusters(); 105 player.sendMessage( 106 TranslatableCaption.of("cluster.cluster_list_heading"), 107 TagResolver.resolver("amount", Tag.inserting(Component.text(clusters.size()))) 108 ); 109 for (PlotCluster cluster : clusters) { 110 // Ignore unmanaged clusters 111 String name = "'" + cluster.getName() + "' : " + cluster; 112 if (player.getUUID().equals(cluster.owner)) { 113 player.sendMessage( 114 TranslatableCaption.of("cluster.cluster_list_element_owner"), 115 TagResolver.resolver("cluster", Tag.inserting(Component.text(name))) 116 ); 117 } else if (cluster.helpers.contains(player.getUUID())) { 118 player.sendMessage( 119 TranslatableCaption.of("cluster.cluster_list_element_helpers"), 120 TagResolver.resolver("cluster", Tag.inserting(Component.text(name))) 121 ); 122 } else if (cluster.invited.contains(player.getUUID())) { 123 player.sendMessage( 124 TranslatableCaption.of("cluster.cluster_list_element_invited"), 125 TagResolver.resolver("cluster", Tag.inserting(Component.text(name))) 126 ); 127 } else { 128 player.sendMessage( 129 TranslatableCaption.of("cluster.cluster_list_element"), 130 TagResolver.resolver("cluster", Tag.inserting(Component.text(cluster.toString()))) 131 ); 132 } 133 } 134 return true; 135 } 136 case "c", "create" -> { 137 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_CREATE)) { 138 player.sendMessage( 139 TranslatableCaption.of("permission.no_permission"), 140 TagResolver.resolver( 141 "node", 142 Tag.inserting(Permission.PERMISSION_CLUSTER_CREATE) 143 ) 144 ); 145 return false; 146 } 147 PlotArea area = player.getApplicablePlotArea(); 148 if (area == null) { 149 player.sendMessage(TranslatableCaption.of("errors.not_in_plot_world")); 150 return false; 151 } 152 if (args.length != 4) { 153 player.sendMessage( 154 TranslatableCaption.of("commandconfig.command_syntax"), 155 TagResolver.resolver( 156 "value", 157 Tag.inserting(Component.text("/plot cluster create <name> <id-bot> <id-top>")) 158 ) 159 ); 160 return false; 161 } 162 int currentClusters = Settings.Limit.GLOBAL ? 163 player.getClusterCount() : 164 player.getPlotCount(player.getLocation().getWorldName()); 165 if (currentClusters >= player.getAllowedPlots()) { 166 player.sendMessage( 167 TranslatableCaption.of("permission.cant_claim_more_clusters"), 168 TagResolver.resolver("amount", Tag.inserting(Component.text(player.getAllowedPlots()))) 169 ); 170 } 171 PlotId pos1; 172 PlotId pos2; 173 // check pos1 / pos2 174 try { 175 pos1 = PlotId.fromString(args[2]); 176 pos2 = PlotId.fromString(args[3]); 177 } catch (IllegalArgumentException ignored) { 178 player.sendMessage(TranslatableCaption.of("invalid.not_valid_plot_id")); 179 return false; 180 } 181 // check if name is taken 182 String name = args[1]; 183 if (area.getCluster(name) != null) { 184 player.sendMessage( 185 TranslatableCaption.of("alias.alias_is_taken"), 186 TagResolver.resolver("alias", Tag.inserting(Component.text(name))) 187 ); 188 return false; 189 } 190 if (pos2.getX() < pos1.getX() || pos2.getY() < pos1.getY()) { 191 PlotId tmp = PlotId.of(Math.min(pos1.getX(), pos2.getX()), Math.min(pos1.getY(), pos2.getY())); 192 pos2 = PlotId.of(Math.max(pos1.getX(), pos2.getX()), Math.max(pos1.getY(), pos2.getY())); 193 pos1 = tmp; 194 } 195 //check if overlap 196 PlotCluster cluster = area.getFirstIntersectingCluster(pos1, pos2); 197 if (cluster != null) { 198 player.sendMessage( 199 TranslatableCaption.of("cluster.cluster_intersection"), 200 TagResolver.resolver("cluster", Tag.inserting(Component.text(cluster.getName()))) 201 ); 202 return false; 203 } 204 // Check if it occupies existing plots 205 if (!area.contains(pos1) || !area.contains(pos2)) { 206 player.sendMessage( 207 TranslatableCaption.of("cluster.cluster_outside"), 208 TagResolver.resolver("area", Tag.inserting(Component.text(area.toString()))) 209 ); 210 return false; 211 } 212 Set<Plot> plots = area.getPlotSelectionOwned(pos1, pos2); 213 if (!plots.isEmpty()) { 214 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_CREATE_OTHER)) { 215 UUID uuid = player.getUUID(); 216 for (Plot plot : plots) { 217 if (!plot.isOwner(uuid)) { 218 player.sendMessage( 219 TranslatableCaption.of("permission.no_permission"), 220 TagResolver.resolver( 221 "node", 222 Tag.inserting(Permission.PERMISSION_CLUSTER_CREATE_OTHER) 223 ) 224 ); 225 return false; 226 } 227 } 228 } 229 } 230 // Check allowed cluster size 231 cluster = new PlotCluster(area, pos1, pos2, player.getUUID()); 232 int current; 233 if (Settings.Limit.GLOBAL) { 234 current = player.getPlayerClusterCount(); 235 } else { 236 current = player.getPlayerClusterCount(player.getLocation().getWorldName()); 237 } 238 int allowed = player.hasPermissionRange( 239 Permission.PERMISSION_CLUSTER_SIZE, 240 Settings.Limit.MAX_PLOTS 241 ); 242 if (current + cluster.getArea() > allowed) { 243 player.sendMessage( 244 TranslatableCaption.of("permission.no_permission"), 245 TagResolver.resolver( 246 "node", 247 Tag.inserting(Component.text(Permission.PERMISSION_CLUSTER_SIZE + "." + (current + cluster.getArea()))) 248 ) 249 ); 250 return false; 251 } 252 // create cluster 253 cluster.settings.setAlias(name); 254 area.addCluster(cluster); 255 DBFunc.createCluster(cluster); 256 // Add any existing plots to the current cluster 257 for (Plot plot : plots) { 258 if (plot.hasOwner()) { 259 if (!cluster.isAdded(plot.getOwner())) { 260 cluster.invited.add(plot.getOwner()); 261 DBFunc.setInvited(cluster, plot.getOwner()); 262 } 263 } 264 } 265 player.sendMessage( 266 TranslatableCaption.of("cluster.cluster_created"), 267 TagResolver.resolver("name", Tag.inserting(Component.text(name))) 268 ); 269 return true; 270 } 271 case "disband", "del", "delete" -> { 272 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_DELETE)) { 273 player.sendMessage( 274 TranslatableCaption.of("permission.no_permission"), 275 TagResolver.resolver( 276 "node", 277 Tag.inserting(Permission.PERMISSION_CLUSTER_DELETE) 278 ) 279 ); 280 return false; 281 } 282 if (args.length != 1 && args.length != 2) { 283 player.sendMessage( 284 TranslatableCaption.of("commandconfig.command_syntax"), 285 TagResolver.resolver("value", Tag.inserting(Component.text("/plot cluster delete [name]"))) 286 ); 287 return false; 288 } 289 PlotArea area = player.getApplicablePlotArea(); 290 if (area == null) { 291 player.sendMessage(TranslatableCaption.of("errors.not_in_plot_world")); 292 return false; 293 } 294 PlotCluster cluster; 295 if (args.length == 2) { 296 cluster = area.getCluster(args[1]); 297 if (cluster == null) { 298 player.sendMessage( 299 TranslatableCaption.of("cluster.invalid_cluster_name"), 300 TagResolver.resolver("cluster", Tag.inserting(Component.text(args[1]))) 301 ); 302 return false; 303 } 304 } else { 305 cluster = area.getCluster(player.getLocation()); 306 if (cluster == null) { 307 player.sendMessage(TranslatableCaption.of("errors.not_in_cluster")); 308 return false; 309 } 310 } 311 if (!cluster.owner.equals(player.getUUID())) { 312 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_DELETE_OTHER)) { 313 player.sendMessage( 314 TranslatableCaption.of("permission.no_permission"), 315 TagResolver.resolver( 316 "node", 317 Tag.inserting(Permission.PERMISSION_CLUSTER_DELETE_OTHER) 318 ) 319 ); 320 return false; 321 } 322 } 323 DBFunc.delete(cluster); 324 player.sendMessage(TranslatableCaption.of("cluster.cluster_deleted"), TagResolver.resolver( 325 "cluster", 326 Tag.inserting(Component.text(cluster.toString())) 327 )); 328 return true; 329 } 330 case "res", "resize" -> { 331 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_RESIZE)) { 332 player.sendMessage( 333 TranslatableCaption.of("permission.no_permission"), 334 TagResolver.resolver( 335 "node", 336 Tag.inserting(Permission.PERMISSION_CLUSTER_RESIZE) 337 ) 338 ); 339 return false; 340 } 341 if (args.length != 3) { 342 player.sendMessage( 343 TranslatableCaption.of("commandconfig.command_syntax"), 344 TagResolver.resolver("value", Tag.inserting(Component.text("/plot cluster resize [name]"))) 345 ); 346 return false; 347 } 348 PlotId pos1; 349 PlotId pos2; 350 // check pos1 / pos2 351 try { 352 pos1 = PlotId.fromString(args[2]); 353 pos2 = PlotId.fromString(args[3]); 354 } catch (IllegalArgumentException ignored) { 355 player.sendMessage(TranslatableCaption.of("invalid.not_valid_plot_id")); 356 return false; 357 } 358 if (pos2.getX() < pos1.getX() || pos2.getY() < pos1.getY()) { 359 pos1 = PlotId.of(Math.min(pos1.getX(), pos2.getX()), Math.min(pos1.getY(), pos2.getY())); 360 pos2 = PlotId.of(Math.max(pos1.getX(), pos2.getX()), Math.max(pos1.getY(), pos2.getY())); 361 } 362 // check if in cluster 363 PlotArea area = player.getApplicablePlotArea(); 364 if (area == null) { 365 player.sendMessage(TranslatableCaption.of("errors.not_in_plot_world")); 366 return false; 367 } 368 PlotCluster cluster = area.getCluster(player.getLocation()); 369 if (cluster == null) { 370 player.sendMessage(TranslatableCaption.of("errors.not_in_cluster")); 371 return false; 372 } 373 if (!cluster.hasHelperRights(player.getUUID())) { 374 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_RESIZE_OTHER)) { 375 player.sendMessage( 376 TranslatableCaption.of("permission.no_permission"), 377 TagResolver.resolver( 378 "node", 379 Tag.inserting(Permission.PERMISSION_CLUSTER_RESIZE_OTHER) 380 ) 381 ); 382 return false; 383 } 384 } 385 //check if overlap 386 PlotCluster intersect = area.getFirstIntersectingCluster(pos1, pos2); 387 if (intersect != null) { 388 player.sendMessage( 389 TranslatableCaption.of("cluster.cluster_intersection"), 390 TagResolver.resolver("cluster", Tag.inserting(Component.text(intersect.getName()))) 391 ); 392 return false; 393 } 394 Set<Plot> existing = area.getPlotSelectionOwned(cluster.getP1(), cluster.getP2()); 395 Set<Plot> newPlots = area.getPlotSelectionOwned(pos1, pos2); 396 Set<Plot> removed = new HashSet<>(existing); 397 398 removed.removeAll(newPlots); 399 // Check expand / shrink 400 if (!removed.isEmpty()) { 401 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_RESIZE_SHRINK)) { 402 player.sendMessage( 403 TranslatableCaption.of("permission.no_permission"), 404 TagResolver.resolver( 405 "node", 406 Tag.inserting(Permission.PERMISSION_CLUSTER_RESIZE_SHRINK) 407 ) 408 ); 409 return false; 410 } 411 } 412 newPlots.removeAll(existing); 413 if (!newPlots.isEmpty()) { 414 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_RESIZE_EXPAND)) { 415 player.sendMessage( 416 TranslatableCaption.of("permission.no_permission"), 417 TagResolver.resolver( 418 "node", 419 Tag.inserting(Permission.PERMISSION_CLUSTER_RESIZE_EXPAND) 420 ) 421 ); 422 return false; 423 } 424 } 425 // Check allowed cluster size 426 int current; 427 if (Settings.Limit.GLOBAL) { 428 current = player.getPlayerClusterCount(); 429 } else { 430 current = player.getPlayerClusterCount(player.getLocation().getWorldName()); 431 } 432 current -= cluster.getArea() + (1 + pos2.getX() - pos1.getX()) * (1 + pos2.getY() - pos1.getY()); 433 int allowed = player.hasPermissionRange( 434 Permission.PERMISSION_CLUSTER, 435 Settings.Limit.MAX_PLOTS 436 ); 437 if (current + cluster.getArea() > allowed) { 438 player.sendMessage( 439 TranslatableCaption.of("permission.no_permission"), 440 TagResolver.resolver("node", Tag.inserting(Component.text( 441 Permission.PERMISSION_CLUSTER + "." + (current + cluster.getArea()) 442 ))) 443 ); 444 return false; 445 } 446 // resize cluster 447 DBFunc.resizeCluster(cluster, pos1, pos2); 448 player.sendMessage(TranslatableCaption.of("cluster.cluster_resized")); 449 return true; 450 } 451 case "add", "inv", "invite" -> { 452 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_INVITE)) { 453 player.sendMessage( 454 TranslatableCaption.of("permission.no_permission"), 455 TagResolver.resolver( 456 "node", 457 Tag.inserting(Permission.PERMISSION_CLUSTER_INVITE) 458 ) 459 ); 460 return false; 461 } 462 if (args.length != 2) { 463 player.sendMessage( 464 TranslatableCaption.of("commandconfig.command_syntax"), 465 TagResolver.resolver("value", Tag.inserting(Component.text("/plot cluster invite <player>"))) 466 ); 467 return false; 468 } 469 // check if in cluster 470 PlotArea area = player.getApplicablePlotArea(); 471 if (area == null) { 472 player.sendMessage(TranslatableCaption.of("errors.not_in_plot_world")); 473 } 474 PlotCluster cluster = area.getCluster(player.getLocation()); 475 if (cluster == null) { 476 player.sendMessage(TranslatableCaption.of("errors.not_in_cluster")); 477 return false; 478 } 479 if (!cluster.hasHelperRights(player.getUUID())) { 480 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_INVITE_OTHER)) { 481 player.sendMessage( 482 TranslatableCaption.of("permission.no_permission"), 483 TagResolver.resolver( 484 "node", 485 Tag.inserting(Permission.PERMISSION_CLUSTER_INVITE_OTHER) 486 ) 487 ); 488 return false; 489 } 490 } 491 492 PlotSquared.get().getImpromptuUUIDPipeline() 493 .getSingle(args[1], (uuid, throwable) -> { 494 if (throwable instanceof TimeoutException) { 495 player.sendMessage(TranslatableCaption.of("players.fetching_players_timeout")); 496 } else if (throwable != null) { 497 player.sendMessage( 498 TranslatableCaption.of("errors.invalid_player"), 499 TagResolver.resolver("value", Tag.inserting(Component.text(args[1]))) 500 ); 501 } else { 502 if (!cluster.isAdded(uuid)) { 503 // add the user if not added 504 cluster.invited.add(uuid); 505 DBFunc.setInvited(cluster, uuid); 506 final PlotPlayer<?> otherPlayer = 507 PlotSquared.platform().playerManager().getPlayerIfExists(uuid); 508 if (otherPlayer != null) { 509 player.sendMessage( 510 TranslatableCaption.of("cluster.cluster_invited"), 511 TagResolver.resolver("cluster", Tag.inserting(Component.text(cluster.getName()))) 512 ); 513 } 514 } 515 player.sendMessage(TranslatableCaption.of("cluster.cluster_added_user")); 516 } 517 }); 518 return true; 519 } 520 case "k", "remove", "kick" -> { 521 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_KICK)) { 522 player.sendMessage( 523 TranslatableCaption.of("permission.no_permission"), 524 TagResolver.resolver( 525 "node", 526 Tag.inserting(Permission.PERMISSION_CLUSTER_KICK) 527 ) 528 ); 529 return false; 530 } 531 if (args.length != 2) { 532 player.sendMessage( 533 TranslatableCaption.of("commandconfig.command_syntax"), 534 TagResolver.resolver("value", Tag.inserting(Component.text("/plot cluster kick <player>"))) 535 ); 536 return false; 537 } 538 PlotArea area = player.getApplicablePlotArea(); 539 if (area == null) { 540 player.sendMessage(TranslatableCaption.of("errors.not_in_plot_world")); 541 } 542 PlotCluster cluster = area.getCluster(player.getLocation()); 543 if (cluster == null) { 544 player.sendMessage(TranslatableCaption.of("errors.not_in_cluster")); 545 return false; 546 } 547 if (!cluster.hasHelperRights(player.getUUID())) { 548 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_KICK_OTHER)) { 549 player.sendMessage( 550 TranslatableCaption.of("permission.no_permission"), 551 TagResolver.resolver( 552 "node", 553 Tag.inserting(Permission.PERMISSION_CLUSTER_KICK_OTHER) 554 ) 555 ); 556 return false; 557 } 558 } 559 // check uuid 560 PlotSquared.get().getImpromptuUUIDPipeline() 561 .getSingle(args[1], (uuid, throwable) -> { 562 if (throwable instanceof TimeoutException) { 563 player.sendMessage(TranslatableCaption.of("players.fetching_players_timeout")); 564 } else if (throwable != null) { 565 player.sendMessage( 566 TranslatableCaption.of("errors.invalid_player"), 567 TagResolver.resolver("value", Tag.inserting(Component.text(args[1]))) 568 ); 569 } else { 570 // Can't kick if the player is yourself, the owner, or not added to the cluster 571 if (uuid.equals(player.getUUID()) || uuid.equals(cluster.owner) 572 || !cluster.isAdded(uuid)) { 573 player.sendMessage( 574 TranslatableCaption.of("cluster.cannot_kick_player"), 575 TagResolver.resolver("value", Tag.inserting(Component.text(cluster.getName()))) 576 ); 577 } else { 578 if (cluster.helpers.contains(uuid)) { 579 cluster.helpers.remove(uuid); 580 DBFunc.removeHelper(cluster, uuid); 581 } 582 cluster.invited.remove(uuid); 583 DBFunc.removeInvited(cluster, uuid); 584 585 final PlotPlayer<?> player2 = 586 PlotSquared.platform().playerManager().getPlayerIfExists(uuid); 587 if (player2 != null) { 588 player.sendMessage( 589 TranslatableCaption.of("cluster.cluster_removed"), 590 TagResolver.resolver("cluster", Tag.inserting(Component.text(cluster.getName()))) 591 ); 592 } 593 removePlayerPlots(cluster, uuid, player2.getLocation().getWorldName()); 594 player.sendMessage(TranslatableCaption.of("cluster.cluster_kicked_user")); 595 } 596 } 597 }); 598 return true; 599 } 600 case "quit", "leave" -> { 601 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_LEAVE)) { 602 player.sendMessage( 603 TranslatableCaption.of("permission.no_permission"), 604 TagResolver.resolver( 605 "node", 606 Tag.inserting(Permission.PERMISSION_CLUSTER_LEAVE) 607 ) 608 ); 609 return false; 610 } 611 if (args.length != 1 && args.length != 2) { 612 player.sendMessage( 613 TranslatableCaption.of("commandconfig.command_syntax"), 614 TagResolver.resolver("value", Tag.inserting(Component.text("/plot cluster leave [name]"))) 615 ); 616 return false; 617 } 618 PlotArea area = player.getApplicablePlotArea(); 619 if (area == null) { 620 player.sendMessage(TranslatableCaption.of("errors.not_in_plot_world")); 621 } 622 PlotCluster cluster; 623 if (args.length == 2) { 624 cluster = area.getCluster(args[1]); 625 if (cluster == null) { 626 player.sendMessage( 627 TranslatableCaption.of("cluster.invalid_cluster_name"), 628 TagResolver.resolver("cluster", Tag.inserting(Component.text(args[1]))) 629 ); 630 return false; 631 } 632 } else { 633 cluster = area.getCluster(player.getLocation()); 634 if (cluster == null) { 635 player.sendMessage(TranslatableCaption.of("errors.not_in_cluster")); 636 return false; 637 } 638 } 639 UUID uuid = player.getUUID(); 640 if (!cluster.isAdded(uuid)) { 641 player.sendMessage(TranslatableCaption.of("cluster.cluster_not_added")); 642 return false; 643 } 644 if (uuid.equals(cluster.owner)) { 645 player.sendMessage(TranslatableCaption.of("cluster.cluster_cannot_leave")); 646 return false; 647 } 648 if (cluster.helpers.contains(uuid)) { 649 cluster.helpers.remove(uuid); 650 DBFunc.removeHelper(cluster, uuid); 651 } 652 cluster.invited.remove(uuid); 653 DBFunc.removeInvited(cluster, uuid); 654 player.sendMessage( 655 TranslatableCaption.of("cluster.cluster_removed"), 656 TagResolver.resolver("cluster", Tag.inserting(Component.text(cluster.getName()))) 657 ); 658 removePlayerPlots(cluster, uuid, player.getLocation().getWorldName()); 659 return true; 660 } 661 case "members" -> { 662 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_HELPERS)) { 663 player.sendMessage( 664 TranslatableCaption.of("permission.no_permission"), 665 TagResolver.resolver( 666 "node", 667 Tag.inserting(Component.text(Permission.PERMISSION_CLUSTER_HELPERS.toString())) 668 ) 669 ); 670 return false; 671 } 672 if (args.length != 3) { 673 player.sendMessage( 674 TranslatableCaption.of("commandconfig.command_syntax"), 675 TagResolver.resolver( 676 "value", 677 Tag.inserting(Component.text("/plot cluster members <add | remove> <player>")) 678 ) 679 ); 680 return false; 681 } 682 PlotArea area = player.getApplicablePlotArea(); 683 if (area == null) { 684 player.sendMessage(TranslatableCaption.of("errors.not_in_plot_world")); 685 } 686 PlotCluster cluster = area.getCluster(player.getLocation()); 687 if (cluster == null) { 688 player.sendMessage(TranslatableCaption.of("errors.not_in_cluster")); 689 return false; 690 } 691 692 PlotSquared.get().getImpromptuUUIDPipeline() 693 .getSingle(args[2], (uuid, throwable) -> { 694 if (throwable instanceof TimeoutException) { 695 player.sendMessage(TranslatableCaption.of("players.fetching_players_timeout")); 696 } else if (throwable != null) { 697 player.sendMessage( 698 TranslatableCaption.of("errors.invalid_player"), 699 TagResolver.resolver("value", Tag.inserting(Component.text(args[2]))) 700 ); 701 } else { 702 if (args[1].equalsIgnoreCase("add")) { 703 cluster.helpers.add(uuid); 704 DBFunc.setHelper(cluster, uuid); 705 player.sendMessage(TranslatableCaption.of("cluster.cluster_added_helper")); 706 } else if (args[1].equalsIgnoreCase("remove")) { 707 cluster.helpers.remove(uuid); 708 DBFunc.removeHelper(cluster, uuid); 709 player.sendMessage(TranslatableCaption.of("cluster.cluster_removed_helper")); 710 } else { 711 player.sendMessage( 712 TranslatableCaption.of("commandconfig.command_syntax"), 713 TagResolver.resolver("value", Tag.inserting(Component.text( 714 "/plot cluster members <add | remove> <player>" 715 ))) 716 ); 717 } 718 } 719 }); 720 return true; 721 } 722 case "spawn", "home", "tp" -> { 723 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_TP)) { 724 player.sendMessage( 725 TranslatableCaption.of("permission.no_permission"), 726 TagResolver.resolver( 727 "node", 728 Tag.inserting(Permission.PERMISSION_CLUSTER_TP) 729 ) 730 ); 731 return false; 732 } 733 if (args.length != 2) { 734 player.sendMessage( 735 TranslatableCaption.of("commandconfig.command_syntax"), 736 TagResolver.resolver("value", Tag.inserting(Component.text("/plot cluster tp <name>"))) 737 ); 738 return false; 739 } 740 PlotArea area = player.getApplicablePlotArea(); 741 if (area == null) { 742 player.sendMessage(TranslatableCaption.of("errors.not_in_plot_world")); 743 return false; 744 } 745 PlotCluster cluster = area.getCluster(args[1]); 746 if (cluster == null) { 747 player.sendMessage( 748 TranslatableCaption.of("cluster.invalid_cluster_name"), 749 TagResolver.resolver("cluster", Tag.inserting(Component.text(args[1]))) 750 ); 751 return false; 752 } 753 UUID uuid = player.getUUID(); 754 if (!cluster.isAdded(uuid)) { 755 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_TP_OTHER)) { 756 player.sendMessage( 757 TranslatableCaption.of("permission.no_permission"), 758 TagResolver.resolver( 759 "node", 760 Tag.inserting(Permission.PERMISSION_CLUSTER_TP_OTHER) 761 ) 762 ); 763 return false; 764 } 765 } 766 cluster.getHome(home -> player.teleport(home, TeleportCause.COMMAND_CLUSTER_TELEPORT)); 767 player.sendMessage(TranslatableCaption.of("cluster.cluster_teleporting")); 768 return true; 769 } 770 case "i", "info", "show", "information" -> { 771 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_INFO)) { 772 player.sendMessage( 773 TranslatableCaption.of("permission.no_permission"), 774 TagResolver.resolver( 775 "node", 776 Tag.inserting(Permission.PERMISSION_CLUSTER_TP) 777 ) 778 ); 779 return false; 780 } 781 if (args.length != 1 && args.length != 2) { 782 player.sendMessage( 783 TranslatableCaption.of("commandconfig.command_syntax"), 784 TagResolver.resolver("value", Tag.inserting(Component.text("/plot cluster info [name]"))) 785 ); 786 } 787 PlotArea area = player.getApplicablePlotArea(); 788 if (area == null) { 789 player.sendMessage(TranslatableCaption.of("errors.not_in_plot_world")); 790 return false; 791 } 792 PlotCluster cluster; 793 if (args.length == 2) { 794 cluster = area.getCluster(args[1]); 795 if (cluster == null) { 796 player.sendMessage( 797 TranslatableCaption.of("cluster.invalid_cluster_name"), 798 TagResolver.resolver("cluster", Tag.inserting(Component.text(args[1]))) 799 ); 800 return false; 801 } 802 } else { 803 cluster = area.getCluster(player.getLocation()); 804 if (cluster == null) { 805 player.sendMessage(TranslatableCaption.of("errors.not_in_cluster")); 806 return false; 807 } 808 } 809 String id = cluster.toString(); 810 811 PlotSquared.get().getImpromptuUUIDPipeline() 812 .getSingle(cluster.owner, (username, throwable) -> { 813 if (throwable instanceof TimeoutException) { 814 player.sendMessage(TranslatableCaption.of("players.fetching_players_timeout")); 815 } else { 816 final String owner; 817 owner = Objects.requireNonNullElse(username, "unknown"); 818 String name = cluster.getName(); 819 String size = (cluster.getP2().getX() - cluster.getP1().getX() + 1) + "x" + ( 820 cluster.getP2().getY() - cluster.getP1().getY() + 1); 821 String rights = cluster.isAdded(player.getUUID()) + ""; 822 Caption message = TranslatableCaption.of("cluster.cluster_info"); 823 TagResolver resolver = TagResolver.builder() 824 .tag("id", Tag.inserting(Component.text(id))) 825 .tag("owner", Tag.inserting(Component.text(owner))) 826 .tag("name", Tag.inserting(Component.text(name))) 827 .tag("size", Tag.inserting(Component.text(size))) 828 .tag("rights", Tag.inserting(Component.text(rights))) 829 .build(); 830 player.sendMessage(message, resolver); 831 } 832 }); 833 return true; 834 } 835 case "sh", "setspawn", "sethome" -> { 836 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_SETHOME)) { 837 player.sendMessage( 838 TranslatableCaption.of("permission.no_permission"), 839 TagResolver.resolver("node", Tag.inserting(Permission.PERMISSION_CLUSTER_SETHOME)) 840 ); 841 return false; 842 } 843 if (args.length != 1 && args.length != 2) { 844 player.sendMessage( 845 TranslatableCaption.of("commandconfig.command_syntax"), 846 TagResolver.resolver("value", Tag.inserting(Component.text("/plot cluster sethome"))) 847 ); 848 return false; 849 } 850 PlotArea area = player.getApplicablePlotArea(); 851 if (area == null) { 852 player.sendMessage(TranslatableCaption.of("errors.not_in_plot_world")); 853 } 854 PlotCluster cluster = area.getCluster(player.getLocation()); 855 if (cluster == null) { 856 player.sendMessage(TranslatableCaption.of("errors.not_in_cluster")); 857 return false; 858 } 859 if (!cluster.hasHelperRights(player.getUUID())) { 860 if (!player.hasPermission(Permission.PERMISSION_CLUSTER_SETHOME_OTHER)) { 861 player.sendMessage( 862 TranslatableCaption.of("permission.no_permission"), 863 TagResolver.resolver( 864 "node", 865 Tag.inserting(Permission.PERMISSION_CLUSTER_SETHOME_OTHER) 866 ) 867 ); 868 return false; 869 } 870 } 871 Location base = cluster.getClusterBottom(); 872 Location relative = player.getLocation().subtract(base.getX(), 0, base.getZ()); 873 BlockLoc blockloc = new BlockLoc(relative.getX(), relative.getY(), relative.getZ()); 874 cluster.settings.setPosition(blockloc); 875 DBFunc.setPosition( 876 cluster, 877 relative.getX() + "," + relative.getY() + "," + relative.getZ() 878 ); 879 player.sendMessage(TranslatableCaption.of("position.position_set")); 880 return true; 881 } 882 } 883 player.sendMessage( 884 TranslatableCaption.of("cluster.cluster_available_args"), 885 TagResolver.resolver("list", Tag.inserting(ComponentHelper.join(AVAILABLE_ARGS, SEPARATOR))) 886 ); 887 return false; 888 } 889 890 private void removePlayerPlots(final PlotCluster cluster, final UUID uuid, final String world) { 891 for (final Plot plot : PlotQuery.newQuery().inWorld(world).ownedBy(uuid)) { 892 PlotCluster current = plot.getCluster(); 893 if (current != null && current.equals(cluster)) { 894 if (plot.getOwners().size() == 1) { 895 plot.unclaim(); 896 } else { 897 for (UUID newOwner : plot.getOwners()) { 898 if (!newOwner.equals(uuid)) { 899 plot.setOwner(newOwner); 900 break; 901 } 902 } 903 } 904 } 905 } 906 } 907 908 @Override 909 public Collection<Command> tab(final PlotPlayer<?> player, final String[] args, final boolean space) { 910 if (args.length == 1) { 911 final List<String> completions = new LinkedList<>(); 912 if (player.hasPermission(Permission.PERMISSION_CLUSTER_LIST)) { 913 completions.add("list"); 914 } 915 if (player.hasPermission(Permission.PERMISSION_CLUSTER_CREATE)) { 916 completions.add("create"); 917 } 918 if (player.hasPermission(Permission.PERMISSION_CLUSTER_DELETE)) { 919 completions.add("delete"); 920 } 921 if (player.hasPermission(Permission.PERMISSION_CLUSTER_RESIZE)) { 922 completions.add("resize"); 923 } 924 if (player.hasPermission(Permission.PERMISSION_CLUSTER_INVITE)) { 925 completions.add("invite"); 926 } 927 if (player.hasPermission(Permission.PERMISSION_CLUSTER_KICK)) { 928 completions.add("kick"); 929 } 930 if (player.hasPermission(Permission.PERMISSION_CLUSTER_KICK)) { 931 completions.add("leave"); 932 } 933 if (player.hasPermission(Permission.PERMISSION_CLUSTER_HELPERS)) { 934 completions.add("members"); 935 } 936 if (player.hasPermission(Permission.PERMISSION_CLUSTER_INFO)) { 937 completions.add("info"); 938 } 939 if (player.hasPermission(Permission.PERMISSION_CLUSTER_TP)) { 940 completions.add("tp"); 941 } 942 if (player.hasPermission(Permission.PERMISSION_CLUSTER_SETHOME)) { 943 completions.add("sethome"); 944 } 945 final List<Command> commands = completions.stream().filter(completion -> completion 946 .toLowerCase() 947 .startsWith(args[0].toLowerCase())) 948 .map(completion -> new Command( 949 null, 950 true, 951 completion, 952 "", 953 RequiredType.NONE, 954 CommandCategory.ADMINISTRATION 955 ) { 956 }).collect(Collectors.toCollection(LinkedList::new)); 957 if (player.hasPermission(Permission.PERMISSION_CLUSTER) && args[0].length() > 0) { 958 commands.addAll(TabCompletions.completePlayers(player, args[0], Collections.emptyList())); 959 } 960 return commands; 961 } 962 return TabCompletions.completePlayers(player, String.join(",", args).trim(), Collections.emptyList()); 963 } 964 965}