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