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.google.inject.Inject; 022import com.plotsquared.core.PlotSquared; 023import com.plotsquared.core.configuration.Settings; 024import com.plotsquared.core.configuration.caption.TranslatableCaption; 025import com.plotsquared.core.database.DBFunc; 026import com.plotsquared.core.events.PlayerPlotAddRemoveEvent; 027import com.plotsquared.core.events.Result; 028import com.plotsquared.core.permissions.Permission; 029import com.plotsquared.core.player.PlotPlayer; 030import com.plotsquared.core.plot.Plot; 031import com.plotsquared.core.util.EventDispatcher; 032import com.plotsquared.core.util.PlayerManager; 033import com.plotsquared.core.util.TabCompletions; 034import com.plotsquared.core.util.task.RunnableVal2; 035import com.plotsquared.core.util.task.RunnableVal3; 036import net.kyori.adventure.text.Component; 037import net.kyori.adventure.text.minimessage.tag.Tag; 038import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; 039import org.checkerframework.checker.nullness.qual.NonNull; 040 041import java.util.Collection; 042import java.util.Collections; 043import java.util.Iterator; 044import java.util.UUID; 045import java.util.concurrent.CompletableFuture; 046import java.util.concurrent.TimeoutException; 047 048@CommandDeclaration(command = "add", 049 usage = "/plot add <player | *>", 050 category = CommandCategory.SETTINGS, 051 permission = "plots.add", 052 requiredType = RequiredType.PLAYER) 053public class Add extends Command { 054 055 private final EventDispatcher eventDispatcher; 056 057 @Inject 058 public Add(final @NonNull EventDispatcher eventDispatcher) { 059 super(MainCommand.getInstance(), true); 060 this.eventDispatcher = eventDispatcher; 061 } 062 063 @Override 064 public CompletableFuture<Boolean> execute( 065 final PlotPlayer<?> player, 066 String[] args, 067 RunnableVal3<Command, Runnable, Runnable> confirm, 068 RunnableVal2<Command, CommandResult> whenDone 069 ) throws CommandException { 070 final Plot plot = check(player.getCurrentPlot(), TranslatableCaption.of("errors.not_in_plot")); 071 checkTrue(plot.hasOwner(), TranslatableCaption.of("info.plot_unowned")); 072 checkTrue( 073 plot.isOwner(player.getUUID()) || player.hasPermission(Permission.PERMISSION_ADMIN_COMMAND_TRUST), 074 TranslatableCaption.of("permission.no_plot_perms") 075 ); 076 checkTrue( 077 args.length == 1, 078 TranslatableCaption.of("commandconfig.command_syntax"), 079 TagResolver.resolver("value", Tag.inserting(Component.text("/plot add <player | *>"))) 080 ); 081 final CompletableFuture<Boolean> future = new CompletableFuture<>(); 082 PlayerManager.getUUIDsFromString(args[0], (uuids, throwable) -> { 083 if (throwable != null) { 084 if (throwable instanceof TimeoutException) { 085 player.sendMessage(TranslatableCaption.of("players.fetching_players_timeout")); 086 } else { 087 player.sendMessage( 088 TranslatableCaption.of("errors.invalid_player"), 089 TagResolver.resolver("value", Tag.inserting(Component.text(args[0]))) 090 ); 091 } 092 future.completeExceptionally(throwable); 093 return; 094 } else { 095 try { 096 checkTrue(!uuids.isEmpty(), TranslatableCaption.of("errors.invalid_player"), 097 TagResolver.resolver("value", Tag.inserting(Component.text(args[0]))) 098 ); 099 Iterator<UUID> iterator = uuids.iterator(); 100 int size = plot.getTrusted().size() + plot.getMembers().size(); 101 while (iterator.hasNext()) { 102 UUID uuid = iterator.next(); 103 if (uuid == DBFunc.EVERYONE && !(player.hasPermission(Permission.PERMISSION_TRUST_EVERYONE) || player.hasPermission( 104 Permission.PERMISSION_ADMIN_COMMAND_TRUST))) { 105 player.sendMessage( 106 TranslatableCaption.of("errors.invalid_player"), 107 PlotSquared 108 .platform() 109 .playerManager() 110 .getUsernameCaption(uuid) 111 .thenApply(caption -> TagResolver.resolver( 112 "value", 113 Tag.inserting(caption.toComponent(player)) 114 )) 115 ); 116 iterator.remove(); 117 continue; 118 } 119 if (plot.isOwner(uuid)) { 120 player.sendMessage( 121 TranslatableCaption.of("member.already_added"), 122 PlotSquared.platform().playerManager().getUsernameCaption(uuid) 123 .thenApply(caption -> TagResolver.resolver( 124 "player", 125 Tag.inserting(caption.toComponent(player)) 126 )) 127 ); 128 iterator.remove(); 129 continue; 130 } 131 if (plot.getMembers().contains(uuid)) { 132 player.sendMessage( 133 TranslatableCaption.of("member.already_added"), 134 PlotSquared.platform().playerManager().getUsernameCaption(uuid) 135 .thenApply(caption -> TagResolver.resolver( 136 "player", 137 Tag.inserting(caption.toComponent(player)) 138 )) 139 ); 140 iterator.remove(); 141 continue; 142 } 143 size += plot.getTrusted().contains(uuid) ? 0 : 1; 144 } 145 checkTrue(!uuids.isEmpty(), null); 146 int localAddSize = plot.getMembers().size(); 147 int maxAddSize = player.hasPermissionRange(Permission.PERMISSION_ADD, Settings.Limit.MAX_PLOTS); 148 if (localAddSize >= maxAddSize) { 149 player.sendMessage( 150 TranslatableCaption.of("members.plot_max_members_added"), 151 TagResolver.resolver("amount", Tag.inserting(Component.text(localAddSize))) 152 ); 153 return; 154 } 155 // Success 156 confirm.run( 157 this, () -> { 158 for (UUID uuid : uuids) { 159 if (this.eventDispatcher.callPlayerAdd( 160 player, 161 plot, 162 uuid, 163 PlayerPlotAddRemoveEvent.Reason.COMMAND 164 ).getEventResult() == Result.DENY) { 165 player.sendMessage( 166 TranslatableCaption.of("events.event_denied"), 167 TagResolver.resolver("value", Tag.inserting(Component.text("Add"))) 168 ); 169 continue; 170 } 171 if (uuid != DBFunc.EVERYONE) { 172 if (!plot.removeTrusted(uuid)) { 173 if (plot.getDenied().contains(uuid)) { 174 plot.removeDenied(uuid); 175 } 176 } 177 } 178 plot.addMember(uuid); 179 this.eventDispatcher.callMember(player, plot, uuid, true); 180 this.eventDispatcher.callPostAdded( 181 player, 182 plot, 183 uuid, 184 false, 185 PlayerPlotAddRemoveEvent.Reason.COMMAND 186 ); 187 player.sendMessage(TranslatableCaption.of("member.member_added")); 188 } 189 }, null 190 ); 191 } catch (final Throwable exception) { 192 future.completeExceptionally(exception); 193 return; 194 } 195 } 196 future.complete(true); 197 }); 198 return future; 199 } 200 201 @Override 202 public Collection<Command> tab(final PlotPlayer<?> player, final String[] args, final boolean space) { 203 return TabCompletions.completePlayers(player, String.join(",", args).trim(), Collections.emptyList()); 204 } 205 206}