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.common.primitives.Ints; 022import com.plotsquared.core.PlotSquared; 023import com.plotsquared.core.configuration.caption.TranslatableCaption; 024import com.plotsquared.core.database.DBFunc; 025import com.plotsquared.core.permissions.Permission; 026import com.plotsquared.core.player.MetaDataAccess; 027import com.plotsquared.core.player.PlayerMetaDataKeys; 028import com.plotsquared.core.player.PlotPlayer; 029import com.plotsquared.core.util.PlayerManager; 030import com.plotsquared.core.util.TabCompletions; 031import com.plotsquared.core.util.task.RunnableVal; 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; 037 038import java.util.Collection; 039import java.util.Collections; 040import java.util.LinkedList; 041import java.util.List; 042import java.util.Map; 043import java.util.UUID; 044import java.util.concurrent.CompletableFuture; 045import java.util.concurrent.TimeoutException; 046import java.util.stream.Collectors; 047 048@CommandDeclaration(command = "grant", 049 category = CommandCategory.CLAIMING, 050 usage = "/plot grant <check | add> [player]", 051 permission = "plots.grant", 052 requiredType = RequiredType.NONE) 053public class Grant extends Command { 054 055 public Grant() { 056 super(MainCommand.getInstance(), true); 057 } 058 059 @Override 060 public CompletableFuture<Boolean> execute( 061 final PlotPlayer<?> player, String[] args, 062 RunnableVal3<Command, Runnable, Runnable> confirm, 063 RunnableVal2<Command, CommandResult> whenDone 064 ) throws CommandException { 065 checkTrue( 066 args.length >= 1 && args.length <= 2, 067 TranslatableCaption.of("commandconfig.command_syntax"), 068 TagResolver.resolver("value", Tag.inserting(Component.text("/plot grant <check | add> [player]"))) 069 ); 070 final String arg0 = args[0].toLowerCase(); 071 switch (arg0) { 072 case "add", "check" -> { 073 if (!player.hasPermission(Permission.PERMISSION_GRANT.format(arg0))) { 074 player.sendMessage( 075 TranslatableCaption.of("permission.no_permission"), 076 TagResolver.resolver("node", Tag.inserting(Component.text(Permission.PERMISSION_GRANT.format(arg0)))) 077 ); 078 return CompletableFuture.completedFuture(false); 079 } 080 if (args.length != 2) { 081 break; 082 } 083 PlayerManager.getUUIDsFromString(args[1], (uuids, throwable) -> { 084 if (throwable instanceof TimeoutException) { 085 player.sendMessage(TranslatableCaption.of("players.fetching_players_timeout")); 086 } else if (throwable != null || uuids.size() != 1) { 087 player.sendMessage( 088 TranslatableCaption.of("errors.invalid_player"), 089 TagResolver.resolver("value", Tag.inserting(Component.text(String.valueOf(uuids)))) 090 ); 091 } else { 092 final UUID uuid = uuids.iterator().next(); 093 PlotPlayer<?> pp = PlotSquared.platform().playerManager().getPlayerIfExists(uuid); 094 if (pp != null) { 095 try (final MetaDataAccess<Integer> access = pp.accessPersistentMetaData( 096 PlayerMetaDataKeys.PERSISTENT_GRANTED_PLOTS)) { 097 if (args[0].equalsIgnoreCase("check")) { 098 player.sendMessage( 099 TranslatableCaption.of("grants.granted_plots"), 100 TagResolver.resolver("amount", Tag.inserting(Component.text(access.get().orElse(0)))) 101 ); 102 } else { 103 access.set(access.get().orElse(0) + 1); 104 player.sendMessage( 105 TranslatableCaption.of("grants.added"), 106 TagResolver.resolver("grants", Tag.inserting(Component.text(access.get().orElse(0)))) 107 ); 108 } 109 } 110 } else { 111 DBFunc.getPersistentMeta(uuid, new RunnableVal<>() { 112 @Override 113 public void run(Map<String, byte[]> value) { 114 final byte[] array = value.get("grantedPlots"); 115 if (arg0.equals("check")) { // check 116 int granted; 117 if (array == null) { 118 granted = 0; 119 } else { 120 granted = Ints.fromByteArray(array); 121 } 122 player.sendMessage( 123 TranslatableCaption.of("grants.granted_plots"), 124 TagResolver.resolver("amount", Tag.inserting(Component.text(granted))) 125 ); 126 } else { // add 127 int amount; 128 if (array == null) { 129 amount = 1; 130 } else { 131 amount = 1 + Ints.fromByteArray(array); 132 } 133 boolean replace = array != null; 134 String key = "grantedPlots"; 135 byte[] rawData = Ints.toByteArray(amount); 136 DBFunc.addPersistentMeta(uuid, key, rawData, replace); 137 player.sendMessage( 138 TranslatableCaption.of("grants.added"), 139 TagResolver.resolver("grants", Tag.inserting(Component.text(amount))) 140 ); 141 } 142 } 143 }); 144 } 145 } 146 }); 147 return CompletableFuture.completedFuture(true); 148 } 149 } 150 sendUsage(player); 151 return CompletableFuture.completedFuture(true); 152 } 153 154 @Override 155 public Collection<Command> tab(final PlotPlayer<?> player, final String[] args, final boolean space) { 156 if (args.length == 1) { 157 final List<String> completions = new LinkedList<>(); 158 if (player.hasPermission(Permission.PERMISSION_GRANT_ADD)) { 159 completions.add("add"); 160 } 161 if (player.hasPermission(Permission.PERMISSION_GRANT_CHECK)) { 162 completions.add("check"); 163 } 164 final List<Command> commands = completions.stream().filter(completion -> completion 165 .toLowerCase() 166 .startsWith(args[0].toLowerCase())) 167 .map(completion -> new Command( 168 null, 169 true, 170 completion, 171 "", 172 RequiredType.NONE, 173 CommandCategory.ADMINISTRATION 174 ) { 175 }).collect(Collectors.toCollection(LinkedList::new)); 176 if (player.hasPermission(Permission.PERMISSION_GRANT_SINGLE) && args[0].length() > 0) { 177 commands.addAll(TabCompletions.completePlayers(player, args[0], Collections.emptyList())); 178 } 179 return commands; 180 } 181 return TabCompletions.completePlayers(player, String.join(",", args).trim(), Collections.emptyList()); 182 } 183 184}