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.backup.BackupManager; 024import com.plotsquared.core.configuration.Settings; 025import com.plotsquared.core.configuration.caption.StaticCaption; 026import com.plotsquared.core.configuration.caption.TranslatableCaption; 027import com.plotsquared.core.inject.factory.ProgressSubscriberFactory; 028import com.plotsquared.core.permissions.Permission; 029import com.plotsquared.core.player.PlotPlayer; 030import com.plotsquared.core.plot.Plot; 031import com.plotsquared.core.plot.PlotArea; 032import com.plotsquared.core.plot.PlotManager; 033import com.plotsquared.core.queue.QueueCoordinator; 034import com.plotsquared.core.util.PatternUtil; 035import com.plotsquared.core.util.StringMan; 036import com.plotsquared.core.util.TabCompletions; 037import com.plotsquared.core.util.WorldUtil; 038import com.sk89q.worldedit.function.pattern.Pattern; 039import com.sk89q.worldedit.world.block.BlockCategory; 040import com.sk89q.worldedit.world.block.BlockType; 041import com.sk89q.worldedit.world.block.BlockTypes; 042import net.kyori.adventure.text.minimessage.Template; 043import org.checkerframework.checker.nullness.qual.NonNull; 044 045import java.util.ArrayList; 046import java.util.Arrays; 047import java.util.Collection; 048import java.util.Collections; 049import java.util.HashSet; 050import java.util.LinkedList; 051import java.util.List; 052import java.util.Locale; 053import java.util.stream.Collectors; 054 055@CommandDeclaration(command = "set", 056 aliases = {"s"}, 057 usage = "/plot set <biome | alias | home | flag> <value...>", 058 permission = "plots.set", 059 category = CommandCategory.APPEARANCE, 060 requiredType = RequiredType.NONE) 061public class Set extends SubCommand { 062 063 public static final String[] values = new String[]{"biome", "alias", "home"}; 064 public static final String[] aliases = new String[]{"b", "w", "wf", "a", "h"}; 065 066 private final SetCommand component; 067 068 @Inject 069 public Set(final @NonNull WorldUtil worldUtil) { 070 this.component = new SetCommand() { 071 072 @Override 073 public String getId() { 074 return "set.component"; 075 } 076 077 @Override 078 public boolean set(PlotPlayer<?> player, final Plot plot, String value) { 079 final PlotArea plotArea = player.getLocation().getPlotArea(); 080 if (plotArea == null) { 081 return false; 082 } 083 final PlotManager manager = plotArea.getPlotManager(); 084 085 String[] components = manager.getPlotComponents(plot.getId()); 086 087 String[] args = value.split(" "); 088 String material = 089 StringMan.join(Arrays.copyOfRange(args, 1, args.length), ",").trim(); 090 091 final List<String> forbiddenTypes = new ArrayList<>(Settings.General.INVALID_BLOCKS); 092 093 if (Settings.Enabled_Components.CHUNK_PROCESSOR) { 094 forbiddenTypes.addAll(worldUtil.getTileEntityTypes().stream().map( 095 BlockType::getName).toList()); 096 } 097 098 if (!player.hasPermission(Permission.PERMISSION_ADMIN_ALLOW_UNSAFE) && 099 !forbiddenTypes.isEmpty()) { 100 for (String forbiddenType : forbiddenTypes) { 101 forbiddenType = forbiddenType.toLowerCase(Locale.ENGLISH); 102 if (forbiddenType.startsWith("minecraft:")) { 103 forbiddenType = forbiddenType.substring(10); 104 } 105 for (String blockType : material.split(",")) { 106 blockType = blockType.toLowerCase(Locale.ENGLISH); 107 if (blockType.startsWith("minecraft:")) { 108 blockType = blockType.substring(10); 109 } 110 111 if (blockType.startsWith("##")) { 112 try { 113 final BlockCategory category = BlockCategory.REGISTRY.get(blockType.substring(2) 114 .replaceAll("[*^|]+", "").toLowerCase(Locale.ENGLISH)); 115 if (category == null || !category.contains(BlockTypes.get(forbiddenType))) { 116 continue; 117 } 118 } catch (final Throwable ignored) { 119 } 120 } else if (!blockType.contains(forbiddenType)) { 121 continue; 122 } 123 player.sendMessage( 124 TranslatableCaption.of("invalid.component_illegal_block"), 125 Template.of("value", forbiddenType) 126 ); 127 return true; 128 } 129 } 130 } 131 132 for (String component : components) { 133 if (component.equalsIgnoreCase(args[0])) { 134 if (!player.hasPermission(Permission.PERMISSION_SET_COMPONENT.format(component))) { 135 player.sendMessage( 136 TranslatableCaption.of("permission.no_permission"), 137 Template.of("node", Permission.PERMISSION_SET_COMPONENT.format(component)) 138 ); 139 return false; 140 } 141 if (args.length < 2) { 142 player.sendMessage(TranslatableCaption.of("need.need_block")); 143 return true; 144 } 145 146 Pattern pattern = PatternUtil.parse(player, material, false); 147 148 if (plot.getRunning() > 0) { 149 player.sendMessage(TranslatableCaption.of("errors.wait_for_timer")); 150 return false; 151 } 152 153 BackupManager.backup(player, plot, () -> { 154 plot.addRunning(); 155 QueueCoordinator queue = plotArea.getQueue(); 156 queue.setCompleteTask(() -> { 157 plot.removeRunning(); 158 player.sendMessage( 159 TranslatableCaption.of("working.component_complete"), 160 Template.of("plot", plot.getId().toString()) 161 ); 162 }); 163 if (Settings.QUEUE.NOTIFY_PROGRESS) { 164 queue.addProgressSubscriber( 165 PlotSquared 166 .platform() 167 .injector() 168 .getInstance(ProgressSubscriberFactory.class) 169 .createWithActor(player)); 170 } 171 for (final Plot current : plot.getConnectedPlots()) { 172 current.getPlotModificationManager().setComponent(component, pattern, player, queue); 173 } 174 queue.enqueue(); 175 player.sendMessage(TranslatableCaption.of("working.generating_component")); 176 }); 177 return true; 178 } 179 } 180 return false; 181 } 182 183 @Override 184 public Collection<Command> tab( 185 final PlotPlayer<?> player, final String[] args, 186 final boolean space 187 ) { 188 return TabCompletions.completePatterns(StringMan.join(args, ",")); 189 } 190 }; 191 } 192 193 public boolean noArgs(PlotPlayer<?> player) { 194 ArrayList<String> newValues = new ArrayList<>(Arrays.asList("biome", "alias", "home")); 195 Plot plot = player.getCurrentPlot(); 196 if (plot != null) { 197 newValues.addAll(Arrays.asList(plot.getManager().getPlotComponents(plot.getId()))); 198 } 199 player.sendMessage(StaticCaption.of(TranslatableCaption 200 .of("commandconfig.subcommand_set_options_header_only") 201 .getComponent(player) + StringMan 202 .join(newValues, TranslatableCaption.of("blocklist.block_list_separator").getComponent(player)))); 203 return false; 204 } 205 206 @Override 207 public boolean onCommand(PlotPlayer<?> player, String[] args) { 208 if (args.length == 0) { 209 return noArgs(player); 210 } 211 Command cmd = MainCommand.getInstance().getCommand("set" + args[0]); 212 if (cmd != null) { 213 if (!player.hasPermission(cmd.getPermission(), true)) { 214 return false; 215 } 216 cmd.execute(player, Arrays.copyOfRange(args, 1, args.length), null, null); 217 return true; 218 } 219 // Additional checks 220 Plot plot = player.getCurrentPlot(); 221 if (plot == null) { 222 player.sendMessage(TranslatableCaption.of("errors.not_in_plot")); 223 return false; 224 } 225 if (plot.getVolume() > Integer.MAX_VALUE) { 226 player.sendMessage(TranslatableCaption.of("schematics.schematic_too_large")); 227 return false; 228 } 229 // components 230 HashSet<String> components = 231 new HashSet<>(Arrays.asList(plot.getManager().getPlotComponents(plot.getId()))); 232 if (components.contains(args[0].toLowerCase())) { 233 return this.component.onCommand(player, Arrays.copyOfRange(args, 0, args.length)); 234 } 235 return noArgs(player); 236 } 237 238 @Override 239 public Collection<Command> tab(final PlotPlayer<?> player, String[] args, boolean space) { 240 if (args.length == 1) { 241 final List<String> completions = new LinkedList<>(); 242 243 if (player.hasPermission(Permission.PERMISSION_SET_BIOME)) { 244 completions.add("biome"); 245 } 246 if (player.hasPermission(Permission.PERMISSION_SET_ALIAS)) { 247 completions.add("alias"); 248 } 249 if (player.hasPermission(Permission.PERMISSION_SET_HOME)) { 250 completions.add("home"); 251 } 252 if (player.hasPermission(Permission.PERMISSION_SET_MAIN)) { 253 completions.add("main"); 254 } 255 if (player.hasPermission(Permission.PERMISSION_SET_FLOOR)) { 256 completions.add("floor"); 257 } 258 if (player.hasPermission(Permission.PERMISSION_SET_AIR)) { 259 completions.add("air"); 260 } 261 if (player.hasPermission(Permission.PERMISSION_SET_ALL)) { 262 completions.add("all"); 263 } 264 if (player.hasPermission(Permission.PERMISSION_SET_BORDER)) { 265 completions.add("border"); 266 } 267 if (player.hasPermission(Permission.PERMISSION_SET_WALL)) { 268 completions.add("wall"); 269 } 270 if (player.hasPermission(Permission.PERMISSION_SET_OUTLINE)) { 271 completions.add("outline"); 272 } 273 if (player.hasPermission(Permission.PERMISSION_SET_MIDDLE)) { 274 completions.add("middle"); 275 } 276 final List<Command> commands = completions.stream().filter(completion -> completion 277 .toLowerCase() 278 .startsWith(args[0].toLowerCase())) 279 .map(completion -> new Command(null, true, completion, "", RequiredType.NONE, CommandCategory.APPEARANCE) { 280 }).collect(Collectors.toCollection(LinkedList::new)); 281 282 if (player.hasPermission(Permission.PERMISSION_SET) && args[0].length() > 0) { 283 commands.addAll(TabCompletions.completePlayers(player, args[0], Collections.emptyList())); 284 } 285 return commands; 286 } else if (args.length > 1) { 287 // Additional checks 288 Plot plot = player.getCurrentPlot(); 289 if (plot == null) { 290 return new ArrayList<>(); 291 } 292 293 final String[] newArgs = new String[args.length - 1]; 294 System.arraycopy(args, 1, newArgs, 0, newArgs.length); 295 296 final Command cmd = MainCommand.getInstance().getCommand("set" + args[0]); 297 if (cmd != null) { 298 if (!player.hasPermission(cmd.getPermission(), true)) { 299 return new ArrayList<>(); 300 } 301 return cmd.tab(player, newArgs, space); 302 } 303 304 // components 305 HashSet<String> components = 306 new HashSet<>(Arrays.asList(plot.getManager().getPlotComponents(plot.getId()))); 307 if (components.contains(args[0].toLowerCase())) { 308 return this.component.tab(player, newArgs, space); 309 } 310 } 311 return tabOf(player, args, space); 312 } 313 314}