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.collect.Lists; 022import com.google.inject.Inject; 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.PlotPlayer; 029import com.plotsquared.core.plot.Plot; 030import com.plotsquared.core.plot.PlotArea; 031import com.plotsquared.core.plot.schematic.Schematic; 032import com.plotsquared.core.plot.world.PlotAreaManager; 033import com.plotsquared.core.util.SchematicHandler; 034import com.plotsquared.core.util.StringMan; 035import com.plotsquared.core.util.TabCompletions; 036import com.plotsquared.core.util.task.RunnableVal; 037import com.plotsquared.core.util.task.TaskManager; 038import net.kyori.adventure.text.minimessage.Template; 039import org.checkerframework.checker.nullness.qual.NonNull; 040 041import java.net.URL; 042import java.util.ArrayList; 043import java.util.Collection; 044import java.util.Collections; 045import java.util.LinkedList; 046import java.util.List; 047import java.util.UUID; 048import java.util.stream.Collectors; 049 050@CommandDeclaration(command = "schematic", 051 permission = "plots.schematic", 052 aliases = "schem", 053 category = CommandCategory.SCHEMATIC, 054 usage = "/plot schematic <save | saveall | paste | list>") 055public class SchematicCmd extends SubCommand { 056 057 private final PlotAreaManager plotAreaManager; 058 private final SchematicHandler schematicHandler; 059 private boolean running = false; 060 061 @Inject 062 public SchematicCmd( 063 final @NonNull PlotAreaManager plotAreaManager, 064 final @NonNull SchematicHandler schematicHandler 065 ) { 066 this.plotAreaManager = plotAreaManager; 067 this.schematicHandler = schematicHandler; 068 } 069 070 @Override 071 public boolean onCommand(final PlotPlayer<?> player, String[] args) { 072 if (args.length < 1) { 073 player.sendMessage( 074 TranslatableCaption.of("commandconfig.command_syntax"), 075 Template.of("value", "Possible values: save, paste, exportall, list") 076 ); 077 return true; 078 } 079 String arg = args[0].toLowerCase(); 080 switch (arg) { 081 case "paste" -> { 082 if (!player.hasPermission(Permission.PERMISSION_SCHEMATIC_PASTE)) { 083 player.sendMessage( 084 TranslatableCaption.of("permission.no_permission"), 085 Template.of("node", String.valueOf(Permission.PERMISSION_SCHEMATIC_PASTE)) 086 ); 087 return false; 088 } 089 if (args.length < 2) { 090 player.sendMessage( 091 TranslatableCaption.of("commandconfig.command_syntax"), 092 Template.of("value", "Possible values: save, paste, exportall, list") 093 ); 094 break; 095 } 096 Location loc = player.getLocation(); 097 final Plot plot = loc.getPlotAbs(); 098 if (plot == null) { 099 player.sendMessage(TranslatableCaption.of("errors.not_in_plot")); 100 return false; 101 } 102 if (!plot.hasOwner()) { 103 player.sendMessage(TranslatableCaption.of("info.plot_unowned")); 104 return false; 105 } 106 if (!plot.isOwner(player.getUUID()) && !player.hasPermission("plots.admin.command.schematic.paste")) { 107 player.sendMessage(TranslatableCaption.of("permission.no_plot_perms")); 108 return false; 109 } 110 if (plot.getVolume() > Integer.MAX_VALUE) { 111 player.sendMessage(TranslatableCaption.of("schematics.schematic_too_large")); 112 return false; 113 } 114 if (this.running) { 115 player.sendMessage(TranslatableCaption.of("error.task_in_process")); 116 return false; 117 } 118 final String location = args[1]; 119 this.running = true; 120 TaskManager.runTaskAsync(() -> { 121 Schematic schematic = null; 122 if (location.startsWith("url:")) { 123 try { 124 UUID uuid = UUID.fromString(location.substring(4)); 125 URL base = new URL(Settings.Web.URL); 126 URL url = new URL(base, "uploads/" + uuid + ".schematic"); 127 schematic = this.schematicHandler.getSchematic(url); 128 } catch (Exception e) { 129 e.printStackTrace(); 130 player.sendMessage( 131 TranslatableCaption.of("schematics.schematic_invalid"), 132 Template.of("reason", "non-existent url: " + location) 133 ); 134 SchematicCmd.this.running = false; 135 return; 136 } 137 } else { 138 try { 139 schematic = this.schematicHandler.getSchematic(location); 140 } catch (SchematicHandler.UnsupportedFormatException e) { 141 e.printStackTrace(); 142 } 143 } 144 if (schematic == null) { 145 SchematicCmd.this.running = false; 146 player.sendMessage( 147 TranslatableCaption.of("schematics.schematic_invalid"), 148 Template.of("reason", "non-existent or not in gzip format") 149 ); 150 return; 151 } 152 this.schematicHandler.paste( 153 schematic, 154 plot, 155 0, 156 plot.getArea().getMinBuildHeight(), 157 0, 158 false, 159 player, 160 new RunnableVal<>() { 161 @Override 162 public void run(Boolean value) { 163 SchematicCmd.this.running = false; 164 if (value) { 165 player.sendMessage(TranslatableCaption.of("schematics.schematic_paste_success")); 166 } else { 167 player.sendMessage(TranslatableCaption.of("schematics.schematic_paste_failed")); 168 } 169 } 170 } 171 ); 172 }); 173 } 174 case "saveall", "exportall" -> { 175 if (!(player instanceof ConsolePlayer)) { 176 player.sendMessage(TranslatableCaption.of("console.not_console")); 177 return false; 178 } 179 if (args.length != 2) { 180 player.sendMessage(TranslatableCaption.of("schematics.schematic_exportall_world_args")); 181 player.sendMessage( 182 TranslatableCaption.of("commandconfig.command_syntax"), 183 Template.of("value", "Use /plot schematic exportall <area>") 184 ); 185 return false; 186 } 187 PlotArea area = this.plotAreaManager.getPlotAreaByString(args[1]); 188 if (area == null) { 189 player.sendMessage( 190 TranslatableCaption.of("errors.not_valid_plot_world"), 191 Template.of("value", args[1]) 192 ); 193 return false; 194 } 195 Collection<Plot> plots = area.getPlots(); 196 if (plots.isEmpty()) { 197 player.sendMessage(TranslatableCaption.of("schematic.schematic_exportall_world")); 198 player.sendMessage( 199 TranslatableCaption.of("commandconfig.command_syntax"), 200 Template.of("value", "Use /plot sch exportall <area>") 201 ); 202 return false; 203 } 204 boolean result = this.schematicHandler.exportAll(plots, null, null, 205 () -> player.sendMessage(TranslatableCaption.of("schematics.schematic_exportall_finished")) 206 ); 207 if (!result) { 208 player.sendMessage(TranslatableCaption.of("error.task_in_process")); 209 return false; 210 } else { 211 player.sendMessage(TranslatableCaption.of("schematics.schematic_exportall_started")); 212 player.sendMessage( 213 TranslatableCaption.of("schematics.plot_to_schem"), 214 Template.of("amount", String.valueOf(plots.size())) 215 ); 216 } 217 } 218 case "export", "save" -> { 219 if (!player.hasPermission(Permission.PERMISSION_SCHEMATIC_SAVE)) { 220 player.sendMessage( 221 TranslatableCaption.of("permission.no_permission"), 222 Template.of("node", String.valueOf(Permission.PERMISSION_SCHEMATIC_SAVE)) 223 ); 224 return false; 225 } 226 if (this.running) { 227 player.sendMessage(TranslatableCaption.of("error.task_in_process")); 228 return false; 229 } 230 Location location = player.getLocation(); 231 Plot plot = location.getPlotAbs(); 232 if (plot == null) { 233 player.sendMessage(TranslatableCaption.of("errors.not_in_plot")); 234 return false; 235 } 236 if (!plot.hasOwner()) { 237 player.sendMessage(TranslatableCaption.of("info.plot_unowned")); 238 return false; 239 } 240 if (plot.getVolume() > Integer.MAX_VALUE) { 241 player.sendMessage(TranslatableCaption.of("schematics.schematic_too_large")); 242 return false; 243 } 244 if (!plot.isOwner(player.getUUID()) && !player.hasPermission("plots.admin.command.schematic.save")) { 245 player.sendMessage(TranslatableCaption.of("permission.no_plot_perms")); 246 return false; 247 } 248 ArrayList<Plot> plots = Lists.newArrayList(plot); 249 boolean result = this.schematicHandler.exportAll(plots, null, null, () -> { 250 player.sendMessage(TranslatableCaption.of("schematics.schematic_exportall_single_finished")); 251 SchematicCmd.this.running = false; 252 }); 253 if (!result) { 254 player.sendMessage(TranslatableCaption.of("error.task_in_process")); 255 return false; 256 } else { 257 player.sendMessage(TranslatableCaption.of("schematics.schematic_exportall_started")); 258 } 259 } 260 case "list" -> { 261 if (!player.hasPermission(Permission.PERMISSION_SCHEMATIC_LIST)) { 262 player.sendMessage( 263 TranslatableCaption.of("permission.no_permission"), 264 Template.of("node", String.valueOf(Permission.PERMISSION_SCHEMATIC_LIST)) 265 ); 266 return false; 267 } 268 final String string = StringMan.join(this.schematicHandler.getSchematicNames(), "$2, $1"); 269 player.sendMessage( 270 TranslatableCaption.of("schematics.schematic_list"), 271 Template.of("list", string) 272 ); 273 } 274 default -> player.sendMessage( 275 TranslatableCaption.of("commandconfig.command_syntax"), 276 Template.of("value", "Possible values: save, paste, exportall, list") 277 ); 278 } 279 return true; 280 } 281 282 @Override 283 public Collection<Command> tab(final PlotPlayer<?> player, final String[] args, final boolean space) { 284 if (args.length == 1) { 285 final List<String> completions = new LinkedList<>(); 286 if (player.hasPermission(Permission.PERMISSION_SCHEMATIC_SAVE)) { 287 completions.add("save"); 288 } 289 if (player.hasPermission(Permission.PERMISSION_SCHEMATIC_LIST)) { 290 completions.add("list"); 291 } 292 if (player.hasPermission(Permission.PERMISSION_SCHEMATIC_PASTE)) { 293 completions.add("paste"); 294 } 295 final List<Command> commands = completions.stream().filter(completion -> completion 296 .toLowerCase() 297 .startsWith(args[0].toLowerCase())) 298 .map(completion -> new Command( 299 null, 300 true, 301 completion, 302 "", 303 RequiredType.NONE, 304 CommandCategory.ADMINISTRATION 305 ) { 306 }).collect(Collectors.toCollection(LinkedList::new)); 307 if (player.hasPermission(Permission.PERMISSION_SCHEMATIC) && args[0].length() > 0) { 308 commands.addAll(TabCompletions.completePlayers(player, args[0], Collections.emptyList())); 309 } 310 return commands; 311 } 312 return TabCompletions.completePlayers(player, String.join(",", args).trim(), Collections.emptyList()); 313 } 314 315}