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.Injector; 022import com.plotsquared.core.PlotSquared; 023import com.plotsquared.core.configuration.Settings; 024import com.plotsquared.core.configuration.caption.TranslatableCaption; 025import com.plotsquared.core.location.Location; 026import com.plotsquared.core.permissions.Permission; 027import com.plotsquared.core.player.ConsolePlayer; 028import com.plotsquared.core.player.MetaDataAccess; 029import com.plotsquared.core.player.PlayerMetaDataKeys; 030import com.plotsquared.core.player.PlotPlayer; 031import com.plotsquared.core.plot.Plot; 032import com.plotsquared.core.plot.PlotArea; 033import com.plotsquared.core.plot.world.SinglePlotArea; 034import com.plotsquared.core.util.EconHandler; 035import com.plotsquared.core.util.PlotExpression; 036import com.plotsquared.core.util.task.RunnableVal2; 037import com.plotsquared.core.util.task.RunnableVal3; 038import net.kyori.adventure.text.Component; 039import net.kyori.adventure.text.minimessage.tag.Tag; 040import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; 041import org.apache.logging.log4j.LogManager; 042import org.apache.logging.log4j.Logger; 043 044import java.util.Arrays; 045import java.util.LinkedList; 046import java.util.List; 047import java.util.concurrent.CompletableFuture; 048 049/** 050 * PlotSquared command class. 051 */ 052@CommandDeclaration(command = "plot", 053 aliases = {"plots", "p", "plotsquared", "plot2", "p2", "ps", "2", "plotme", "plotz", "ap"}) 054public class MainCommand extends Command { 055 056 private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + MainCommand.class.getSimpleName()); 057 058 private static MainCommand instance; 059 public Help help; 060 public Toggle toggle; 061 062 private MainCommand() { 063 super(null, true); 064 instance = this; 065 } 066 067 public static MainCommand getInstance() { 068 if (instance == null) { 069 instance = new MainCommand(); 070 071 final Injector injector = PlotSquared.platform().injector(); 072 final List<Class<? extends Command>> commands = new LinkedList<>(); 073 commands.add(Caps.class); 074 commands.add(Buy.class); 075 if (Settings.Web.LEGACY_WEBINTERFACE) { 076 LOGGER.warn("Legacy webinterface is used. Please note that it will be removed in future."); 077 } 078 commands.add(Load.class); 079 commands.add(Confirm.class); 080 commands.add(Template.class); 081 commands.add(Download.class); 082 commands.add(Setup.class); 083 commands.add(Area.class); 084 commands.add(DebugSaveTest.class); 085 commands.add(DebugLoadTest.class); 086 commands.add(CreateRoadSchematic.class); 087 commands.add(DebugAllowUnsafe.class); 088 commands.add(RegenAllRoads.class); 089 commands.add(Claim.class); 090 commands.add(Auto.class); 091 commands.add(HomeCommand.class); 092 commands.add(Visit.class); 093 commands.add(Set.class); 094 commands.add(Clear.class); 095 commands.add(Delete.class); 096 commands.add(Trust.class); 097 commands.add(Add.class); 098 commands.add(Leave.class); 099 commands.add(Deny.class); 100 commands.add(Remove.class); 101 commands.add(Info.class); 102 commands.add(Near.class); 103 commands.add(ListCmd.class); 104 commands.add(Debug.class); 105 commands.add(SchematicCmd.class); 106 commands.add(PluginCmd.class); 107 commands.add(Purge.class); 108 commands.add(Reload.class); 109 commands.add(Merge.class); 110 commands.add(DebugPaste.class); 111 commands.add(Unlink.class); 112 commands.add(Kick.class); 113 commands.add(Inbox.class); 114 commands.add(Comment.class); 115 commands.add(DatabaseCommand.class); 116 commands.add(Swap.class); 117 commands.add(Music.class); 118 commands.add(DebugRoadRegen.class); 119 commands.add(DebugExec.class); 120 commands.add(FlagCommand.class); 121 commands.add(Target.class); 122 commands.add(Move.class); 123 commands.add(Condense.class); 124 commands.add(Copy.class); 125 commands.add(Trim.class); 126 commands.add(Done.class); 127 commands.add(Continue.class); 128 commands.add(Middle.class); 129 commands.add(Grant.class); 130 commands.add(Owner.class); 131 commands.add(Desc.class); 132 commands.add(Biome.class); 133 commands.add(Alias.class); 134 commands.add(SetHome.class); 135 commands.add(Cluster.class); 136 commands.add(DebugImportWorlds.class); 137 commands.add(Backup.class); 138 139 if (Settings.Ratings.USE_LIKES) { 140 commands.add(Like.class); 141 commands.add(Dislike.class); 142 } else { 143 commands.add(Rate.class); 144 } 145 146 for (final Class<? extends Command> command : commands) { 147 try { 148 injector.getInstance(command); 149 } catch (final Exception e) { 150 LOGGER.error("Failed to register command {}", command.getCanonicalName()); 151 e.printStackTrace(); 152 } 153 } 154 155 // Referenced commands 156 instance.toggle = injector.getInstance(Toggle.class); 157 instance.help = new Help(instance); 158 } 159 return instance; 160 } 161 162 public static boolean onCommand(final PlotPlayer<?> player, String... args) { 163 final EconHandler econHandler = PlotSquared.platform().econHandler(); 164 if (args.length >= 1 && args[0].contains(":")) { 165 String[] split2 = args[0].split(":"); 166 if (split2.length == 2) { 167 // Ref: c:v, this will push value to the last spot in the array 168 // ex. /p h:2 SomeUsername 169 // > /p h SomeUsername 2 170 String[] tmp = new String[args.length + 1]; 171 tmp[0] = split2[0]; 172 tmp[args.length] = split2[1]; 173 if (args.length >= 2) { 174 System.arraycopy(args, 1, tmp, 1, args.length - 1); 175 } 176 args = tmp; 177 } 178 } 179 try { 180 getInstance().execute(player, args, new RunnableVal3<>() { 181 @Override 182 public void run(final Command cmd, final Runnable success, final Runnable failure) { 183 if (cmd.hasConfirmation(player)) { 184 CmdConfirm.addPending(player, cmd.getUsage(), () -> { 185 PlotArea area = player.getApplicablePlotArea(); 186 if (area != null && econHandler.isEnabled(area) && !player.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_ECON)) { 187 PlotExpression priceEval = 188 area.getPrices().get(cmd.getFullId()); 189 double price = priceEval != null ? priceEval.evaluate(0d) : 0d; 190 if (econHandler.getMoney(player) < price) { 191 if (failure != null) { 192 failure.run(); 193 } 194 return; 195 } 196 } 197 if (success != null) { 198 success.run(); 199 } 200 }); 201 return; 202 } 203 PlotArea area = player.getApplicablePlotArea(); 204 if (area != null && econHandler.isEnabled(area) && !player.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_ECON)) { 205 PlotExpression priceEval = area.getPrices().get(cmd.getFullId()); 206 double price = priceEval != null ? priceEval.evaluate(0d) : 0d; 207 if (price != 0d && econHandler.getMoney(player) < price) { 208 if (failure != null) { 209 failure.run(); 210 } 211 return; 212 } 213 } 214 if (success != null) { 215 success.run(); 216 } 217 } 218 }, new RunnableVal2<>() { 219 @Override 220 public void run(Command cmd, CommandResult result) { 221 // Post command stuff!? 222 } 223 }).thenAccept(result -> { 224 // TODO: Something with the command result 225 }); 226 } catch (CommandException e) { 227 e.perform(player); 228 } 229 // Always true 230 return true; 231 } 232 233 @Override 234 public CompletableFuture<Boolean> execute( 235 final PlotPlayer<?> player, String[] args, 236 RunnableVal3<Command, Runnable, Runnable> confirm, 237 RunnableVal2<Command, CommandResult> whenDone 238 ) { 239 // Optional command scope // 240 Location location = null; 241 Plot plot = null; 242 boolean tp = false; 243 if (args.length >= 2) { 244 PlotArea area = player.getApplicablePlotArea(); 245 Plot newPlot = Plot.fromString(area, args[0]); 246 if (newPlot != null && (player instanceof ConsolePlayer || newPlot.getArea() 247 .equals(area) || player.hasPermission(Permission.PERMISSION_ADMIN) 248 || player.hasPermission(Permission.PERMISSION_ADMIN_AREA_SUDO)) 249 && !newPlot.isDenied(player.getUUID())) { 250 final Location newLoc; 251 if (newPlot.getArea() instanceof SinglePlotArea) { 252 newLoc = newPlot.isLoaded() ? newPlot.getCenterSynchronous() : Location.at("", 0, 0, 0); 253 } else { 254 newLoc = newPlot.getCenterSynchronous(); 255 } 256 if (player.canTeleport(newLoc)) { 257 // Save meta 258 try (final MetaDataAccess<Location> locationMetaDataAccess 259 = player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { 260 location = locationMetaDataAccess.get().orElse(null); 261 locationMetaDataAccess.set(newLoc); 262 } 263 try (final MetaDataAccess<Plot> plotMetaDataAccess 264 = player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { 265 plot = plotMetaDataAccess.get().orElse(null); 266 plotMetaDataAccess.set(newPlot); 267 } 268 tp = true; 269 } else { 270 player.sendMessage(TranslatableCaption.of("border.denied")); 271 } 272 // Trim command 273 args = Arrays.copyOfRange(args, 1, args.length); 274 } 275 if (args.length >= 2 && !args[0].isEmpty() && args[0].charAt(0) == '-') { 276 if ("f".equals(args[0].substring(1))) { 277 confirm = new RunnableVal3<>() { 278 @Override 279 public void run(Command cmd, Runnable success, Runnable failure) { 280 if (area != null && PlotSquared.platform().econHandler().isEnabled(area)) { 281 PlotExpression priceEval = 282 area.getPrices().get(cmd.getFullId()); 283 double price = priceEval != null ? priceEval.evaluate(0d) : 0d; 284 if (price != 0d 285 && PlotSquared.platform().econHandler().getMoney(player) < price) { 286 if (failure != null) { 287 failure.run(); 288 } 289 return; 290 } 291 } 292 if (success != null) { 293 success.run(); 294 } 295 } 296 }; 297 args = Arrays.copyOfRange(args, 1, args.length); 298 } else { 299 player.sendMessage(TranslatableCaption.of("errors.invalid_command_flag")); 300 return CompletableFuture.completedFuture(false); 301 } 302 } 303 } 304 try { 305 super.execute(player, args, confirm, whenDone); 306 } catch (CommandException e) { 307 throw e; 308 } catch (Throwable e) { 309 e.printStackTrace(); 310 String message = e.getMessage(); 311 if (message != null) { 312 player.sendMessage( 313 TranslatableCaption.of("errors.error"), 314 TagResolver.resolver("value", Tag.inserting(Component.text(message))) 315 ); 316 } else { 317 player.sendMessage( 318 TranslatableCaption.of("errors.error_console")); 319 } 320 } 321 // Reset command scope // 322 if (tp && !(player instanceof ConsolePlayer)) { 323 try (final MetaDataAccess<Location> locationMetaDataAccess 324 = player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { 325 if (location == null) { 326 locationMetaDataAccess.remove(); 327 } else { 328 locationMetaDataAccess.set(location); 329 } 330 } 331 try (final MetaDataAccess<Plot> plotMetaDataAccess 332 = player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { 333 if (plot == null) { 334 plotMetaDataAccess.remove(); 335 } else { 336 plotMetaDataAccess.set(plot); 337 } 338 } 339 } 340 return CompletableFuture.completedFuture(true); 341 } 342 343 @Override 344 public boolean canExecute(PlotPlayer<?> player, boolean message) { 345 return true; 346 } 347 348}