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