diff --git a/build.gradle b/build.gradle
index 8bdc30616..839562495 100644
--- a/build.gradle
+++ b/build.gradle
@@ -78,6 +78,11 @@ subprojects {
maven { url "http://maven.sk89q.com/repo/" }
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
}
+ configurations.all {
+ resolutionStrategy {
+ cacheChangingModulesFor 5, 'minutes'
+ }
+ }
}
configure(['core', 'bukkit', 'forge', 'sponge'].collect { project(":worldedit-$it") }) {
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index a2d043d73..0fe76dff3 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -53,5 +53,13 @@
+
+
+
+
+
+
+
+
diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml
index 28ccad1e4..36ccf3d0b 100644
--- a/config/checkstyle/import-control.xml
+++ b/config/checkstyle/import-control.xml
@@ -16,6 +16,7 @@
+
@@ -38,6 +39,7 @@
+
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index a95009c3b..a9534e761 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,6 @@
+#Thu Mar 14 00:19:48 PDT 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip
diff --git a/settings.gradle b/settings.gradle
index efbda026f..84386e427 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -5,4 +5,5 @@ include 'worldedit-libs'
['bukkit', 'core', 'forge', 'sponge'].forEach {
include "worldedit-libs:$it"
include "worldedit-$it"
-}
\ No newline at end of file
+}
+include "worldedit-libs:core:ap"
diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle
index 975aee9d9..7c5ded7b9 100644
--- a/worldedit-bukkit/build.gradle
+++ b/worldedit-bukkit/build.gradle
@@ -8,6 +8,12 @@ repositories {
maven { url 'https://papermc.io/repo/repository/maven-public/' }
}
+configurations.all { Configuration it ->
+ it.resolutionStrategy { ResolutionStrategy rs ->
+ rs.force("com.google.guava:guava:21.0")
+ }
+}
+
dependencies {
compile project(':worldedit-core')
compile project(':worldedit-libs:bukkit')
diff --git a/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/CommandsManagerRegistration.java b/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/CommandsManagerRegistration.java
index 5f8bfbc8c..7e64bf319 100644
--- a/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/CommandsManagerRegistration.java
+++ b/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/CommandsManagerRegistration.java
@@ -31,6 +31,8 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
+@Deprecated
+@SuppressWarnings("deprecation")
public class CommandsManagerRegistration extends CommandRegistration {
protected CommandsManager> commands;
diff --git a/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommand.java b/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommand.java
index 479681c6b..9f1912587 100644
--- a/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommand.java
+++ b/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommand.java
@@ -35,6 +35,7 @@ import java.util.List;
/**
* An implementation of a dynamically registered {@link org.bukkit.command.Command} attached to a plugin
*/
+@SuppressWarnings("deprecation")
public class DynamicPluginCommand extends org.bukkit.command.Command implements PluginIdentifiableCommand {
protected final CommandExecutor owner;
diff --git a/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommandHelpTopic.java b/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommandHelpTopic.java
index 6f4cec526..7635d174e 100644
--- a/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommandHelpTopic.java
+++ b/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommandHelpTopic.java
@@ -30,6 +30,7 @@ import org.bukkit.help.HelpTopicFactory;
import java.util.Map;
+@SuppressWarnings("deprecation")
public class DynamicPluginCommandHelpTopic extends HelpTopic {
private final DynamicPluginCommand cmd;
diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java
index fa3f2917f..0cd9b1b9d 100644
--- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java
+++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java
@@ -20,25 +20,31 @@
package com.sk89q.worldedit.bukkit;
import com.sk89q.bukkit.util.CommandInspector;
-import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.extension.platform.Actor;
-import com.sk89q.worldedit.util.command.CommandMapping;
-import com.sk89q.worldedit.util.command.Description;
-import com.sk89q.worldedit.util.command.Dispatcher;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
+import org.enginehub.piston.CommandManager;
+import org.enginehub.piston.CommandParameters;
+import org.enginehub.piston.NoInputCommandParameters;
+import org.enginehub.piston.inject.InjectedValueStore;
+import org.enginehub.piston.inject.Key;
+import org.enginehub.piston.inject.MapBackedValueStore;
+import org.enginehub.piston.inject.MemoizingValueAccess;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Optional;
+
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.sk89q.worldedit.bukkit.BukkitTextAdapter.reduceToText;
class BukkitCommandInspector implements CommandInspector {
private static final Logger logger = LoggerFactory.getLogger(BukkitCommandInspector.class);
private final WorldEditPlugin plugin;
- private final Dispatcher dispatcher;
+ private final CommandManager dispatcher;
- BukkitCommandInspector(WorldEditPlugin plugin, Dispatcher dispatcher) {
+ BukkitCommandInspector(WorldEditPlugin plugin, CommandManager dispatcher) {
checkNotNull(plugin);
checkNotNull(dispatcher);
this.plugin = plugin;
@@ -47,9 +53,9 @@ class BukkitCommandInspector implements CommandInspector {
@Override
public String getShortText(Command command) {
- CommandMapping mapping = dispatcher.get(command.getName());
- if (mapping != null) {
- return mapping.getDescription().getDescription();
+ Optional mapping = dispatcher.getCommand(command.getName());
+ if (mapping.isPresent()) {
+ return reduceToText(mapping.get().getDescription());
} else {
logger.warn("BukkitCommandInspector doesn't know how about the command '" + command + "'");
return "Help text not available";
@@ -58,10 +64,9 @@ class BukkitCommandInspector implements CommandInspector {
@Override
public String getFullText(Command command) {
- CommandMapping mapping = dispatcher.get(command.getName());
- if (mapping != null) {
- Description description = mapping.getDescription();
- return "Usage: " + description.getUsage() + (description.getHelp() != null ? "\n" + description.getHelp() : "");
+ Optional mapping = dispatcher.getCommand(command.getName());
+ if (mapping.isPresent()) {
+ return reduceToText(mapping.get().getFullHelp());
} else {
logger.warn("BukkitCommandInspector doesn't know how about the command '" + command + "'");
return "Help text not available";
@@ -70,11 +75,15 @@ class BukkitCommandInspector implements CommandInspector {
@Override
public boolean testPermission(CommandSender sender, Command command) {
- CommandMapping mapping = dispatcher.get(command.getName());
- if (mapping != null) {
- CommandLocals locals = new CommandLocals();
- locals.put(Actor.class, plugin.wrapCommandSender(sender));
- return mapping.getCallable().testPermission(locals);
+ Optional mapping = dispatcher.getCommand(command.getName());
+ if (mapping.isPresent()) {
+ InjectedValueStore store = MapBackedValueStore.create();
+ store.injectValue(Key.of(Actor.class), context ->
+ Optional.of(plugin.wrapCommandSender(sender)));
+ CommandParameters parameters = NoInputCommandParameters.builder()
+ .injectedValues(MemoizingValueAccess.wrap(store))
+ .build();
+ return mapping.get().getCondition().satisfied(parameters);
} else {
logger.warn("BukkitCommandInspector doesn't know how about the command '" + command + "'");
return false;
diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java
index b82dfe458..2d4ea70cf 100644
--- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java
+++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java
@@ -26,7 +26,7 @@ import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.cui.CUIEvent;
import com.sk89q.worldedit.session.SessionKey;
import com.sk89q.worldedit.util.auth.AuthorizationException;
-import com.sk89q.worldedit.util.formatting.text.TextComponent;
+import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -94,7 +94,7 @@ public class BukkitCommandSender implements Actor {
}
@Override
- public void print(TextComponent component) {
+ public void print(Component component) {
TextAdapter.sendComponent(sender, component);
}
diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java
index 71941a69d..c0dc5c7e2 100644
--- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java
+++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java
@@ -31,13 +31,13 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.session.SessionKey;
import com.sk89q.worldedit.util.HandSide;
+import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldedit.world.gamemode.GameModes;
-import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -127,7 +127,7 @@ public class BukkitPlayer extends AbstractPlayerActor {
}
@Override
- public void print(TextComponent component) {
+ public void print(Component component) {
TextAdapter.sendComponent(player, component);
}
diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java
index 9dfc856b2..34ad4c257 100644
--- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java
+++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java
@@ -22,27 +22,29 @@ package com.sk89q.worldedit.bukkit;
import com.sk89q.bukkit.util.CommandInfo;
import com.sk89q.bukkit.util.CommandRegistration;
import com.sk89q.worldedit.LocalConfiguration;
+import com.sk89q.worldedit.command.util.PermissionCondition;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.MultiUserPlatform;
import com.sk89q.worldedit.extension.platform.Preference;
-import com.sk89q.worldedit.util.command.CommandMapping;
-import com.sk89q.worldedit.util.command.Description;
-import com.sk89q.worldedit.util.command.Dispatcher;
import com.sk89q.worldedit.world.registry.Registries;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.EntityType;
+import org.enginehub.piston.CommandManager;
+import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
-import javax.annotation.Nullable;
+import static com.sk89q.worldedit.bukkit.BukkitTextAdapter.reduceToText;
public class BukkitServerInterface implements MultiUserPlatform {
public Server server;
@@ -70,7 +72,7 @@ public class BukkitServerInterface implements MultiUserPlatform {
if (plugin.getBukkitImplAdapter() != null) {
return plugin.getBukkitImplAdapter().getDataVersion();
}
- return 0;
+ return -1;
}
@Override
@@ -124,20 +126,25 @@ public class BukkitServerInterface implements MultiUserPlatform {
}
@Override
- public void registerCommands(Dispatcher dispatcher) {
- List toRegister = new ArrayList<>();
+ public void registerCommands(CommandManager dispatcher) {
BukkitCommandInspector inspector = new BukkitCommandInspector(plugin, dispatcher);
-
- for (CommandMapping command : dispatcher.getCommands()) {
- Description description = command.getDescription();
- List permissions = description.getPermissions();
- String[] permissionsArray = new String[permissions.size()];
- permissions.toArray(permissionsArray);
- toRegister.add(new CommandInfo(description.getUsage(), description.getDescription(), command.getAllAliases(), inspector, permissionsArray));
- }
+ dynamicCommands.register(dispatcher.getAllCommands()
+ .map(command -> {
+ String[] permissionsArray = command.getCondition()
+ .as(PermissionCondition.class)
+ .map(PermissionCondition::getPermissions)
+ .map(s -> s.toArray(new String[0]))
+ .orElseGet(() -> new String[0]);
- dynamicCommands.register(toRegister);
+ String[] aliases = Stream.concat(
+ Stream.of(command.getName()),
+ command.getAliases().stream()
+ ).toArray(String[]::new);
+ return new CommandInfo(reduceToText(command.getUsage()),
+ reduceToText(command.getDescription()), aliases,
+ inspector, permissionsArray);
+ }).collect(Collectors.toList()));
}
@Override
diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitTextAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitTextAdapter.java
new file mode 100644
index 000000000..fba2c2b1e
--- /dev/null
+++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitTextAdapter.java
@@ -0,0 +1,48 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.bukkit;
+
+import com.sk89q.worldedit.util.formatting.text.Component;
+import com.sk89q.worldedit.util.formatting.text.TextComponent;
+import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
+
+public class BukkitTextAdapter {
+
+ public static String reduceToText(Component component) {
+ StringBuilder text = new StringBuilder();
+ appendTextTo(text, component);
+ return text.toString();
+ }
+
+ private static void appendTextTo(StringBuilder builder, Component component) {
+ if (component instanceof TextComponent) {
+ builder.append(((TextComponent) component).content());
+ } else if (component instanceof TranslatableComponent) {
+ builder.append(((TranslatableComponent) component).key());
+ }
+ for (Component child : component.children()) {
+ appendTextTo(builder, child);
+ }
+ }
+
+ private BukkitTextAdapter() {
+ }
+
+}
diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java
index 05774b84c..7eea4312b 100644
--- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java
+++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java
@@ -21,13 +21,11 @@
package com.sk89q.worldedit.bukkit;
-import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.util.StringUtil;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.Location;
-import com.sk89q.worldedit.util.command.CommandMapping;
import com.sk89q.worldedit.world.World;
import org.bukkit.block.Block;
import org.bukkit.event.Event.Result;
@@ -40,9 +38,15 @@ import org.bukkit.event.player.PlayerCommandSendEvent;
import org.bukkit.event.player.PlayerGameModeChangeEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
+import org.enginehub.piston.CommandManager;
+import org.enginehub.piston.CommandParameters;
+import org.enginehub.piston.NoInputCommandParameters;
+import org.enginehub.piston.inject.InjectedValueStore;
+import org.enginehub.piston.inject.Key;
+import org.enginehub.piston.inject.MapBackedValueStore;
+import org.enginehub.piston.inject.MemoizingValueAccess;
-import java.util.Set;
-import java.util.stream.Collectors;
+import java.util.Optional;
/**
* Handles all events thrown in relation to a Player
@@ -87,7 +91,7 @@ public class WorldEditListener implements Listener {
if (split.length > 0) {
split[0] = split[0].substring(1);
- split = plugin.getWorldEdit().getPlatformManager().getCommandManager().commandDetection(split);
+ split = plugin.getWorldEdit().getPlatformManager().getPlatformCommandManager().commandDetection(split);
}
final String newMessage = "/" + StringUtil.joinString(split, " ");
@@ -108,13 +112,19 @@ public class WorldEditListener implements Listener {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerCommand(PlayerCommandSendEvent event) {
- CommandLocals locals = new CommandLocals();
- locals.put(Actor.class, plugin.wrapCommandSender(event.getPlayer()));
- Set toRemove = plugin.getWorldEdit().getPlatformManager().getCommandManager().getDispatcher().getCommands().stream()
- .filter(commandMapping -> !commandMapping.getCallable().testPermission(locals))
- .map(CommandMapping::getPrimaryAlias)
- .collect(Collectors.toSet());
- event.getCommands().removeIf(toRemove::contains);
+ InjectedValueStore store = MapBackedValueStore.create();
+ store.injectValue(Key.of(Actor.class), context ->
+ Optional.of(plugin.wrapCommandSender(event.getPlayer())));
+ CommandParameters parameters = NoInputCommandParameters.builder()
+ .injectedValues(MemoizingValueAccess.wrap(store))
+ .build();
+ CommandManager commandManager = plugin.getWorldEdit().getPlatformManager().getPlatformCommandManager().getCommandManager();
+ event.getCommands().removeIf(name ->
+ // remove if in the manager and not satisfied
+ commandManager.getCommand(name)
+ .filter(command -> !command.getCondition().satisfied(parameters))
+ .isPresent()
+ );
}
/**
diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java
index 1c824dcec..99652499d 100644
--- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java
+++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java
@@ -289,7 +289,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
// code of WorldEdit expects it
String[] split = new String[args.length + 1];
System.arraycopy(args, 0, split, 1, args.length);
- split[0] = cmd.getName();
+ split[0] = "/" + cmd.getName();
CommandEvent event = new CommandEvent(wrapCommandSender(sender), Joiner.on(" ").join(split));
getWorldEdit().getEventBus().post(event);
@@ -303,7 +303,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
// code of WorldEdit expects it
String[] split = new String[args.length + 1];
System.arraycopy(args, 0, split, 1, args.length);
- split[0] = cmd.getName();
+ split[0] = "/" + cmd.getName();
CommandSuggestionEvent event = new CommandSuggestionEvent(wrapCommandSender(sender), Joiner.on(" ").join(split));
getWorldEdit().getEventBus().post(event);
diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle
index 828833d9a..9ed0f8b2a 100644
--- a/worldedit-core/build.gradle
+++ b/worldedit-core/build.gradle
@@ -1,28 +1,52 @@
-apply plugin: 'eclipse'
-apply plugin: 'idea'
-
-dependencies {
- compile project(':worldedit-libs:core')
- compile 'de.schlichtherle:truezip:6.8.3'
- compile 'rhino:js:1.7R2'
- compile 'org.yaml:snakeyaml:1.9'
- compile 'com.google.guava:guava:21.0'
- compile 'com.google.code.findbugs:jsr305:1.3.9'
- compile 'com.google.code.gson:gson:2.8.0'
- compile 'com.googlecode.json-simple:json-simple:1.1.1'
- compile 'org.slf4j:slf4j-api:1.7.26'
- //compile 'net.sf.trove4j:trove4j:3.0.3'
- testCompile 'org.mockito:mockito-core:1.9.0-rc1'
-}
-
-sourceSets {
- main {
- java {
- srcDir 'src/main/java'
- srcDir 'src/legacy/java'
- }
- resources {
- srcDir 'src/main/resources'
- }
- }
-}
+plugins {
+ id("net.ltgt.apt") version "0.21"
+}
+
+apply plugin: 'java-library'
+apply plugin: 'eclipse'
+apply plugin: 'idea'
+apply plugin: 'net.ltgt.apt-eclipse'
+apply plugin: 'net.ltgt.apt-idea'
+
+configurations.all { Configuration it ->
+ it.resolutionStrategy { ResolutionStrategy rs ->
+ rs.force("com.google.guava:guava:21.0")
+ }
+}
+
+dependencies {
+ compile project(':worldedit-libs:core')
+ compile 'de.schlichtherle:truezip:6.8.3'
+ compile 'rhino:js:1.7R2'
+ compile 'org.yaml:snakeyaml:1.9'
+ compile 'com.google.guava:guava:21.0'
+ compile 'com.google.code.findbugs:jsr305:1.3.9'
+ compile 'com.google.code.gson:gson:2.8.0'
+ compile 'com.googlecode.json-simple:json-simple:1.1.1'
+ compile 'org.slf4j:slf4j-api:1.7.26'
+
+ compileOnly project(':worldedit-libs:core:ap')
+ annotationProcessor project(':worldedit-libs:core:ap')
+ annotationProcessor "com.google.guava:guava:21.0"
+ def avVersion = "1.6.5"
+ compileOnly "com.google.auto.value:auto-value-annotations:$avVersion"
+ annotationProcessor "com.google.auto.value:auto-value:$avVersion"
+ //compile 'net.sf.trove4j:trove4j:3.0.3'
+ testCompile 'org.mockito:mockito-core:1.9.0-rc1'
+}
+
+tasks.withType(JavaCompile).configureEach {
+ it.options.compilerArgs.add("-Aarg.name.key.prefix=")
+}
+
+sourceSets {
+ main {
+ java {
+ srcDir 'src/main/java'
+ srcDir 'src/legacy/java'
+ }
+ resources {
+ srcDir 'src/main/resources'
+ }
+ }
+}
diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java
index c74c8f382..eb0c2e382 100644
--- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java
+++ b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java
@@ -90,7 +90,7 @@ public class MobSpawnerBlock extends BaseBlock {
/**
* Get the spawn delay.
- *
+ *
* @return the delay
*/
public short getDelay() {
@@ -99,13 +99,13 @@ public class MobSpawnerBlock extends BaseBlock {
/**
* Set the spawn delay.
- *
+ *
* @param delay the delay to set
*/
public void setDelay(short delay) {
this.delay = delay;
}
-
+
@Override
public boolean hasNbtData() {
return true;
@@ -208,7 +208,7 @@ public class MobSpawnerBlock extends BaseBlock {
this.spawnCount = spawnCountTag.getValue();
}
if (spawnRangeTag != null) {
- this.spawnRange =spawnRangeTag.getValue();
+ this.spawnRange = spawnRangeTag.getValue();
}
if (minSpawnDelayTag != null) {
this.minSpawnDelay = minSpawnDelayTag.getValue();
diff --git a/worldedit-core/src/main/assembly/default.xml b/worldedit-core/src/main/assembly/default.xml
deleted file mode 100644
index e6c1849ab..000000000
--- a/worldedit-core/src/main/assembly/default.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
- false
-
- tar.gz
- tar.bz2
- zip
-
-
-
-
- WorldEdit.jar
- /
- false
-
-
-
- /
- true
-
-
-
-
-
- LICENSE.txt
- CHANGELOG.txt
- contrib/craftscripts/*
-
-
-
-
diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java
index df3b0806b..5263d3aba 100644
--- a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java
+++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java
@@ -60,6 +60,7 @@ import java.util.Set;
* @param command sender class
*/
@SuppressWarnings("ProtectedField")
+@Deprecated
public abstract class CommandsManager {
protected static final Logger logger =
diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/package-info.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/package-info.java
new file mode 100644
index 000000000..8dd9c94ff
--- /dev/null
+++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * This package contains the old command system. It is no longer in use. Please switch
+ * to Piston, Intake, ACF, or similar systems.
+ */
+package com.sk89q.minecraft.util.commands;
\ No newline at end of file
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java
index bf26a0a1f..43843e8a3 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java
@@ -122,7 +122,6 @@ import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
@@ -175,15 +174,6 @@ public class EditSession implements Extent, AutoCloseable {
public String getDisplayName() {
return this.displayName;
}
-
- public static Optional getFromDisplayName(String name) {
- for (ReorderMode mode : values()) {
- if (mode.getDisplayName().equalsIgnoreCase(name)) {
- return Optional.of(mode);
- }
- }
- return Optional.empty();
- }
}
@SuppressWarnings("ProtectedField")
@@ -914,16 +904,15 @@ public class EditSession implements Extent, AutoCloseable {
* Remove blocks of a certain type nearby a given position.
*
* @param position center position of cuboid
- * @param blockType the block type to match
+ * @param mask the mask to match
* @param apothem an apothem of the cuboid, where the minimum is 1
* @return number of blocks affected
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
- public int removeNear(BlockVector3 position, BlockType blockType, int apothem) throws MaxChangedBlocksException {
+ public int removeNear(BlockVector3 position, Mask mask, int apothem) throws MaxChangedBlocksException {
checkNotNull(position);
checkArgument(apothem >= 1, "apothem >= 1");
- Mask mask = new BlockTypeMask(this, blockType);
BlockVector3 adjustment = BlockVector3.ONE.multiply(apothem - 1);
Region region = new CuboidRegion(
getWorld(), // Causes clamping of Y range
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java
index bf15a504a..b0c1ebd45 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java
@@ -52,6 +52,7 @@ import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.snapshot.Snapshot;
import javax.annotation.Nullable;
+import java.time.ZoneId;
import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedList;
@@ -91,7 +92,7 @@ public class LocalSession {
private transient int cuiVersion = -1;
private transient boolean fastMode = false;
private transient Mask mask;
- private transient TimeZone timezone = TimeZone.getDefault();
+ private transient ZoneId timezone = ZoneId.systemDefault();
private transient BlockVector3 cuiTemporaryBlock;
private transient EditSession.ReorderMode reorderMode = EditSession.ReorderMode.MULTI_STAGE;
@@ -169,7 +170,7 @@ public class LocalSession {
*
* @return the timezone
*/
- public TimeZone getTimeZone() {
+ public ZoneId getTimeZone() {
return timezone;
}
@@ -178,7 +179,7 @@ public class LocalSession {
*
* @param timezone the user's timezone
*/
- public void setTimezone(TimeZone timezone) {
+ public void setTimezone(ZoneId timezone) {
checkNotNull(timezone);
this.timezone = timezone;
}
@@ -849,9 +850,10 @@ public class LocalSession {
public Calendar detectDate(String input) {
checkNotNull(input);
- Time.setTimeZone(getTimeZone());
+ TimeZone tz = TimeZone.getTimeZone(getTimeZone());
+ Time.setTimeZone(tz);
Options opt = new com.sk89q.jchronic.Options();
- opt.setNow(Calendar.getInstance(getTimeZone()));
+ opt.setNow(Calendar.getInstance(tz));
Span date = Chronic.parse(input, opt);
if (date == null) {
return null;
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java
index e206f383f..205cfde5f 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java
@@ -303,6 +303,17 @@ public final class WorldEdit {
if (exts.size() != 1) {
exts = exts.subList(0, 1);
}
+ } else {
+ int dot = filename.lastIndexOf('.');
+ if (dot < 0 || dot == filename.length() - 1) {
+ String currentExt = filename.substring(dot + 1);
+ if (exts.contains(currentExt) && checkFilename(filename)) {
+ File f = new File(dir, filename);
+ if (f.exists()) {
+ return f;
+ }
+ }
+ }
}
File result = null;
for (Iterator iter = exts.iterator(); iter.hasNext() && (result == null || (!isSave && !result.exists()));) {
@@ -317,7 +328,7 @@ public final class WorldEdit {
private File getSafeFileWithExtension(File dir, String filename, String extension) {
if (extension != null) {
int dot = filename.lastIndexOf('.');
- if (dot < 0 || !filename.substring(dot).equalsIgnoreCase(extension)) {
+ if (dot < 0 || dot == filename.length() - 1 || !filename.substring(dot + 1).equalsIgnoreCase(extension)) {
filename += "." + extension;
}
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java
new file mode 100644
index 000000000..f9ceadd3e
--- /dev/null
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java
@@ -0,0 +1,133 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.command;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.sk89q.worldedit.LocalSession;
+import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.blocks.BaseItem;
+import com.sk89q.worldedit.command.factory.ItemUseFactory;
+import com.sk89q.worldedit.command.factory.ReplaceFactory;
+import com.sk89q.worldedit.command.factory.TreeGeneratorFactory;
+import com.sk89q.worldedit.command.util.PermissionCondition;
+import com.sk89q.worldedit.entity.Player;
+import com.sk89q.worldedit.function.Contextual;
+import com.sk89q.worldedit.function.RegionFunction;
+import com.sk89q.worldedit.function.factory.Apply;
+import com.sk89q.worldedit.function.pattern.Pattern;
+import com.sk89q.worldedit.regions.factory.RegionFactory;
+import com.sk89q.worldedit.util.TreeGenerator;
+import com.sk89q.worldedit.internal.command.CommandRegistrationHandler;
+import com.sk89q.worldedit.util.formatting.text.TextComponent;
+import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
+import org.enginehub.piston.CommandManager;
+import org.enginehub.piston.CommandParameters;
+import org.enginehub.piston.DefaultCommandManagerService;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
+import org.enginehub.piston.inject.Key;
+import org.enginehub.piston.part.CommandArgument;
+import org.enginehub.piston.part.SubCommandPart;
+
+import java.util.stream.Collectors;
+
+import static java.util.Objects.requireNonNull;
+import static org.enginehub.piston.part.CommandParts.arg;
+
+@CommandContainer
+public class ApplyBrushCommands {
+
+ private static final CommandArgument REGION_FACTORY = arg(TranslatableComponent.of("shape"), TextComponent.of("The shape of the region"))
+ .defaultsTo(ImmutableList.of())
+ .ofTypes(ImmutableList.of(Key.of(RegionFactory.class)))
+ .build();
+
+ private static final CommandArgument RADIUS = arg(TranslatableComponent.of("radius"), TextComponent.of("The size of the brush"))
+ .defaultsTo(ImmutableList.of("5"))
+ .ofTypes(ImmutableList.of(Key.of(double.class)))
+ .build();
+
+ public static void register(CommandManager commandManager, CommandRegistrationHandler registration) {
+ commandManager.register("apply", builder -> {
+ builder.description(TextComponent.of("Apply brush, apply a function to every block"));
+ builder.action(org.enginehub.piston.Command.Action.NULL_ACTION);
+
+ CommandManager manager = DefaultCommandManagerService.getInstance()
+ .newCommandManager();
+ registration.register(
+ manager,
+ ApplyBrushCommandsRegistration.builder(),
+ new ApplyBrushCommands()
+ );
+
+ builder.condition(new PermissionCondition(ImmutableSet.of("worldedit.brush.apply")));
+
+ builder.addParts(REGION_FACTORY, RADIUS);
+ builder.addPart(SubCommandPart.builder(TranslatableComponent.of("type"), TextComponent.of("Type of brush to use"))
+ .withCommands(manager.getAllCommands().collect(Collectors.toList()))
+ .required()
+ .build());
+ });
+ }
+
+ private void setApplyBrush(CommandParameters parameters, Player player, LocalSession localSession,
+ Contextual extends RegionFunction> generatorFactory) throws WorldEditException {
+ double radius = requireNonNull(RADIUS.value(parameters).asSingle(double.class));
+ RegionFactory regionFactory = REGION_FACTORY.value(parameters).asSingle(RegionFactory.class);
+ BrushCommands.setOperationBasedBrush(player, localSession, radius,
+ new Apply(generatorFactory), regionFactory, "worldedit.brush.apply");
+ }
+
+ @Command(
+ name = "forest",
+ desc = "Plant trees"
+ )
+ public void forest(CommandParameters parameters,
+ Player player, LocalSession localSession,
+ @Arg(desc = "The type of tree to plant")
+ TreeGenerator.TreeType type) throws WorldEditException {
+ setApplyBrush(parameters, player, localSession, new TreeGeneratorFactory(type));
+ }
+
+ @Command(
+ name = "item",
+ desc = "Use an item"
+ )
+ public void item(CommandParameters parameters,
+ Player player, LocalSession localSession,
+ @Arg(desc = "The type of item to use")
+ BaseItem item) throws WorldEditException {
+ setApplyBrush(parameters, player, localSession, new ItemUseFactory(item));
+ }
+
+ @Command(
+ name = "set",
+ desc = "Place a block"
+ )
+ public void set(CommandParameters parameters,
+ Player player, LocalSession localSession,
+ @Arg(desc = "The pattern of blocks to use")
+ Pattern pattern) throws WorldEditException {
+ setApplyBrush(parameters, player, localSession, new ReplaceFactory(pattern));
+ }
+
+}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java
index f3d9e9694..ef6e38981 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java
@@ -19,17 +19,13 @@
package com.sk89q.worldedit.command;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION;
-
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandContext;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
-import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
+import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.function.FlatRegionFunction;
@@ -46,93 +42,71 @@ import com.sk89q.worldedit.regions.FlatRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.Regions;
import com.sk89q.worldedit.util.Location;
-import com.sk89q.worldedit.util.command.binding.Switch;
+import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeData;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
+import org.enginehub.piston.annotation.param.Switch;
-import java.util.Collection;
import java.util.HashSet;
+import java.util.Objects;
import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
/**
* Implements biome-related commands such as "/biomelist".
*/
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class BiomeCommands {
- private final WorldEdit worldEdit;
-
/**
* Create a new instance.
- *
- * @param worldEdit reference to WorldEdit
*/
- public BiomeCommands(WorldEdit worldEdit) {
- checkNotNull(worldEdit);
- this.worldEdit = worldEdit;
+ public BiomeCommands() {
}
@Command(
- aliases = { "biomelist", "biomels" },
- usage = "[page]",
- desc = "Gets all biomes available.",
- max = 1
+ name = "biomelist",
+ aliases = { "biomels" },
+ desc = "Gets all biomes available."
)
@CommandPermissions("worldedit.biome.list")
- public void biomeList(Player player, CommandContext args) throws WorldEditException {
- int page;
- int offset;
- int count = 0;
-
- if (args.argsLength() == 0 || (page = args.getInteger(0)) < 2) {
- page = 1;
- offset = 0;
- } else {
- offset = (page - 1) * 19;
- }
-
+ public void biomeList(Player player,
+ @Arg(desc = "Page number.", def = "1")
+ int page) throws WorldEditException {
BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry();
- Collection biomes = BiomeType.REGISTRY.values();
- int totalPages = biomes.size() / 19 + 1;
- player.print("Available Biomes (page " + page + "/" + totalPages + ") :");
- for (BiomeType biome : biomes) {
- if (offset > 0) {
- offset--;
- } else {
- BiomeData data = biomeRegistry.getData(biome);
- if (data != null) {
- player.print(" " + data.getName());
- if (++count == 19) {
- break;
- }
- } else {
- player.print(" ");
- }
- }
- }
+
+ PaginationBox paginationBox = PaginationBox.fromStrings("Available Biomes", "/biomelist %page%",
+ BiomeType.REGISTRY.values().stream()
+ .map(biomeRegistry::getData).filter(Objects::nonNull)
+ .map(BiomeData::getName).collect(Collectors.toList()));
+ player.print(paginationBox.create(page));
}
@Command(
- aliases = { "biomeinfo" },
- flags = "pt",
+ name = "biomeinfo",
desc = "Get the biome of the targeted block.",
- help =
- "Get the biome of the block.\n" +
- "By default use all the blocks contained in your selection.\n" +
- "-t use the block you are looking at.\n" +
- "-p use the block you are currently in",
- max = 0
+ descFooter = "By default, uses all blocks in your selection."
)
@CommandPermissions("worldedit.biome.info")
- public void biomeInfo(Player player, LocalSession session, CommandContext args) throws WorldEditException {
+ public void biomeInfo(Player player, LocalSession session,
+ @Switch(name = 't', desc = "Use the block you are looking at.")
+ boolean useLineOfSight,
+ @Switch(name = 'p', desc = "Use the block you are currently in.")
+ boolean usePosition) throws WorldEditException {
BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry();
Set biomes = new HashSet<>();
String qualifier;
- if (args.hasFlag('t')) {
+ if (useLineOfSight) {
Location blockPosition = player.getBlockTrace(300);
if (blockPosition == null) {
player.printError("No block in sight!");
@@ -143,7 +117,7 @@ public class BiomeCommands {
biomes.add(biome);
qualifier = "at line of sight point";
- } else if (args.hasFlag('p')) {
+ } else if (usePosition) {
BiomeType biome = player.getWorld().getBiome(player.getLocation().toVector().toBlockPoint().toBlockVector2());
biomes.add(biome);
@@ -177,18 +151,16 @@ public class BiomeCommands {
}
@Command(
- aliases = { "/setbiome" },
- usage = "",
- flags = "p",
- desc = "Sets the biome of the player's current block or region.",
- help =
- "Set the biome of the region.\n" +
- "By default use all the blocks contained in your selection.\n" +
- "-p use the block you are currently in"
+ name = "/setbiome",
+ desc = "Sets the biome of your current block or region.",
+ descFooter = "By default, uses all the blocks in your selection"
)
@Logging(REGION)
@CommandPermissions("worldedit.biome.set")
- public void setBiome(Player player, LocalSession session, EditSession editSession, BiomeType target, @Switch('p') boolean atPosition) throws WorldEditException {
+ public void setBiome(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "Biome type.") BiomeType target,
+ @Switch(name = 'p', desc = "Use your current position")
+ boolean atPosition) throws WorldEditException {
World world = player.getWorld();
Region region;
Mask mask = editSession.getMask();
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java
index 450bf5f51..b6433a206 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java
@@ -19,15 +19,12 @@
package com.sk89q.worldedit.command;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandContext;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.command.factory.ReplaceFactory;
+import com.sk89q.worldedit.command.factory.TreeGeneratorFactory;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.brush.ButcherBrush;
import com.sk89q.worldedit.command.tool.brush.ClipboardBrush;
@@ -35,26 +32,42 @@ import com.sk89q.worldedit.command.tool.brush.CylinderBrush;
import com.sk89q.worldedit.command.tool.brush.GravityBrush;
import com.sk89q.worldedit.command.tool.brush.HollowCylinderBrush;
import com.sk89q.worldedit.command.tool.brush.HollowSphereBrush;
+import com.sk89q.worldedit.command.tool.brush.OperationFactoryBrush;
import com.sk89q.worldedit.command.tool.brush.SmoothBrush;
import com.sk89q.worldedit.command.tool.brush.SphereBrush;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.CreatureButcher;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
+import com.sk89q.worldedit.function.Contextual;
+import com.sk89q.worldedit.function.factory.Apply;
+import com.sk89q.worldedit.function.factory.Deform;
+import com.sk89q.worldedit.function.factory.Paint;
import com.sk89q.worldedit.function.mask.BlockTypeMask;
import com.sk89q.worldedit.function.mask.Mask;
+import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
+import com.sk89q.worldedit.regions.factory.RegionFactory;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.session.request.RequestExtent;
import com.sk89q.worldedit.util.HandSide;
-import com.sk89q.worldedit.util.command.binding.Switch;
-import com.sk89q.worldedit.util.command.parametric.Optional;
+import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.block.BlockTypes;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
+import org.enginehub.piston.annotation.param.ArgFlag;
+import org.enginehub.piston.annotation.param.Switch;
+
+import static com.google.common.base.Preconditions.checkNotNull;
/**
* Commands to set brush shape.
*/
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class BrushCommands {
private final WorldEdit worldEdit;
@@ -70,19 +83,18 @@ public class BrushCommands {
}
@Command(
- aliases = { "sphere", "s" },
- usage = " [radius]",
- flags = "h",
- desc = "Choose the sphere brush",
- help =
- "Chooses the sphere brush.\n" +
- "The -h flag creates hollow spheres instead.",
- min = 1,
- max = 2
+ name = "sphere",
+ aliases = { "s" },
+ desc = "Choose the sphere brush"
)
@CommandPermissions("worldedit.brush.sphere")
- public void sphereBrush(Player player, LocalSession session, Pattern fill,
- @Optional("2") double radius, @Switch('h') boolean hollow) throws WorldEditException {
+ public void sphereBrush(Player player, LocalSession session,
+ @Arg(desc = "The pattern of blocks to set")
+ Pattern fill,
+ @Arg(desc = "The radius of the sphere", def = "2")
+ double radius,
+ @Switch(name = 'h', desc = "Create hollow spheres instead")
+ boolean hollow) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType());
@@ -99,19 +111,20 @@ public class BrushCommands {
}
@Command(
- aliases = { "cylinder", "cyl", "c" },
- usage = " [radius] [height]",
- flags = "h",
- desc = "Choose the cylinder brush",
- help =
- "Chooses the cylinder brush.\n" +
- "The -h flag creates hollow cylinders instead.",
- min = 1,
- max = 3
+ name = "cylinder",
+ aliases = { "cyl", "c" },
+ desc = "Choose the cylinder brush"
)
@CommandPermissions("worldedit.brush.cylinder")
- public void cylinderBrush(Player player, LocalSession session, Pattern fill,
- @Optional("2") double radius, @Optional("1") int height, @Switch('h') boolean hollow) throws WorldEditException {
+ public void cylinderBrush(Player player, LocalSession session,
+ @Arg(desc = "The pattern of blocks to set")
+ Pattern fill,
+ @Arg(desc = "The radius of the cylinder", def = "2")
+ double radius,
+ @Arg(desc = "The height of the cylinder", def = "1")
+ int height,
+ @Switch(name = 'h', desc = "Create hollow cylinders instead")
+ boolean hollow) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
worldEdit.checkMaxBrushRadius(height);
@@ -129,20 +142,22 @@ public class BrushCommands {
}
@Command(
- aliases = { "clipboard", "copy" },
- usage = "",
- flags = "aoebm",
- desc = "Choose the clipboard brush",
- help =
- "Chooses the clipboard brush.\n" +
- "The -a flag makes it not paste air.\n" +
- "Without the -p flag, the paste will appear centered at the target location. " +
- "With the flag, then the paste will appear relative to where you had " +
- "stood relative to the copied area when you copied it."
+ name = "clipboard",
+ aliases = { "copy" },
+ desc = "Choose the clipboard brush"
)
@CommandPermissions("worldedit.brush.clipboard")
- public void clipboardBrush(Player player, LocalSession session, @Switch('a') boolean ignoreAir, @Switch('o') boolean usingOrigin,
- @Switch('e') boolean pasteEntities, @Switch('b') boolean pasteBiomes, @Switch('m') Mask sourceMask) throws WorldEditException {
+ public void clipboardBrush(Player player, LocalSession session,
+ @Switch(name = 'a', desc = "Don't paste air from the clipboard")
+ boolean ignoreAir,
+ @Switch(name = 'o', desc = "Paste using clipboard origin, instead of being centered at the target location")
+ boolean usingOrigin,
+ @Switch(name = 'e', desc = "Paste entities if available")
+ boolean pasteEntities,
+ @Switch(name = 'b', desc = "Paste biomes if available")
+ boolean pasteBiomes,
+ @ArgFlag(name = 'm', desc = "Skip blocks matching this mask in the clipboard", def = "")
+ Mask sourceMask) throws WorldEditException {
ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard();
@@ -159,18 +174,18 @@ public class BrushCommands {
}
@Command(
- aliases = { "smooth" },
- usage = "[size] [iterations] [filter]",
+ name = "smooth",
desc = "Choose the terrain softener brush",
- help =
- "Chooses the terrain softener brush. Optionally, specify a mask of blocks to be used for the heightmap.\n" +
- "For example, '/brush smooth 2 4 grass_block,dirt,stone'.",
- min = 0,
- max = 3
+ descFooter = "Example: '/brush smooth 2 4 grass_block,dirt,stone'"
)
@CommandPermissions("worldedit.brush.smooth")
public void smoothBrush(Player player, LocalSession session,
- @Optional("2") double radius, @Optional("4") int iterations, @Optional Mask mask) throws WorldEditException {
+ @Arg(desc = "The radius to sample for softening", def = "2")
+ double radius,
+ @Arg(desc = "The number of iterations to perform", def = "4")
+ int iterations,
+ @Arg(desc = "The mask of blocks to use for the heightmap", def = "")
+ Mask mask) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType());
@@ -181,14 +196,14 @@ public class BrushCommands {
}
@Command(
- aliases = { "ex", "extinguish" },
- usage = "[radius]",
- desc = "Shortcut fire extinguisher brush",
- min = 0,
- max = 1
+ name = "extinguish",
+ aliases = { "ex" },
+ desc = "Shortcut fire extinguisher brush"
)
@CommandPermissions("worldedit.brush.ex")
- public void extinguishBrush(Player player, LocalSession session, @Optional("5") double radius) throws WorldEditException {
+ public void extinguishBrush(Player player, LocalSession session,
+ @Arg(desc = "The radius to extinguish", def = "5")
+ double radius) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType());
@@ -202,19 +217,16 @@ public class BrushCommands {
}
@Command(
- aliases = { "gravity", "grav" },
- usage = "[radius]",
- flags = "h",
- desc = "Gravity brush",
- help =
- "This brush simulates the affect of gravity.\n" +
- "The -h flag makes it affect blocks starting at the world's max y, " +
- "instead of the clicked block's y + radius.",
- min = 0,
- max = 1
+ name = "gravity",
+ aliases = { "grav" },
+ desc = "Gravity brush, simulates the effect of gravity"
)
@CommandPermissions("worldedit.brush.gravity")
- public void gravityBrush(Player player, LocalSession session, @Optional("5") double radius, @Switch('h') boolean fromMaxY) throws WorldEditException {
+ public void gravityBrush(Player player, LocalSession session,
+ @Arg(desc = "The radius to apply gravity in", def = "5")
+ double radius,
+ @Switch(name = 'h', desc = "Affect blocks starting at max Y, rather than the target location Y + radius")
+ boolean fromMaxY) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType());
@@ -224,31 +236,34 @@ public class BrushCommands {
player.print(String.format("Gravity brush equipped (%.0f).",
radius));
}
-
+
@Command(
- aliases = { "butcher", "kill" },
- usage = "[radius]",
- flags = "plangbtfr",
- desc = "Butcher brush",
- help = "Kills nearby mobs within the specified radius.\n" +
- "Flags:\n" +
- " -p also kills pets.\n" +
- " -n also kills NPCs.\n" +
- " -g also kills Golems.\n" +
- " -a also kills animals.\n" +
- " -b also kills ambient mobs.\n" +
- " -t also kills mobs with name tags.\n" +
- " -f compounds all previous flags.\n" +
- " -r also destroys armor stands.\n" +
- " -l currently does nothing.",
- min = 0,
- max = 1
+ name = "butcher",
+ aliases = { "kill" },
+ desc = "Butcher brush, kills mobs within a radius"
)
@CommandPermissions("worldedit.brush.butcher")
- public void butcherBrush(Player player, LocalSession session, CommandContext args) throws WorldEditException {
+ public void butcherBrush(Player player, LocalSession session,
+ @Arg(desc = "Radius to kill mobs in", def = "5")
+ double radius,
+ @Switch(name = 'p', desc = "Also kill pets")
+ boolean killPets,
+ @Switch(name = 'n', desc = "Also kill NPCs")
+ boolean killNpcs,
+ @Switch(name = 'g', desc = "Also kill golems")
+ boolean killGolems,
+ @Switch(name = 'a', desc = "Also kill animals")
+ boolean killAnimals,
+ @Switch(name = 'b', desc = "Also kill ambient mobs")
+ boolean killAmbient,
+ @Switch(name = 't', desc = "Also kill mobs with name tags")
+ boolean killWithName,
+ @Switch(name = 'f', desc = "Also kill all friendly mobs (Applies the flags `-abgnpt`)")
+ boolean killFriendly,
+ @Switch(name = 'r', desc = "Also destroy armor stands")
+ boolean killArmorStands) throws WorldEditException {
LocalConfiguration config = worldEdit.getConfiguration();
- double radius = args.argsLength() > 0 ? args.getDouble(0) : 5;
double maxRadius = config.maxBrushRadius;
// hmmmm not horribly worried about this because -1 is still rather efficient,
// the problem arises when butcherMaxRadius is some really high number but not infinite
@@ -262,7 +277,14 @@ public class BrushCommands {
}
CreatureButcher flags = new CreatureButcher(player);
- flags.fromCommand(args);
+ flags.or(CreatureButcher.Flags.FRIENDLY , killFriendly); // No permission check here. Flags will instead be filtered by the subsequent calls.
+ flags.or(CreatureButcher.Flags.PETS , killPets, "worldedit.butcher.pets");
+ flags.or(CreatureButcher.Flags.NPCS , killNpcs, "worldedit.butcher.npcs");
+ flags.or(CreatureButcher.Flags.GOLEMS , killGolems, "worldedit.butcher.golems");
+ flags.or(CreatureButcher.Flags.ANIMALS , killAnimals, "worldedit.butcher.animals");
+ flags.or(CreatureButcher.Flags.AMBIENT , killAmbient, "worldedit.butcher.ambient");
+ flags.or(CreatureButcher.Flags.TAGGED , killWithName, "worldedit.butcher.tagged");
+ flags.or(CreatureButcher.Flags.ARMOR_STAND , killArmorStands, "worldedit.butcher.armorstands");
BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType());
tool.setSize(radius);
@@ -270,4 +292,106 @@ public class BrushCommands {
player.print(String.format("Butcher brush equipped (%.0f).", radius));
}
+
+ @Command(
+ name = "deform",
+ desc = "Deform brush, applies an expression to an area"
+ )
+ @CommandPermissions("worldedit.brush.deform")
+ public void deform(Player player, LocalSession localSession,
+ @Arg(desc = "The shape of the region")
+ RegionFactory shape,
+ @Arg(desc = "The size of the brush", def = "5")
+ double radius,
+ @Arg(desc = "Expression to apply", def = "y-=0.2")
+ String expression,
+ @Switch(name = 'r', desc = "Use the game's coordinate origin")
+ boolean useRawCoords,
+ @Switch(name = 'o', desc = "Use the placement position as the origin")
+ boolean usePlacement) throws WorldEditException {
+ Deform deform = new Deform(expression);
+ if (useRawCoords) {
+ deform.setMode(Deform.Mode.RAW_COORD);
+ } else if (usePlacement) {
+ deform.setMode(Deform.Mode.OFFSET);
+ deform.setOffset(localSession.getPlacementPosition(player).toVector3());
+ }
+ setOperationBasedBrush(player, localSession, radius,
+ deform, shape, "worldedit.brush.deform");
+ }
+
+ @Command(
+ name = "set",
+ desc = "Set brush, sets all blocks in the area"
+ )
+ @CommandPermissions("worldedit.brush.set")
+ public void set(Player player, LocalSession localSession,
+ @Arg(desc = "The shape of the region")
+ RegionFactory shape,
+ @Arg(desc = "The size of the brush", def = "5")
+ double radius,
+ @Arg(desc = "The pattern of blocks to set")
+ Pattern pattern) throws WorldEditException {
+ setOperationBasedBrush(player, localSession, radius,
+ new Apply(new ReplaceFactory(pattern)), shape, "worldedit.brush.set");
+ }
+
+ @Command(
+ name = "forest",
+ desc = "Forest brush, creates a forest in the area"
+ )
+ @CommandPermissions("worldedit.brush.forest")
+ public void forest(Player player, LocalSession localSession,
+ @Arg(desc = "The shape of the region")
+ RegionFactory shape,
+ @Arg(desc = "The size of the brush", def = "5")
+ double radius,
+ @Arg(desc = "The density of the brush", def = "20")
+ double density,
+ @Arg(desc = "The type of tree to use")
+ TreeGenerator.TreeType type) throws WorldEditException {
+ setOperationBasedBrush(player, localSession, radius,
+ new Paint(new TreeGeneratorFactory(type), density / 100), shape, "worldedit.brush.forest");
+ }
+
+ @Command(
+ name = "raise",
+ desc = "Raise brush, raise all blocks by one"
+ )
+ @CommandPermissions("worldedit.brush.raise")
+ public void raise(Player player, LocalSession localSession,
+ @Arg(desc = "The shape of the region")
+ RegionFactory shape,
+ @Arg(desc = "The size of the brush", def = "5")
+ double radius) throws WorldEditException {
+ setOperationBasedBrush(player, localSession, radius,
+ new Deform("y-=1"), shape, "worldedit.brush.raise");
+ }
+
+ @Command(
+ name = "lower",
+ desc = "Lower brush, lower all blocks by one"
+ )
+ @CommandPermissions("worldedit.brush.lower")
+ public void lower(Player player, LocalSession localSession,
+ @Arg(desc = "The shape of the region")
+ RegionFactory shape,
+ @Arg(desc = "The size of the brush", def = "5")
+ double radius) throws WorldEditException {
+ setOperationBasedBrush(player, localSession, radius,
+ new Deform("y+=1"), shape, "worldedit.brush.lower");
+ }
+
+ static void setOperationBasedBrush(Player player, LocalSession session, double radius,
+ Contextual extends Operation> factory,
+ RegionFactory shape,
+ String permission) throws WorldEditException {
+ WorldEdit.getInstance().checkMaxBrushRadius(radius);
+ BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType());
+ tool.setSize(radius);
+ tool.setFill(null);
+ tool.setBrush(new OperationFactoryBrush(factory, shape, session), permission);
+
+ player.print("Set brush to " + factory);
+ }
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java
index 30d99269d..8dc99dc15 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java
@@ -20,49 +20,51 @@
package com.sk89q.worldedit.command;
import static com.google.common.base.Preconditions.checkNotNull;
-import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION;
+import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
-import com.sk89q.minecraft.util.commands.Logging;
-import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
+import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.MathUtils;
import com.sk89q.worldedit.util.Location;
+import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.world.storage.LegacyChunkStore;
import com.sk89q.worldedit.world.storage.McRegionChunkStore;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Set;
+import java.util.stream.Collectors;
/**
* Commands for working with chunks.
*/
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ChunkCommands {
private final WorldEdit worldEdit;
-
+
public ChunkCommands(WorldEdit worldEdit) {
checkNotNull(worldEdit);
this.worldEdit = worldEdit;
}
@Command(
- aliases = { "chunkinfo" },
- usage = "",
- desc = "Get information about the chunk that you are inside",
- min = 0,
- max = 0
+ name = "chunkinfo",
+ desc = "Get information about the chunk you're inside"
)
@CommandPermissions("worldedit.chunkinfo")
- public void chunkInfo(Player player) throws WorldEditException {
+ public void chunkInfo(Player player) {
Location pos = player.getBlockIn();
int chunkX = (int) Math.floor(pos.getBlockX() / 16.0);
int chunkZ = (int) Math.floor(pos.getBlockZ() / 16.0);
@@ -79,27 +81,22 @@ public class ChunkCommands {
}
@Command(
- aliases = { "listchunks" },
- usage = "",
- desc = "List chunks that your selection includes",
- min = 0,
- max = 0
+ name = "listchunks",
+ desc = "List chunks that your selection includes"
)
@CommandPermissions("worldedit.listchunks")
- public void listChunks(Player player, LocalSession session) throws WorldEditException {
+ public void listChunks(Player player, LocalSession session,
+ @Arg(desc = "Page number.", def = "1") int page) throws WorldEditException {
Set chunks = session.getSelection(player.getWorld()).getChunks();
- for (BlockVector2 chunk : chunks) {
- player.print(LegacyChunkStore.getFilename(chunk));
- }
+ PaginationBox paginationBox = PaginationBox.fromStrings("Selected Chunks", "/listchunks %page%",
+ chunks.stream().map(BlockVector2::toString).collect(Collectors.toList()));
+ player.print(paginationBox.create(page));
}
@Command(
- aliases = { "delchunks" },
- usage = "",
- desc = "Delete chunks that your selection includes",
- min = 0,
- max = 0
+ name = "delchunks",
+ desc = "Delete chunks that your selection includes"
)
@CommandPermissions("worldedit.delchunks")
@Logging(REGION)
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java
index 7c242011f..01d1a1fb9 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java
@@ -19,18 +19,13 @@
package com.sk89q.worldedit.command;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT;
-import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION;
-
import com.google.common.collect.Lists;
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
-import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
-import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
+import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
@@ -49,46 +44,42 @@ import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.session.ClipboardHolder;
-import com.sk89q.worldedit.session.PasteBuilder;
-import com.sk89q.worldedit.util.command.binding.Switch;
-import com.sk89q.worldedit.util.command.parametric.Optional;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
+import org.enginehub.piston.annotation.param.ArgFlag;
+import org.enginehub.piston.annotation.param.Switch;
import java.util.List;
+import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT;
+import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
+
/**
* Clipboard commands.
*/
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ClipboardCommands {
- private final WorldEdit worldEdit;
-
/**
* Create a new instance.
- *
- * @param worldEdit reference to WorldEdit
*/
- public ClipboardCommands(WorldEdit worldEdit) {
- checkNotNull(worldEdit);
- this.worldEdit = worldEdit;
+ public ClipboardCommands() {
}
@Command(
- aliases = { "/copy" },
- flags = "em",
- desc = "Copy the selection to the clipboard",
- help = "Copy the selection to the clipboard\n" +
- "Flags:\n" +
- " -e will also copy entities\n" +
- " -b will also copy biomes\n" +
- " -m sets a source mask so that excluded blocks become air",
- min = 0,
- max = 0
+ name = "/copy",
+ desc = "Copy the selection to the clipboard"
)
@CommandPermissions("worldedit.clipboard.copy")
public void copy(Player player, LocalSession session, EditSession editSession,
- @Selection Region region, @Switch('e') boolean copyEntities,
- @Switch('m') Mask mask, @Switch('b') boolean copyBiomes) throws WorldEditException {
-
+ @Selection Region region,
+ @Switch(name = 'e', desc = "Also copy entities")
+ boolean copyEntities,
+ @Switch(name = 'b', desc = "Also copy biomes")
+ boolean copyBiomes,
+ @ArgFlag(name = 'm', desc = "Set the exclude mask, matching blocks become air", def = "")
+ Mask mask) throws WorldEditException {
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
clipboard.setOrigin(session.getPlacementPosition(player));
ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint());
@@ -106,24 +97,22 @@ public class ClipboardCommands {
}
@Command(
- aliases = { "/cut" },
- flags = "em",
- usage = "[leave-pattern]",
+ name = "/cut",
desc = "Cut the selection to the clipboard",
- help = "Copy the selection to the clipboard\n" +
- "The space will be filled with the leave pattern if specified, otherwise air." +
- "Flags:\n" +
- " -e will also cut entities\n" +
- " -b will also copy biomes (source biomes unaffected)\n" +
- " -m sets a source mask so that excluded blocks become air\n" +
- "WARNING: Cutting and pasting entities cannot yet be undone!",
- max = 1
+ descFooter = "WARNING: Cutting and pasting entities cannot be undone!"
)
@CommandPermissions("worldedit.clipboard.cut")
@Logging(REGION)
public void cut(Player player, LocalSession session, EditSession editSession,
- @Selection Region region, @Optional("air") Pattern leavePattern, @Switch('e') boolean copyEntities,
- @Switch('m') Mask mask, @Switch('b') boolean copyBiomes) throws WorldEditException {
+ @Selection Region region,
+ @Arg(desc = "Pattern to leave in place of the selection", def = "air")
+ Pattern leavePattern,
+ @Switch(name = 'e', desc = "Also cut entities")
+ boolean copyEntities,
+ @Switch(name = 'b', desc = "Also copy biomes, source biomes are unaffected")
+ boolean copyBiomes,
+ @ArgFlag(name = 'm', desc = "Set the exclude mask, matching blocks become air", def = "")
+ Mask mask) throws WorldEditException {
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
clipboard.setOrigin(session.getPlacementPosition(player));
@@ -144,26 +133,24 @@ public class ClipboardCommands {
}
@Command(
- aliases = { "/paste" },
- flags = "saobem:",
- desc = "Paste the clipboard's contents",
- help =
- "Pastes the clipboard's contents.\n" +
- "Flags:\n" +
- " -a skips air blocks\n" +
- " -b pastes biomes if available\n" +
- " -e pastes entities if available\n" +
- " -m [] skips matching blocks in the clipboard\n" +
- " -o pastes at the original position\n" +
- " -s selects the region after pasting\n",
- max = 0
+ name = "/paste",
+ desc = "Paste the clipboard's contents"
)
@CommandPermissions("worldedit.clipboard.paste")
@Logging(PLACEMENT)
public void paste(Player player, LocalSession session, EditSession editSession,
- @Switch('a') boolean ignoreAirBlocks, @Switch('o') boolean atOrigin,
- @Switch('s') boolean selectPasted, @Switch('e') boolean pasteEntities,
- @Switch('b') boolean pasteBiomes, @Switch('m') Mask sourceMask) throws WorldEditException {
+ @Switch(name = 'a', desc = "Skip air blocks")
+ boolean ignoreAirBlocks,
+ @Switch(name = 'o', desc = "Paste at the original position")
+ boolean atOrigin,
+ @Switch(name = 's', desc = "Select the region after pasting")
+ boolean selectPasted,
+ @Switch(name = 'e', desc = "Paste entities if available")
+ boolean pasteEntities,
+ @Switch(name = 'b', desc = "Paste biomes if available")
+ boolean pasteBiomes,
+ @ArgFlag(name = 'm', desc = "Skip blocks matching this mask", def = "")
+ Mask sourceMask) throws WorldEditException {
ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard();
@@ -197,42 +184,43 @@ public class ClipboardCommands {
}
@Command(
- aliases = { "/rotate" },
- usage = " [] []",
+ name = "/rotate",
desc = "Rotate the contents of the clipboard",
- help = "Non-destructively rotate the contents of the clipboard.\n" +
- "Angles are provided in degrees and a positive angle will result in a clockwise rotation. " +
- "Multiple rotations can be stacked. Interpolation is not performed so angles should be a multiple of 90 degrees.\n"
+ descFooter = "Non-destructively rotate the contents of the clipboard.\n" +
+ "Angles are provided in degrees and a positive angle will result in a clockwise rotation. " +
+ "Multiple rotations can be stacked. Interpolation is not performed so angles should be a multiple of 90 degrees.\n"
)
@CommandPermissions("worldedit.clipboard.rotate")
- public void rotate(Player player, LocalSession session, Double yRotate, @Optional Double xRotate, @Optional Double zRotate) throws WorldEditException {
- if ((yRotate != null && Math.abs(yRotate % 90) > 0.001) ||
- xRotate != null && Math.abs(xRotate % 90) > 0.001 ||
- zRotate != null && Math.abs(zRotate % 90) > 0.001) {
+ public void rotate(Player player, LocalSession session,
+ @Arg(desc = "Amount to rotate on the y-axis")
+ double yRotate,
+ @Arg(desc = "Amount to rotate on the x-axis", def = "0")
+ double xRotate,
+ @Arg(desc = "Amount to rotate on the z-axis", def = "0")
+ double zRotate) throws WorldEditException {
+ if (Math.abs(yRotate % 90) > 0.001 ||
+ Math.abs(xRotate % 90) > 0.001 ||
+ Math.abs(zRotate % 90) > 0.001) {
player.printDebug("Note: Interpolation is not yet supported, so angles that are multiples of 90 is recommended.");
}
ClipboardHolder holder = session.getClipboard();
AffineTransform transform = new AffineTransform();
- transform = transform.rotateY(-(yRotate != null ? yRotate : 0));
- transform = transform.rotateX(-(xRotate != null ? xRotate : 0));
- transform = transform.rotateZ(-(zRotate != null ? zRotate : 0));
+ transform = transform.rotateY(-yRotate);
+ transform = transform.rotateX(-xRotate);
+ transform = transform.rotateZ(-zRotate);
holder.setTransform(holder.getTransform().combine(transform));
player.print("The clipboard copy has been rotated.");
}
@Command(
- aliases = { "/flip" },
- usage = "[]",
- desc = "Flip the contents of the clipboard",
- help =
- "Flips the contents of the clipboard across the point from which the copy was made.\n",
- min = 0,
- max = 1
+ name = "/flip",
+ desc = "Flip the contents of the clipboard across the origin"
)
@CommandPermissions("worldedit.clipboard.flip")
public void flip(Player player, LocalSession session,
- @Optional(Direction.AIM) @Direction BlockVector3 direction) throws WorldEditException {
+ @Arg(desc = "The direction to flip, defaults to look direction.", def = Direction.AIM)
+ @Direction BlockVector3 direction) throws WorldEditException {
ClipboardHolder holder = session.getClipboard();
AffineTransform transform = new AffineTransform();
transform = transform.scale(direction.abs().multiply(-2).add(1, 1, 1).toVector3());
@@ -241,11 +229,8 @@ public class ClipboardCommands {
}
@Command(
- aliases = { "clearclipboard" },
- usage = "",
- desc = "Clear your clipboard",
- min = 0,
- max = 0
+ name = "clearclipboard",
+ desc = "Clear your clipboard"
)
@CommandPermissions("worldedit.clipboard.clear")
public void clearClipboard(Player player, LocalSession session) throws WorldEditException {
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java
index b05adf155..a84c3d1a0 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java
@@ -19,28 +19,31 @@
package com.sk89q.worldedit.command;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.common.collect.Sets;
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandContext;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.input.DisallowedUsageException;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.function.mask.Mask;
-import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
+import org.enginehub.piston.annotation.param.Switch;
+
+import static com.google.common.base.Preconditions.checkNotNull;
/**
* General WorldEdit commands.
*/
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class GeneralCommands {
private final WorldEdit worldEdit;
@@ -56,19 +59,18 @@ public class GeneralCommands {
}
@Command(
- aliases = { "/limit" },
- usage = "[limit]",
- desc = "Modify block change limit",
- min = 0,
- max = 1
+ name = "/limit",
+ desc = "Modify block change limit"
)
@CommandPermissions("worldedit.limit")
- public void limit(Player player, LocalSession session, CommandContext args) throws WorldEditException {
-
+ public void limit(Player player, LocalSession session,
+ @Arg(desc = "The limit to set", def = "")
+ Integer limit) throws WorldEditException {
+
LocalConfiguration config = worldEdit.getConfiguration();
boolean mayDisable = player.hasPermission("worldedit.limit.unrestricted");
- int limit = args.argsLength() == 0 ? config.defaultChangeLimit : Math.max(-1, args.getInteger(0));
+ limit = limit == null ? config.defaultChangeLimit : Math.max(-1, limit);
if (!mayDisable && config.maxChangeLimit > -1) {
if (limit > config.maxChangeLimit) {
player.printError("Your maximum allowable limit is " + config.maxChangeLimit + ".");
@@ -86,19 +88,18 @@ public class GeneralCommands {
}
@Command(
- aliases = { "/timeout" },
- usage = "[time]",
- desc = "Modify evaluation timeout time.",
- min = 0,
- max = 1
+ name = "/timeout",
+ desc = "Modify evaluation timeout time."
)
@CommandPermissions("worldedit.timeout")
- public void timeout(Player player, LocalSession session, CommandContext args) throws WorldEditException {
+ public void timeout(Player player, LocalSession session,
+ @Arg(desc = "The timeout time to set", def = "")
+ Integer limit) throws WorldEditException {
LocalConfiguration config = worldEdit.getConfiguration();
boolean mayDisable = player.hasPermission("worldedit.timeout.unrestricted");
- int limit = args.argsLength() == 0 ? config.calculationTimeout : Math.max(-1, args.getInteger(0));
+ limit = limit == null ? config.calculationTimeout : Math.max(-1, limit);
if (!mayDisable && config.maxCalculationTimeout > -1) {
if (limit > config.maxCalculationTimeout) {
player.printError("Your maximum allowable timeout is " + config.maxCalculationTimeout + " ms.");
@@ -116,89 +117,65 @@ public class GeneralCommands {
}
@Command(
- aliases = { "/fast" },
- usage = "[on|off]",
- desc = "Toggle fast mode",
- min = 0,
- max = 1
+ name = "/fast",
+ desc = "Toggle fast mode"
)
@CommandPermissions("worldedit.fast")
- public void fast(Player player, LocalSession session, CommandContext args) throws WorldEditException {
-
- String newState = args.getString(0, null);
- if (session.hasFastMode()) {
- if ("on".equals(newState)) {
- player.printError("Fast mode already enabled.");
- return;
- }
+ public void fast(Player player, LocalSession session,
+ @Arg(desc = "The new fast mode state", def = "")
+ Boolean fastMode) throws WorldEditException {
+ boolean hasFastMode = session.hasFastMode();
+ if (fastMode != null && fastMode == hasFastMode) {
+ player.printError("Fast mode already " + (fastMode ? "enabled" : "disabled") + ".");
+ return;
+ }
+ if (hasFastMode) {
session.setFastMode(false);
player.print("Fast mode disabled.");
} else {
- if ("off".equals(newState)) {
- player.printError("Fast mode already disabled.");
- return;
- }
-
session.setFastMode(true);
player.print("Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes.");
}
}
@Command(
- aliases = { "/reorder" },
- usage = "[multi|fast|none]",
- desc = "Sets the reorder mode of WorldEdit",
- min = 0,
- max = 1
+ name = "/reorder",
+ desc = "Sets the reorder mode of WorldEdit"
)
@CommandPermissions("worldedit.reorder")
- public void reorderMode(Player player, LocalSession session, CommandContext args) throws WorldEditException {
- String newState = args.getString(0, null);
- if (newState == null) {
+ public void reorderMode(Player player, LocalSession session,
+ @Arg(desc = "The reorder mode", def = "")
+ EditSession.ReorderMode reorderMode) throws WorldEditException {
+ if (reorderMode == null) {
player.print("The reorder mode is " + session.getReorderMode().getDisplayName());
} else {
- java.util.Optional reorderModeOptional = EditSession.ReorderMode.getFromDisplayName(newState);
- if (!reorderModeOptional.isPresent()) {
- player.printError("Unknown reorder mode!");
- return;
- }
-
- EditSession.ReorderMode reorderMode = reorderModeOptional.get();
session.setReorderMode(reorderMode);
player.print("The reorder mode is now " + session.getReorderMode().getDisplayName());
}
}
@Command(
- aliases = { "/drawsel" },
- usage = "[on|off]",
- desc = "Toggle drawing the current selection",
- min = 0,
- max = 1
+ name = "/drawsel",
+ desc = "Toggle drawing the current selection"
)
@CommandPermissions("worldedit.drawsel")
- public void drawSelection(Player player, LocalSession session, CommandContext args) throws WorldEditException {
-
+ public void drawSelection(Player player, LocalSession session,
+ @Arg(desc = "The new draw selection state", def = "")
+ Boolean drawSelection) throws WorldEditException {
if (!WorldEdit.getInstance().getConfiguration().serverSideCUI) {
throw new DisallowedUsageException("This functionality is disabled in the configuration!");
}
- String newState = args.getString(0, null);
- if (session.shouldUseServerCUI()) {
- if ("on".equals(newState)) {
- player.printError("Server CUI already enabled.");
- return;
- }
-
+ boolean useServerCui = session.shouldUseServerCUI();
+ if (drawSelection != null && drawSelection == useServerCui) {
+ player.printError("Server CUI already " + (useServerCui ? "enabled" : "disabled") + ".");
+ return;
+ }
+ if (useServerCui) {
session.setUseServerCUI(false);
session.updateServerCUI(player);
player.print("Server CUI disabled.");
} else {
- if ("off".equals(newState)) {
- player.printError("Server CUI already disabled.");
- return;
- }
-
session.setUseServerCUI(true);
session.updateServerCUI(player);
player.print("Server CUI enabled. This only supports cuboid regions, with a maximum size of 32x32x32.");
@@ -206,14 +183,14 @@ public class GeneralCommands {
}
@Command(
- aliases = { "/gmask", "gmask" },
- usage = "[mask]",
- desc = "Set the global mask",
- min = 0,
- max = -1
+ name = "gmask",
+ aliases = {"/gmask"},
+ desc = "Set the global mask"
)
@CommandPermissions("worldedit.global-mask")
- public void gmask(Player player, LocalSession session, @Optional Mask mask) throws WorldEditException {
+ public void gmask(Player player, LocalSession session,
+ @Arg(desc = "The mask to set", def = "")
+ Mask mask) throws WorldEditException {
if (mask == null) {
session.setMask((Mask) null);
player.print("Global mask disabled.");
@@ -224,11 +201,9 @@ public class GeneralCommands {
}
@Command(
- aliases = { "/toggleplace", "toggleplace" },
- usage = "",
- desc = "Switch between your position and pos1 for placement",
- min = 0,
- max = 0
+ name = "toggleplace",
+ aliases = {"/toggleplace"},
+ desc = "Switch between your position and pos1 for placement"
)
public void togglePlace(Player player, LocalSession session) throws WorldEditException {
@@ -240,24 +215,17 @@ public class GeneralCommands {
}
@Command(
- aliases = { "/searchitem", "/l", "/search", "searchitem" },
- usage = "",
- flags = "bi",
- desc = "Search for an item",
- help =
- "Searches for an item.\n" +
- "Flags:\n" +
- " -b only search for blocks\n" +
- " -i only search for items",
- min = 1,
- max = 1
+ name = "searchitem",
+ aliases = {"/searchitem", "/l", "/search"},
+ desc = "Search for an item"
)
- public void searchItem(Actor actor, CommandContext args) throws WorldEditException {
-
- String query = args.getString(0).trim().toLowerCase();
- boolean blocksOnly = args.hasFlag('b');
- boolean itemsOnly = args.hasFlag('i');
-
+ public void searchItem(Actor actor,
+ @Arg(desc = "Item query")
+ String query,
+ @Switch(name = 'b', desc = "Only search for blocks")
+ boolean blocksOnly,
+ @Switch(name = 'i', desc = "Only search for items")
+ boolean itemsOnly) throws WorldEditException {
ItemType type = ItemTypes.get(query);
if (type != null) {
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java
index 971fb58d8..5f5229aeb 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java
@@ -19,35 +19,39 @@
package com.sk89q.worldedit.command;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.sk89q.minecraft.util.commands.Logging.LogMode.ALL;
-import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT;
-import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION;
-
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
-import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
+import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.pattern.Pattern;
+import com.sk89q.worldedit.internal.annotation.Radii;
import com.sk89q.worldedit.internal.annotation.Selection;
import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.TreeGenerator.TreeType;
-import com.sk89q.worldedit.util.command.binding.Range;
-import com.sk89q.worldedit.util.command.binding.Switch;
-import com.sk89q.worldedit.util.command.binding.Text;
-import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.world.biome.BiomeType;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
+import org.enginehub.piston.annotation.param.Switch;
+
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL;
+import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT;
+import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION;
/**
* Commands for the generation of shapes and other objects.
*/
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class GenerationCommands {
private final WorldEdit worldEdit;
@@ -63,54 +67,52 @@ public class GenerationCommands {
}
@Command(
- aliases = { "/hcyl" },
- usage = " [,] [height]",
- desc = "Generates a hollow cylinder.",
- help =
- "Generates a hollow cylinder.\n" +
- "By specifying 2 radii, separated by a comma,\n" +
- "you can generate elliptical cylinders.\n" +
- "The 1st radius is north/south, the 2nd radius is east/west.",
- min = 2,
- max = 3
+ name = "/hcyl",
+ desc = "Generates a hollow cylinder."
)
@CommandPermissions("worldedit.generation.cylinder")
@Logging(PLACEMENT)
- public void hcyl(Player player, LocalSession session, EditSession editSession, Pattern pattern, String radiusString, @Optional("1") int height) throws WorldEditException {
- cyl(player, session, editSession, pattern, radiusString, height, true);
+ public int hcyl(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The pattern of blocks to generate")
+ Pattern pattern,
+ @Arg(desc = "The radii of the cylinder. 1st is N/S, 2nd is E/W")
+ @Radii(2)
+ List radii,
+ @Arg(desc = "The height of the cylinder", def = "1")
+ int height) throws WorldEditException {
+ return cyl(player, session, editSession, pattern, radii, height, true);
}
@Command(
- aliases = { "/cyl" },
- usage = " [,] [height]",
- flags = "h",
- desc = "Generates a cylinder.",
- help =
- "Generates a cylinder.\n" +
- "By specifying 2 radii, separated by a comma,\n" +
- "you can generate elliptical cylinders.\n" +
- "The 1st radius is north/south, the 2nd radius is east/west.",
- min = 2,
- max = 3
+ name = "/cyl",
+ desc = "Generates a cylinder."
)
@CommandPermissions("worldedit.generation.cylinder")
@Logging(PLACEMENT)
- public void cyl(Player player, LocalSession session, EditSession editSession, Pattern pattern, String radiusString, @Optional("1") int height, @Switch('h') boolean hollow) throws WorldEditException {
- String[] radii = radiusString.split(",");
+ public int cyl(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The pattern of blocks to generate")
+ Pattern pattern,
+ @Arg(desc = "The radii of the cylinder. 1st is N/S, 2nd is E/W")
+ @Radii(2)
+ List radii,
+ @Arg(desc = "The height of the cylinder", def = "1")
+ int height,
+ @Switch(name = 'h', desc = "Make a hollow cylinder")
+ boolean hollow) throws WorldEditException {
final double radiusX, radiusZ;
- switch (radii.length) {
+ switch (radii.size()) {
case 1:
- radiusX = radiusZ = Math.max(1, Double.parseDouble(radii[0]));
+ radiusX = radiusZ = Math.max(1, radii.get(0));
break;
case 2:
- radiusX = Math.max(1, Double.parseDouble(radii[0]));
- radiusZ = Math.max(1, Double.parseDouble(radii[1]));
+ radiusX = Math.max(1, radii.get(0));
+ radiusZ = Math.max(1, radii.get(1));
break;
default:
player.printError("You must either specify 1 or 2 radius values.");
- return;
+ return 0;
}
worldEdit.checkMaxRadius(radiusX);
@@ -120,58 +122,57 @@ public class GenerationCommands {
BlockVector3 pos = session.getPlacementPosition(player);
int affected = editSession.makeCylinder(pos, pattern, radiusX, radiusZ, height, !hollow);
player.print(affected + " block(s) have been created.");
+ return affected;
}
@Command(
- aliases = { "/hsphere" },
- usage = " [,,] [raised?]",
- desc = "Generates a hollow sphere.",
- help =
- "Generates a hollow sphere.\n" +
- "By specifying 3 radii, separated by commas,\n" +
- "you can generate an ellipsoid. The order of the ellipsoid radii\n" +
- "is north/south, up/down, east/west.",
- min = 2,
- max = 3
+ name = "/hsphere",
+ desc = "Generates a hollow sphere."
)
@CommandPermissions("worldedit.generation.sphere")
@Logging(PLACEMENT)
- public void hsphere(Player player, LocalSession session, EditSession editSession, Pattern pattern, String radiusString, @Optional("false") boolean raised) throws WorldEditException {
- sphere(player, session, editSession, pattern, radiusString, raised, true);
+ public int hsphere(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The pattern of blocks to generate")
+ Pattern pattern,
+ @Arg(desc = "The radii of the sphere. Order is N/S, U/D, E/W")
+ @Radii(3)
+ List radii,
+ @Switch(name = 'r', desc = "Raise the bottom of the sphere to the placement position")
+ boolean raised) throws WorldEditException {
+ return sphere(player, session, editSession, pattern, radii, raised, true);
}
@Command(
- aliases = { "/sphere" },
- usage = " [,,] [raised?]",
- flags = "h",
- desc = "Generates a filled sphere.",
- help =
- "Generates a filled sphere.\n" +
- "By specifying 3 radii, separated by commas,\n" +
- "you can generate an ellipsoid. The order of the ellipsoid radii\n" +
- "is north/south, up/down, east/west.",
- min = 2,
- max = 3
+ name = "/sphere",
+ desc = "Generates a filled sphere."
)
@CommandPermissions("worldedit.generation.sphere")
@Logging(PLACEMENT)
- public void sphere(Player player, LocalSession session, EditSession editSession, Pattern pattern, String radiusString, @Optional("false") boolean raised, @Switch('h') boolean hollow) throws WorldEditException {
- String[] radii = radiusString.split(",");
+ public int sphere(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The pattern of blocks to generate")
+ Pattern pattern,
+ @Arg(desc = "The radii of the sphere. Order is N/S, U/D, E/W")
+ @Radii(3)
+ List radii,
+ @Switch(name = 'r', desc = "Raise the bottom of the sphere to the placement position")
+ boolean raised,
+ @Switch(name = 'h', desc = "Make a hollow sphere")
+ boolean hollow) throws WorldEditException {
final double radiusX, radiusY, radiusZ;
- switch (radii.length) {
+ switch (radii.size()) {
case 1:
- radiusX = radiusY = radiusZ = Math.max(1, Double.parseDouble(radii[0]));
+ radiusX = radiusY = radiusZ = Math.max(1, radii.get(0));
break;
case 3:
- radiusX = Math.max(1, Double.parseDouble(radii[0]));
- radiusY = Math.max(1, Double.parseDouble(radii[1]));
- radiusZ = Math.max(1, Double.parseDouble(radii[2]));
+ radiusX = Math.max(1, radii.get(0));
+ radiusY = Math.max(1, radii.get(1));
+ radiusZ = Math.max(1, radii.get(2));
break;
default:
player.printError("You must either specify 1 or 3 radius values.");
- return;
+ return 0;
}
worldEdit.checkMaxRadius(radiusX);
@@ -186,98 +187,102 @@ public class GenerationCommands {
int affected = editSession.makeSphere(pos, pattern, radiusX, radiusY, radiusZ, !hollow);
player.findFreePosition();
player.print(affected + " block(s) have been created.");
+ return affected;
}
@Command(
- aliases = { "forestgen" },
- usage = "[size] [type] [density]",
- desc = "Generate a forest",
- min = 0,
- max = 3
+ name = "forestgen",
+ desc = "Generate a forest"
)
@CommandPermissions("worldedit.generation.forest")
@Logging(POSITION)
- public void forestGen(Player player, LocalSession session, EditSession editSession, @Optional("10") int size,
- @Optional("tree") TreeType type, @Optional("5") @Range(min = 0, max = 100) double density) throws WorldEditException {
+ public int forestGen(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The size of the forest, in blocks", def = "10")
+ int size,
+ @Arg(desc = "The type of forest", def = "tree")
+ TreeType type,
+ @Arg(desc = "The density of the forest, between 0 and 100", def = "5")
+ double density) throws WorldEditException {
+ if (density < 0 || density > 100) {
+ throw new IllegalArgumentException("Density must be between 0 and 100");
+ }
density = density / 100;
int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type);
player.print(affected + " trees created.");
+ return affected;
}
@Command(
- aliases = { "pumpkins" },
- usage = "[size]",
- desc = "Generate pumpkin patches",
- min = 0,
- max = 1
+ name = "pumpkins",
+ desc = "Generate pumpkin patches"
)
@CommandPermissions("worldedit.generation.pumpkins")
@Logging(POSITION)
- public void pumpkins(Player player, LocalSession session, EditSession editSession, @Optional("10") int apothem) throws WorldEditException {
- int affected = editSession.makePumpkinPatches(session.getPlacementPosition(player), apothem);
+ public int pumpkins(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The size of the patch", def = "10")
+ int size) throws WorldEditException {
+ int affected = editSession.makePumpkinPatches(session.getPlacementPosition(player), size);
player.print(affected + " pumpkin patches created.");
+ return affected;
}
@Command(
- aliases = { "/hpyramid" },
- usage = " ",
- desc = "Generate a hollow pyramid",
- min = 2,
- max = 2
+ name = "/hpyramid",
+ desc = "Generate a hollow pyramid"
)
@CommandPermissions("worldedit.generation.pyramid")
@Logging(PLACEMENT)
- public void hollowPyramid(Player player, LocalSession session, EditSession editSession, Pattern pattern, @Range(min = 1) int size) throws WorldEditException {
- pyramid(player, session, editSession, pattern, size, true);
+ public int hollowPyramid(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The pattern of blocks to set")
+ Pattern pattern,
+ @Arg(desc = "The size of the pyramid")
+ int size) throws WorldEditException {
+ return pyramid(player, session, editSession, pattern, size, true);
}
@Command(
- aliases = { "/pyramid" },
- usage = " ",
- flags = "h",
- desc = "Generate a filled pyramid",
- min = 2,
- max = 2
+ name = "/pyramid",
+ desc = "Generate a filled pyramid"
)
@CommandPermissions("worldedit.generation.pyramid")
@Logging(PLACEMENT)
- public void pyramid(Player player, LocalSession session, EditSession editSession, Pattern pattern, @Range(min = 1) int size, @Switch('h') boolean hollow) throws WorldEditException {
+ public int pyramid(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The pattern of blocks to set")
+ Pattern pattern,
+ @Arg(desc = "The size of the pyramid")
+ int size,
+ @Switch(name = 'h', desc = "Make a hollow pyramid")
+ boolean hollow) throws WorldEditException {
BlockVector3 pos = session.getPlacementPosition(player);
worldEdit.checkMaxRadius(size);
int affected = editSession.makePyramid(pos, pattern, size, !hollow);
player.findFreePosition();
player.print(affected + " block(s) have been created.");
+ return affected;
}
@Command(
- aliases = { "/generate", "/gen", "/g" },
- usage = " ",
+ name = "/generate",
+ aliases = { "/gen", "/g" },
desc = "Generates a shape according to a formula.",
- help =
- "Generates a shape according to a formula that is expected to\n" +
- "return positive numbers (true) if the point is inside the shape\n" +
- "Optionally set type/data to the desired block.\n" +
- "Flags:\n" +
- " -h to generate a hollow shape\n" +
- " -r to use raw minecraft coordinates\n" +
- " -o is like -r, except offset from placement.\n" +
- " -c is like -r, except offset selection center.\n" +
- "If neither -r nor -o is given, the selection is mapped to -1..1\n" +
- "See also tinyurl.com/wesyntax.",
- flags = "hroc",
- min = 2,
- max = -1
+ descFooter = "See also https://tinyurl.com/wesyntax."
)
@CommandPermissions("worldedit.generation.shape")
@Logging(ALL)
- public void generate(Player player, LocalSession session, EditSession editSession,
- @Selection Region region,
- Pattern pattern,
- @Text String expression,
- @Switch('h') boolean hollow,
- @Switch('r') boolean useRawCoords,
- @Switch('o') boolean offset,
- @Switch('c') boolean offsetCenter) throws WorldEditException {
+ public int generate(Player player, LocalSession session, EditSession editSession,
+ @Selection Region region,
+ @Arg(desc = "The pattern of blocks to set")
+ Pattern pattern,
+ @Arg(desc = "Expression to test block placement locations and set block type", variable = true)
+ List expression,
+ @Switch(name = 'h', desc = "Generate a hollow shape")
+ boolean hollow,
+ @Switch(name = 'r', desc = "Use the game's coordinate origin")
+ boolean useRawCoords,
+ @Switch(name = 'o', desc = "Use the placement's coordinate origin")
+ boolean offset,
+ @Switch(name = 'c', desc = "Use the selection's center as origin")
+ boolean offsetCenter) throws WorldEditException {
final Vector3 zero;
Vector3 unit;
@@ -307,43 +312,38 @@ public class GenerationCommands {
}
try {
- final int affected = editSession.makeShape(region, zero, unit, pattern, expression, hollow, session.getTimeout());
+ final int affected = editSession.makeShape(region, zero, unit, pattern, String.join(" ", expression), hollow, session.getTimeout());
player.findFreePosition();
player.print(affected + " block(s) have been created.");
+ return affected;
} catch (ExpressionException e) {
player.printError(e.getMessage());
+ return 0;
}
}
@Command(
- aliases = { "/generatebiome", "/genbiome", "/gb" },
- usage = " ",
+ name = "/generatebiome",
+ aliases = { "/genbiome", "/gb" },
desc = "Sets biome according to a formula.",
- help =
- "Generates a shape according to a formula that is expected to\n" +
- "return positive numbers (true) if the point is inside the shape\n" +
- "Sets the biome of blocks in that shape.\n" +
- "Flags:\n" +
- " -h to generate a hollow shape\n" +
- " -r to use raw minecraft coordinates\n" +
- " -o is like -r, except offset from placement.\n" +
- " -c is like -r, except offset selection center.\n" +
- "If neither -r nor -o is given, the selection is mapped to -1..1\n" +
- "See also tinyurl.com/wesyntax.",
- flags = "hroc",
- min = 2,
- max = -1
+ descFooter = "See also https://tinyurl.com/wesyntax."
)
@CommandPermissions("worldedit.generation.shape.biome")
@Logging(ALL)
- public void generateBiome(Player player, LocalSession session, EditSession editSession,
- @Selection Region region,
- BiomeType target,
- @Text String expression,
- @Switch('h') boolean hollow,
- @Switch('r') boolean useRawCoords,
- @Switch('o') boolean offset,
- @Switch('c') boolean offsetCenter) throws WorldEditException {
+ public int generateBiome(Player player, LocalSession session, EditSession editSession,
+ @Selection Region region,
+ @Arg(desc = "The biome type to set")
+ BiomeType target,
+ @Arg(desc = "Expression to test block placement locations and set biome type", variable = true)
+ List expression,
+ @Switch(name = 'h', desc = "Generate a hollow shape")
+ boolean hollow,
+ @Switch(name = 'r', desc = "Use the game's coordinate origin")
+ boolean useRawCoords,
+ @Switch(name = 'o', desc = "Use the placement's coordinate origin")
+ boolean offset,
+ @Switch(name = 'c', desc = "Use the selection's center as origin")
+ boolean offsetCenter) throws WorldEditException {
final Vector3 zero;
Vector3 unit;
@@ -372,11 +372,13 @@ public class GenerationCommands {
}
try {
- final int affected = editSession.makeBiomeShape(region, zero, unit, target, expression, hollow, session.getTimeout());
+ final int affected = editSession.makeBiomeShape(region, zero, unit, target, String.join(" ", expression), hollow, session.getTimeout());
player.findFreePosition();
player.print("" + affected + " columns affected.");
+ return affected;
} catch (ExpressionException e) {
player.printError(e.getMessage());
+ return 0;
}
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java
index 773916d59..c5bb07699 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java
@@ -19,20 +19,23 @@
package com.sk89q.worldedit.command;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandContext;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.entity.Player;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
+
+import static com.google.common.base.Preconditions.checkNotNull;
/**
* Commands to undo, redo, and clear history.
*/
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class HistoryCommands {
private final WorldEdit worldEdit;
@@ -48,28 +51,29 @@ public class HistoryCommands {
}
@Command(
- aliases = { "/undo", "undo" },
- usage = "[times] [player]",
- desc = "Undoes the last action",
- min = 0,
- max = 2
+ name = "undo",
+ aliases = { "/undo" },
+ desc = "Undoes the last action (from history)"
)
@CommandPermissions("worldedit.history.undo")
- public void undo(Player player, LocalSession session, CommandContext args) throws WorldEditException {
- int times = Math.max(1, args.getInteger(0, 1));
+ public void undo(Player player, LocalSession session,
+ @Arg(desc = "Number of undoes to perform", def = "1")
+ int times,
+ @Arg(name = "player", desc = "Undo this player's operations", def = "")
+ String playerName) throws WorldEditException {
+ times = Math.max(1, times);
for (int i = 0; i < times; ++i) {
- EditSession undone;
- if (args.argsLength() < 2) {
- undone = session.undo(session.getBlockBag(player), player);
- } else {
+ LocalSession undoSession = session;
+ if (playerName != null) {
player.checkPermission("worldedit.history.undo.other");
- LocalSession sess = worldEdit.getSessionManager().findByName(args.getString(1));
+ LocalSession sess = worldEdit.getSessionManager().findByName(playerName);
if (sess == null) {
- player.printError("Unable to find session for " + args.getString(1));
+ player.printError("Unable to find session for " + playerName);
break;
}
- undone = sess.undo(session.getBlockBag(player), player);
+ undoSession = session;
}
+ EditSession undone = undoSession.undo(undoSession.getBlockBag(player), player);
if (undone != null) {
player.print("Undo successful.");
worldEdit.flushBlockBag(player, undone);
@@ -81,30 +85,29 @@ public class HistoryCommands {
}
@Command(
- aliases = { "/redo", "redo" },
- usage = "[times] [player]",
- desc = "Redoes the last action (from history)",
- min = 0,
- max = 2
+ name = "redo",
+ aliases = { "/redo" },
+ desc = "Redoes the last action (from history)"
)
@CommandPermissions("worldedit.history.redo")
- public void redo(Player player, LocalSession session, CommandContext args) throws WorldEditException {
-
- int times = Math.max(1, args.getInteger(0, 1));
-
+ public void redo(Player player, LocalSession session,
+ @Arg(desc = "Number of redoes to perform", def = "1")
+ int times,
+ @Arg(name = "player", desc = "Redo this player's operations", def = "")
+ String playerName) throws WorldEditException {
+ times = Math.max(1, times);
for (int i = 0; i < times; ++i) {
- EditSession redone;
- if (args.argsLength() < 2) {
- redone = session.redo(session.getBlockBag(player), player);
- } else {
+ LocalSession redoSession = session;
+ if (playerName != null) {
player.checkPermission("worldedit.history.redo.other");
- LocalSession sess = worldEdit.getSessionManager().findByName(args.getString(1));
+ LocalSession sess = worldEdit.getSessionManager().findByName(playerName);
if (sess == null) {
- player.printError("Unable to find session for " + args.getString(1));
+ player.printError("Unable to find session for " + playerName);
break;
}
- redone = sess.redo(session.getBlockBag(player), player);
+ redoSession = session;
}
+ EditSession redone = redoSession.redo(redoSession.getBlockBag(player), player);
if (redone != null) {
player.print("Redo successful.");
worldEdit.flushBlockBag(player, redone);
@@ -116,11 +119,9 @@ public class HistoryCommands {
}
@Command(
- aliases = { "/clearhistory", "clearhistory" },
- usage = "",
- desc = "Clear your history",
- min = 0,
- max = 0
+ name = "clearhistory",
+ aliases = { "/clearhistory" },
+ desc = "Clear your history"
)
@CommandPermissions("worldedit.history.clear")
public void clearHistory(Player player, LocalSession session) throws WorldEditException {
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java
index 2d64d472b..0b70e0bd7 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java
@@ -19,23 +19,26 @@
package com.sk89q.worldedit.command;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION;
-
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandContext;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
-import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
+import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.util.Location;
-import com.sk89q.worldedit.util.command.parametric.Optional;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
+import org.enginehub.piston.annotation.param.Switch;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION;
/**
* Commands for moving the player around.
*/
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class NavigationCommands {
private final WorldEdit worldEdit;
@@ -51,80 +54,78 @@ public class NavigationCommands {
}
@Command(
- aliases = { "unstuck", "!" },
- usage = "",
- desc = "Escape from being stuck inside a block",
- min = 0,
- max = 0
+ name = "unstuck",
+ aliases = { "!" },
+ desc = "Escape from being stuck inside a block"
)
@CommandPermissions("worldedit.navigation.unstuck")
public void unstuck(Player player) throws WorldEditException {
- player.print("There you go!");
player.findFreePosition();
+ player.print("There you go!");
}
@Command(
- aliases = { "ascend", "asc" },
- usage = "[# of levels]",
- desc = "Go up a floor",
- min = 0,
- max = 1
+ name = "ascend",
+ aliases = { "asc" },
+ desc = "Go up a floor"
)
@CommandPermissions("worldedit.navigation.ascend")
- public void ascend(Player player, @Optional("1") int levelsToAscend) throws WorldEditException {
+ public void ascend(Player player,
+ @Arg(desc = "# of levels to ascend", def = "1")
+ int levels) throws WorldEditException {
int ascentLevels = 0;
while (player.ascendLevel()) {
++ascentLevels;
- if (levelsToAscend == ascentLevels) {
+ if (levels == ascentLevels) {
break;
}
}
if (ascentLevels == 0) {
player.printError("No free spot above you found.");
} else {
- player.print((ascentLevels != 1) ? "Ascended " + Integer.toString(ascentLevels) + " levels." : "Ascended a level.");
+ player.print((ascentLevels != 1) ? "Ascended " + ascentLevels + " levels." : "Ascended a level.");
}
}
@Command(
- aliases = { "descend", "desc" },
- usage = "[# of floors]",
- desc = "Go down a floor",
- min = 0,
- max = 1
+ name = "descend",
+ aliases = { "desc" },
+ desc = "Go down a floor"
)
@CommandPermissions("worldedit.navigation.descend")
- public void descend(Player player, @Optional("1") int levelsToDescend) throws WorldEditException {
+ public void descend(Player player,
+ @Arg(desc = "# of levels to descend", def = "1")
+ int levels) throws WorldEditException {
int descentLevels = 0;
while (player.descendLevel()) {
++descentLevels;
- if (levelsToDescend == descentLevels) {
+ if (levels == descentLevels) {
break;
}
}
if (descentLevels == 0) {
player.printError("No free spot below you found.");
} else {
- player.print((descentLevels != 1) ? "Descended " + Integer.toString(descentLevels) + " levels." : "Descended a level.");
+ player.print((descentLevels != 1) ? "Descended " + descentLevels + " levels." : "Descended a level.");
}
}
@Command(
- aliases = { "ceil" },
- usage = "[clearance]",
- desc = "Go to the celing",
- flags = "fg",
- min = 0,
- max = 1
+ name = "ceil",
+ desc = "Go to the ceiling"
)
@CommandPermissions("worldedit.navigation.ceiling")
@Logging(POSITION)
- public void ceiling(Player player, CommandContext args) throws WorldEditException {
+ public void ceiling(Player player,
+ @Arg(desc = "# of blocks to leave above you", def = "0")
+ int clearance,
+ @Switch(name = 'f', desc = "Force using flight to keep you still")
+ boolean forceFlight,
+ @Switch(name = 'g', desc = "Force using glass to keep you still")
+ boolean forceGlass) throws WorldEditException {
+ clearance = Math.max(0, clearance);
- final int clearance = args.argsLength() > 0 ?
- Math.max(0, args.getInteger(0)) : 0;
-
- final boolean alwaysGlass = getAlwaysGlass(args);
+ boolean alwaysGlass = getAlwaysGlass(forceFlight, forceGlass);
if (player.ascendToCeiling(clearance, alwaysGlass)) {
player.print("Whoosh!");
} else {
@@ -133,11 +134,8 @@ public class NavigationCommands {
}
@Command(
- aliases = { "thru" },
- usage = "",
- desc = "Passthrough walls",
- min = 0,
- max = 0
+ name = "thru",
+ desc = "Pass through walls"
)
@CommandPermissions("worldedit.navigation.thru.command")
public void thru(Player player) throws WorldEditException {
@@ -149,11 +147,9 @@ public class NavigationCommands {
}
@Command(
- aliases = { "jumpto", "j" },
- usage = "",
- desc = "Teleport to a location",
- min = 0,
- max = 0
+ name = "jumpto",
+ aliases = { "j" },
+ desc = "Teleport to a location"
)
@CommandPermissions("worldedit.navigation.jumpto.command")
public void jumpTo(Player player) throws WorldEditException {
@@ -168,19 +164,19 @@ public class NavigationCommands {
}
@Command(
- aliases = { "up" },
- usage = "",
- desc = "Go upwards some distance",
- flags = "fg",
- min = 1,
- max = 1
+ name = "up",
+ desc = "Go upwards some distance"
)
@CommandPermissions("worldedit.navigation.up")
@Logging(POSITION)
- public void up(Player player, CommandContext args) throws WorldEditException {
- final int distance = args.getInteger(0);
-
- final boolean alwaysGlass = getAlwaysGlass(args);
+ public void up(Player player,
+ @Arg(desc = "Distance to go upwards")
+ int distance,
+ @Switch(name = 'f', desc = "Force using flight to keep you still")
+ boolean forceFlight,
+ @Switch(name = 'g', desc = "Force using glass to keep you still")
+ boolean forceGlass) throws WorldEditException {
+ boolean alwaysGlass = getAlwaysGlass(forceFlight, forceGlass);
if (player.ascendUpwards(distance, alwaysGlass)) {
player.print("Whoosh!");
} else {
@@ -190,16 +186,14 @@ public class NavigationCommands {
/**
* Helper function for /up and /ceil.
- *
- * @param args The {@link CommandContext} to extract the flags from.
+ *
+ * @param forceFlight if flight should be used, rather than the default config option
+ * @param forceGlass if glass should always be placed, rather than the default config option
* @return true, if glass should always be put under the player
*/
- private boolean getAlwaysGlass(CommandContext args) {
+ private boolean getAlwaysGlass(boolean forceFlight, boolean forceGlass) {
final LocalConfiguration config = worldEdit.getConfiguration();
- final boolean forceFlight = args.hasFlag('f');
- final boolean forceGlass = args.hasFlag('g');
-
return forceGlass || (config.navigationUseGlass && !forceFlight);
}
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java
new file mode 100644
index 000000000..cc53ec5b8
--- /dev/null
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java
@@ -0,0 +1,139 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.command;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.sk89q.worldedit.LocalSession;
+import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.blocks.BaseItem;
+import com.sk89q.worldedit.command.factory.ItemUseFactory;
+import com.sk89q.worldedit.command.factory.ReplaceFactory;
+import com.sk89q.worldedit.command.factory.TreeGeneratorFactory;
+import com.sk89q.worldedit.command.util.PermissionCondition;
+import com.sk89q.worldedit.entity.Player;
+import com.sk89q.worldedit.function.Contextual;
+import com.sk89q.worldedit.function.RegionFunction;
+import com.sk89q.worldedit.function.factory.Paint;
+import com.sk89q.worldedit.function.pattern.Pattern;
+import com.sk89q.worldedit.regions.factory.RegionFactory;
+import com.sk89q.worldedit.util.TreeGenerator;
+import com.sk89q.worldedit.internal.command.CommandRegistrationHandler;
+import com.sk89q.worldedit.util.formatting.text.TextComponent;
+import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
+import org.enginehub.piston.CommandManager;
+import org.enginehub.piston.CommandParameters;
+import org.enginehub.piston.DefaultCommandManagerService;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
+import org.enginehub.piston.inject.Key;
+import org.enginehub.piston.part.CommandArgument;
+import org.enginehub.piston.part.SubCommandPart;
+
+import java.util.stream.Collectors;
+
+import static java.util.Objects.requireNonNull;
+import static org.enginehub.piston.part.CommandParts.arg;
+
+@CommandContainer
+public class PaintBrushCommands {
+
+ private static final CommandArgument REGION_FACTORY = arg(TranslatableComponent.of("shape"), TextComponent.of("The shape of the region"))
+ .defaultsTo(ImmutableList.of())
+ .ofTypes(ImmutableList.of(Key.of(RegionFactory.class)))
+ .build();
+
+ private static final CommandArgument RADIUS = arg(TranslatableComponent.of("radius"), TextComponent.of("The size of the brush"))
+ .defaultsTo(ImmutableList.of("5"))
+ .ofTypes(ImmutableList.of(Key.of(double.class)))
+ .build();
+
+ private static final CommandArgument DENSITY = arg(TranslatableComponent.of("density"), TextComponent.of("The density of the brush"))
+ .defaultsTo(ImmutableList.of("20"))
+ .ofTypes(ImmutableList.of(Key.of(double.class)))
+ .build();
+
+ public static void register(CommandManager commandManager, CommandRegistrationHandler registration) {
+ commandManager.register("paint", builder -> {
+ builder.description(TextComponent.of("Paint brush, apply a function to a surface"));
+ builder.action(org.enginehub.piston.Command.Action.NULL_ACTION);
+
+ CommandManager manager = DefaultCommandManagerService.getInstance()
+ .newCommandManager();
+ registration.register(
+ manager,
+ PaintBrushCommandsRegistration.builder(),
+ new PaintBrushCommands()
+ );
+
+ builder.condition(new PermissionCondition(ImmutableSet.of("worldedit.brush.paint")));
+
+ builder.addParts(REGION_FACTORY, RADIUS, DENSITY);
+ builder.addPart(SubCommandPart.builder(TranslatableComponent.of("type"), TextComponent.of("Type of brush to use"))
+ .withCommands(manager.getAllCommands().collect(Collectors.toList()))
+ .required()
+ .build());
+ });
+ }
+
+ private void setPaintBrush(CommandParameters parameters, Player player, LocalSession localSession,
+ Contextual extends RegionFunction> generatorFactory) throws WorldEditException {
+ double radius = requireNonNull(RADIUS.value(parameters).asSingle(double.class));
+ double density = requireNonNull(DENSITY.value(parameters).asSingle(double.class)) / 100;
+ RegionFactory regionFactory = REGION_FACTORY.value(parameters).asSingle(RegionFactory.class);
+ BrushCommands.setOperationBasedBrush(player, localSession, radius,
+ new Paint(generatorFactory, density), regionFactory, "worldedit.brush.paint");
+ }
+
+ @Command(
+ name = "forest",
+ desc = "Plant trees"
+ )
+ public void forest(CommandParameters parameters,
+ Player player, LocalSession localSession,
+ @Arg(desc = "The type of tree to plant")
+ TreeGenerator.TreeType type) throws WorldEditException {
+ setPaintBrush(parameters, player, localSession, new TreeGeneratorFactory(type));
+ }
+
+ @Command(
+ name = "item",
+ desc = "Use an item"
+ )
+ public void item(CommandParameters parameters,
+ Player player, LocalSession localSession,
+ @Arg(desc = "The type of item to use")
+ BaseItem item) throws WorldEditException {
+ setPaintBrush(parameters, player, localSession, new ItemUseFactory(item));
+ }
+
+ @Command(
+ name = "set",
+ desc = "Place a block"
+ )
+ public void set(CommandParameters parameters,
+ Player player, LocalSession localSession,
+ @Arg(desc = "The pattern of blocks to use")
+ Pattern pattern) throws WorldEditException {
+ setPaintBrush(parameters, player, localSession, new ReplaceFactory(pattern));
+ }
+
+}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java
index d788063d5..a8591e1de 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java
@@ -19,31 +19,26 @@
package com.sk89q.worldedit.command;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.sk89q.minecraft.util.commands.Logging.LogMode.ALL;
-import static com.sk89q.minecraft.util.commands.Logging.LogMode.ORIENTATION_REGION;
-import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION;
-import static com.sk89q.worldedit.regions.Regions.asFlatRegion;
-import static com.sk89q.worldedit.regions.Regions.maximumBlockY;
-import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
-
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
-import com.sk89q.minecraft.util.commands.Logging;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
-import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
+import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.GroundFunction;
+import com.sk89q.worldedit.function.RegionFunction;
+import com.sk89q.worldedit.function.block.BlockReplace;
import com.sk89q.worldedit.function.generator.FloraGenerator;
-import com.sk89q.worldedit.function.generator.ForestGenerator;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.NoiseFilter2D;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.LayerVisitor;
+import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.internal.annotation.Direction;
import com.sk89q.worldedit.internal.annotation.Selection;
import com.sk89q.worldedit.internal.expression.ExpressionException;
@@ -58,56 +53,79 @@ import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionOperationException;
import com.sk89q.worldedit.util.TreeGenerator.TreeType;
-import com.sk89q.worldedit.util.command.binding.Range;
-import com.sk89q.worldedit.util.command.binding.Switch;
-import com.sk89q.worldedit.util.command.binding.Text;
-import com.sk89q.worldedit.util.command.parametric.Optional;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
+import org.enginehub.piston.annotation.param.Switch;
import java.util.ArrayList;
import java.util.List;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL;
+import static com.sk89q.worldedit.command.util.Logging.LogMode.ORIENTATION_REGION;
+import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
+import static com.sk89q.worldedit.regions.Regions.asFlatRegion;
+import static com.sk89q.worldedit.regions.Regions.maximumBlockY;
+import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
+
/**
* Commands that operate on regions.
*/
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class RegionCommands {
- private final WorldEdit worldEdit;
-
/**
* Create a new instance.
- *
- * @param worldEdit reference to WorldEdit
*/
- public RegionCommands(WorldEdit worldEdit) {
- checkNotNull(worldEdit);
- this.worldEdit = worldEdit;
+ public RegionCommands() {
}
@Command(
- aliases = { "/line" },
- usage = " [thickness]",
- desc = "Draws a line segment between cuboid selection corners",
- help =
- "Draws a line segment between cuboid selection corners.\n" +
- "Can only be used with cuboid selections.\n" +
- "Flags:\n" +
- " -h generates only a shell",
- flags = "h",
- min = 1,
- max = 2
+ name = "/set",
+ desc = "Sets all the blocks in the region"
+ )
+ @CommandPermissions("worldedit.region.set")
+ @Logging(REGION)
+ public int set(Player player, EditSession editSession,
+ @Selection Region region,
+ @Arg(desc = "The patter of blocks to set")
+ Pattern pattern) {
+ RegionFunction set = new BlockReplace(editSession, pattern);
+ RegionVisitor visitor = new RegionVisitor(region, set);
+
+ Operations.completeBlindly(visitor);
+ List messages = Lists.newArrayList();
+ visitor.addStatusMessages(messages);
+ if (messages.isEmpty()) {
+ player.print("Operation completed.");
+ } else {
+ player.print("Operation completed (" + Joiner.on(", ").join(messages) + ").");
+ }
+
+ return visitor.getAffected();
+ }
+
+ @Command(
+ name = "/line",
+ desc = "Draws a line segment between cuboid selection corners",
+ descFooter = "Can only be used with a cuboid selection"
)
@CommandPermissions("worldedit.region.line")
@Logging(REGION)
- public void line(Player player, EditSession editSession,
- @Selection Region region,
- Pattern pattern,
- @Optional("0") @Range(min = 0) int thickness,
- @Switch('h') boolean shell) throws WorldEditException {
-
+ public int line(Player player, EditSession editSession,
+ @Selection Region region,
+ @Arg(desc = "The pattern of blocks to place")
+ Pattern pattern,
+ @Arg(desc = "The thickness of the line", def = "0")
+ int thickness,
+ @Switch(name = 'h', desc = "Generate only a shell")
+ boolean shell) throws WorldEditException {
if (!(region instanceof CuboidRegion)) {
player.printError("//line only works with cuboid selections");
- return;
+ return 0;
}
+ checkArgument(thickness >= 0, "Thickness must be >= 0");
CuboidRegion cuboidregion = (CuboidRegion) region;
BlockVector3 pos1 = cuboidregion.getPos1();
@@ -115,32 +133,29 @@ public class RegionCommands {
int blocksChanged = editSession.drawLine(pattern, pos1, pos2, thickness, !shell);
player.print(blocksChanged + " block(s) have been changed.");
+ return blocksChanged;
}
@Command(
- aliases = { "/curve" },
- usage = " [thickness]",
- desc = "Draws a spline through selected points",
- help =
- "Draws a spline through selected points.\n" +
- "Can only be used with convex polyhedral selections.\n" +
- "Flags:\n" +
- " -h generates only a shell",
- flags = "h",
- min = 1,
- max = 2
+ name = "/curve",
+ desc = "Draws a spline through selected points",
+ descFooter = "Can only be used with a convex polyhedral selection"
)
@CommandPermissions("worldedit.region.curve")
@Logging(REGION)
- public void curve(Player player, EditSession editSession,
- @Selection Region region,
- Pattern pattern,
- @Optional("0") @Range(min = 0) int thickness,
- @Switch('h') boolean shell) throws WorldEditException {
+ public int curve(Player player, EditSession editSession,
+ @Selection Region region,
+ @Arg(desc = "The pattern of blocks to place")
+ Pattern pattern,
+ @Arg(desc = "The thickness of the curve", def = "0")
+ int thickness,
+ @Switch(name = 'h', desc = "Generate only a shell")
+ boolean shell) throws WorldEditException {
if (!(region instanceof ConvexPolyhedralRegion)) {
player.printError("//curve only works with convex polyhedral selections");
- return;
+ return 0;
}
+ checkArgument(thickness >= 0, "Thickness must be >= 0");
ConvexPolyhedralRegion cpregion = (ConvexPolyhedralRegion) region;
List vectors = new ArrayList<>(cpregion.getVertices());
@@ -148,139 +163,140 @@ public class RegionCommands {
int blocksChanged = editSession.drawSpline(pattern, vectors, 0, 0, 0, 10, thickness, !shell);
player.print(blocksChanged + " block(s) have been changed.");
+ return blocksChanged;
}
@Command(
- aliases = { "/replace", "/re", "/rep" },
- usage = "[from-block] ",
- desc = "Replace all blocks in the selection with another",
- flags = "f",
- min = 1,
- max = 2
+ name = "/replace",
+ aliases = { "/re", "/rep" },
+ desc = "Replace all blocks in the selection with another"
)
@CommandPermissions("worldedit.region.replace")
@Logging(REGION)
- public void replace(Player player, EditSession editSession, @Selection Region region, @Optional Mask from, Pattern to) throws WorldEditException {
+ public int replace(Player player, EditSession editSession, @Selection Region region,
+ @Arg(desc = "The mask representing blocks to replace", def = "")
+ Mask from,
+ @Arg(desc = "The pattern of blocks to replace with")
+ Pattern to) throws WorldEditException {
if (from == null) {
from = new ExistingBlockMask(editSession);
}
int affected = editSession.replaceBlocks(region, from, to);
player.print(affected + " block(s) have been replaced.");
+ return affected;
}
@Command(
- aliases = { "/overlay" },
- usage = "",
- desc = "Set a block on top of blocks in the region",
- min = 1,
- max = 1
+ name = "/overlay",
+ desc = "Set a block on top of blocks in the region"
)
@CommandPermissions("worldedit.region.overlay")
@Logging(REGION)
- public void overlay(Player player, EditSession editSession, @Selection Region region, Pattern pattern) throws WorldEditException {
+ public int overlay(Player player, EditSession editSession, @Selection Region region,
+ @Arg(desc = "The pattern of blocks to overlay")
+ Pattern pattern) throws WorldEditException {
int affected = editSession.overlayCuboidBlocks(region, pattern);
player.print(affected + " block(s) have been overlaid.");
+ return affected;
}
@Command(
- aliases = { "/center", "/middle" },
- usage = "",
- desc = "Set the center block(s)",
- min = 1,
- max = 1
+ name = "/center",
+ aliases = { "/middle" },
+ desc = "Set the center block(s)"
)
@Logging(REGION)
@CommandPermissions("worldedit.region.center")
- public void center(Player player, EditSession editSession, @Selection Region region, Pattern pattern) throws WorldEditException {
+ public int center(Player player, EditSession editSession, @Selection Region region,
+ @Arg(desc = "The pattern of blocks to set")
+ Pattern pattern) throws WorldEditException {
int affected = editSession.center(region, pattern);
- player.print("Center set ("+ affected + " blocks changed)");
+ player.print("Center set (" + affected + " block(s) changed)");
+ return affected;
}
@Command(
- aliases = { "/naturalize" },
- usage = "",
- desc = "3 layers of dirt on top then rock below",
- min = 0,
- max = 0
+ name = "/naturalize",
+ desc = "3 layers of dirt on top then rock below"
)
@CommandPermissions("worldedit.region.naturalize")
@Logging(REGION)
- public void naturalize(Player player, EditSession editSession, @Selection Region region) throws WorldEditException {
+ public int naturalize(Player player, EditSession editSession, @Selection Region region) throws WorldEditException {
int affected = editSession.naturalizeCuboidBlocks(region);
player.print(affected + " block(s) have been made to look more natural.");
+ return affected;
}
@Command(
- aliases = { "/walls" },
- usage = "",
- desc = "Build the four sides of the selection",
- min = 1,
- max = 1
+ name = "/walls",
+ desc = "Build the four sides of the selection"
)
@CommandPermissions("worldedit.region.walls")
@Logging(REGION)
- public void walls(Player player, EditSession editSession, @Selection Region region, Pattern pattern) throws WorldEditException {
+ public int walls(Player player, EditSession editSession, @Selection Region region,
+ @Arg(desc = "The pattern of blocks to set")
+ Pattern pattern) throws WorldEditException {
int affected = editSession.makeWalls(region, pattern);
player.print(affected + " block(s) have been changed.");
+ return affected;
}
@Command(
- aliases = { "/faces", "/outline" },
- usage = "",
- desc = "Build the walls, ceiling, and floor of a selection",
- min = 1,
- max = 1
+ name = "/faces",
+ aliases = { "/outline" },
+ desc = "Build the walls, ceiling, and floor of a selection"
)
@CommandPermissions("worldedit.region.faces")
@Logging(REGION)
- public void faces(Player player, EditSession editSession, @Selection Region region, Pattern pattern) throws WorldEditException {
+ public int faces(Player player, EditSession editSession, @Selection Region region,
+ @Arg(desc = "The pattern of blocks to set")
+ Pattern pattern) throws WorldEditException {
int affected = editSession.makeCuboidFaces(region, pattern);
player.print(affected + " block(s) have been changed.");
+ return affected;
}
@Command(
- aliases = { "/smooth" },
- usage = "[iterations] [filter]",
+ name = "/smooth",
desc = "Smooth the elevation in the selection",
- help =
- "Smooths the elevation in the selection.\n" +
- "Optionally, restricts the height map to a set of blocks specified with mask syntax.\n" +
- "For example, '//smooth 1 grass_block,dirt,stone' would only smooth natural surface terrain.",
- min = 0,
- max = 2
+ descFooter = "Example: '//smooth 1 grass_block,dirt,stone' would only smooth natural surface terrain."
)
@CommandPermissions("worldedit.region.smooth")
@Logging(REGION)
- public void smooth(Player player, EditSession editSession, @Selection Region region, @Optional("1") int iterations, @Optional Mask mask) throws WorldEditException {
+ public int smooth(Player player, EditSession editSession, @Selection Region region,
+ @Arg(desc = "# of iterations to perform", def = "1")
+ int iterations,
+ @Arg(desc = "The mask of blocks to use as the height map", def = "")
+ Mask mask) throws WorldEditException {
HeightMap heightMap = new HeightMap(editSession, region, mask);
HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0));
int affected = heightMap.applyFilter(filter, iterations);
player.print("Terrain's height map smoothed. " + affected + " block(s) changed.");
-
+ return affected;
}
@Command(
- aliases = { "/move" },
- usage = "[count] [direction] [leave-id]",
- flags = "sa",
- desc = "Move the contents of the selection",
- help =
- "Moves the contents of the selection.\n" +
- "The -s flag shifts the selection to the target location.\n" +
- "The -a flag skips air blocks.\n" +
- "Optionally fills the old location with .",
- min = 0,
- max = 3
+ name = "/move",
+ desc = "Move the contents of the selection"
)
@CommandPermissions("worldedit.region.move")
@Logging(ORIENTATION_REGION)
- public void move(Player player, EditSession editSession, LocalSession session,
- @Selection Region region,
- @Optional("1") @Range(min = 1) int count,
- @Optional(Direction.AIM) @Direction(includeDiagonals = true) BlockVector3 direction,
- @Optional("air") Pattern replace,
- @Switch('s') boolean moveSelection,
- @Switch('a') boolean ignoreAirBlocks) throws WorldEditException {
+ public int move(Player player, EditSession editSession, LocalSession session,
+ @Selection Region region,
+ @Arg(desc = "# of blocks to move", def = "1")
+ int count,
+ @Arg(desc = "The direction to move", def = Direction.AIM)
+ @Direction(includeDiagonals = true)
+ BlockVector3 direction,
+ @Arg(desc = "The pattern of blocks to leave", def = "air")
+ Pattern replace,
+ @Switch(name = 's', desc = "Shift the selection to the target location")
+ boolean moveSelection,
+ @Switch(name = 'a', desc = "Ignore air blocks")
+ boolean ignoreAirBlocks) throws WorldEditException {
+ if (count < 1) {
+ throw new IllegalArgumentException("Count must be >= 1");
+ }
int affected = editSession.moveRegion(region, direction, count, !ignoreAirBlocks, replace);
@@ -295,30 +311,27 @@ public class RegionCommands {
}
}
- player.print(affected + " blocks moved.");
+ player.print(affected + " block(s) moved.");
+ return affected;
}
@Command(
- aliases = { "/stack" },
- usage = "[count] [direction]",
- flags = "sa",
- desc = "Repeat the contents of the selection",
- help =
- "Repeats the contents of the selection.\n" +
- "Flags:\n" +
- " -s shifts the selection to the last stacked copy\n" +
- " -a skips air blocks",
- min = 0,
- max = 2
+ name = "/stack",
+ desc = "Repeat the contents of the selection"
)
@CommandPermissions("worldedit.region.stack")
@Logging(ORIENTATION_REGION)
- public void stack(Player player, EditSession editSession, LocalSession session,
- @Selection Region region,
- @Optional("1") @Range(min = 1) int count,
- @Optional(Direction.AIM) @Direction(includeDiagonals = true) BlockVector3 direction,
- @Switch('s') boolean moveSelection,
- @Switch('a') boolean ignoreAirBlocks) throws WorldEditException {
+ public int stack(Player player, EditSession editSession, LocalSession session,
+ @Selection Region region,
+ @Arg(desc = "# of copies to stack", def = "1")
+ int count,
+ @Arg(desc = "The direction to stack", def = Direction.AIM)
+ @Direction(includeDiagonals = true)
+ BlockVector3 direction,
+ @Switch(name = 's', desc = "Shift the selection to the last stacked copy")
+ boolean moveSelection,
+ @Switch(name = 'a', desc = "Ignore air blocks")
+ boolean ignoreAirBlocks) throws WorldEditException {
int affected = editSession.stackCuboidRegion(region, direction, count, !ignoreAirBlocks);
if (moveSelection) {
@@ -335,26 +348,22 @@ public class RegionCommands {
}
}
- player.print(affected + " blocks changed. Undo with //undo");
+ player.print(affected + " block(s) changed. Undo with //undo");
+ return affected;
}
@Command(
- aliases = { "/regen" },
- usage = "",
+ name = "/regen",
desc = "Regenerates the contents of the selection",
- help =
- "Regenerates the contents of the current selection.\n" +
- "This command might affect things outside the selection,\n" +
- "if they are within the same chunk.",
- min = 0,
- max = 0
+ descFooter = "This command might affect things outside the selection,\n" +
+ "if they are within the same chunk."
)
@CommandPermissions("worldedit.regen")
@Logging(REGION)
public void regenerateChunk(Player player, LocalSession session, EditSession editSession, @Selection Region region) throws WorldEditException {
Mask mask = session.getMask();
try {
- session.setMask((Mask) null);
+ session.setMask(null);
player.getWorld().regenerate(region, editSession);
} finally {
session.setMask(mask);
@@ -363,25 +372,22 @@ public class RegionCommands {
}
@Command(
- aliases = { "/deform" },
- usage = "",
- desc = "Deforms a selected region with an expression",
- help =
- "Deforms a selected region with an expression\n" +
- "The expression is executed for each block and is expected\n" +
- "to modify the variables x, y and z to point to a new block\n" +
- "to fetch. See also tinyurl.com/wesyntax.",
- flags = "ro",
- min = 1,
- max = -1
+ name = "/deform",
+ desc = "Deforms a selected region with an expression",
+ descFooter = "The expression is executed for each block and is expected\n" +
+ "to modify the variables x, y and z to point to a new block\n" +
+ "to fetch. See also tinyurl.com/wesyntax."
)
@CommandPermissions("worldedit.region.deform")
@Logging(ALL)
- public void deform(Player player, LocalSession session, EditSession editSession,
- @Selection Region region,
- @Text String expression,
- @Switch('r') boolean useRawCoords,
- @Switch('o') boolean offset) throws WorldEditException {
+ public int deform(Player player, LocalSession session, EditSession editSession,
+ @Selection Region region,
+ @Arg(desc = "The expression to use", variable = true)
+ List expression,
+ @Switch(name = 'r', desc = "Use the game's coordinate origin")
+ boolean useRawCoords,
+ @Switch(name = 'o', desc = "Use the selection's center as origin")
+ boolean offset) throws WorldEditException {
final Vector3 zero;
Vector3 unit;
@@ -404,61 +410,63 @@ public class RegionCommands {
}
try {
- final int affected = editSession.deformRegion(region, zero, unit, expression, session.getTimeout());
+ final int affected = editSession.deformRegion(region, zero, unit, String.join(" ", expression), session.getTimeout());
player.findFreePosition();
player.print(affected + " block(s) have been deformed.");
+ return affected;
} catch (ExpressionException e) {
player.printError(e.getMessage());
+ return 0;
}
}
@Command(
- aliases = { "/hollow" },
- usage = "[[ ]]",
+ name = "/hollow",
desc = "Hollows out the object contained in this selection",
- help =
- "Hollows out the object contained in this selection.\n" +
- "Optionally fills the hollowed out part with the given block.\n" +
- "Thickness is measured in manhattan distance.",
- min = 0,
- max = 2
+ descFooter = "Thickness is measured in manhattan distance."
)
@CommandPermissions("worldedit.region.hollow")
@Logging(REGION)
- public void hollow(Player player, EditSession editSession,
- @Selection Region region,
- @Optional("0") @Range(min = 0) int thickness,
- @Optional("air") Pattern pattern) throws WorldEditException {
+ public int hollow(Player player, EditSession editSession,
+ @Selection Region region,
+ @Arg(desc = "Thickness of the shell to leave", def = "0")
+ int thickness,
+ @Arg(desc = "The pattern of blocks to replace the hollowed area with", def = "air")
+ Pattern pattern) throws WorldEditException {
+ checkArgument(thickness >= 0, "Thickness must be >= 0");
int affected = editSession.hollowOutRegion(region, thickness, pattern);
player.print(affected + " block(s) have been changed.");
+ return affected;
}
@Command(
- aliases = { "/forest" },
- usage = "[type] [density]",
- desc = "Make a forest within the region",
- min = 0,
- max = 2
+ name = "/forest",
+ desc = "Make a forest within the region"
)
@CommandPermissions("worldedit.region.forest")
@Logging(REGION)
- public void forest(Player player, EditSession editSession, @Selection Region region, @Optional("tree") TreeType type,
- @Optional("5") @Range(min = 0, max = 100) double density) throws WorldEditException {
+ public int forest(Player player, EditSession editSession, @Selection Region region,
+ @Arg(desc = "The type of tree to place", def = "tree")
+ TreeType type,
+ @Arg(desc = "The density of the forest", def = "5")
+ double density) throws WorldEditException {
+ checkArgument(0 <= density && density <= 100, "Density must be in [0, 100]");
int affected = editSession.makeForest(region, density / 100, type);
player.print(affected + " trees created.");
+ return affected;
}
@Command(
- aliases = { "/flora" },
- usage = "[density]",
- desc = "Make flora within the region",
- min = 0,
- max = 1
+ name = "/flora",
+ desc = "Make flora within the region"
)
@CommandPermissions("worldedit.region.flora")
@Logging(REGION)
- public void flora(Player player, EditSession editSession, @Selection Region region, @Optional("10") @Range(min = 0, max = 100) double density) throws WorldEditException {
+ public int flora(Player player, EditSession editSession, @Selection Region region,
+ @Arg(desc = "The density of the forest", def = "5")
+ double density) throws WorldEditException {
+ checkArgument(0 <= density && density <= 100, "Density must be in [0, 100]");
density = density / 100;
FloraGenerator generator = new FloraGenerator(editSession);
GroundFunction ground = new GroundFunction(new ExistingBlockMask(editSession), generator);
@@ -466,7 +474,9 @@ public class RegionCommands {
visitor.setMask(new NoiseFilter2D(new RandomNoise(), density));
Operations.completeLegacy(visitor);
- player.print(ground.getAffected() + " flora created.");
+ int affected = ground.getAffected();
+ player.print(affected + " flora created.");
+ return affected;
}
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java
index ab8ff950b..829af8a9c 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java
@@ -19,16 +19,12 @@
package com.sk89q.worldedit.command;
-import com.google.common.collect.Multimap;
-import com.google.common.io.Files;
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandContext;
-import com.sk89q.minecraft.util.commands.CommandException;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
@@ -41,12 +37,19 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.session.ClipboardHolder;
-import com.sk89q.worldedit.util.command.binding.Switch;
-import com.sk89q.worldedit.util.command.parametric.Optional;
+import com.sk89q.worldedit.util.formatting.component.PaginationBox;
+import com.sk89q.worldedit.util.formatting.component.SchematicPaginationBox;
+import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.io.Closer;
import com.sk89q.worldedit.util.io.file.FilenameException;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
+import org.enginehub.piston.annotation.param.ArgFlag;
+import org.enginehub.piston.annotation.param.Switch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.enginehub.piston.exception.StopExecutionException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -57,19 +60,15 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Commands that work with schematic files.
*/
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class SchematicCommands {
- /**
- * 9 schematics per page fits in the MC chat window.
- */
- private static final int SCHEMATICS_PER_PAGE = 9;
private static final Logger log = LoggerFactory.getLogger(SchematicCommands.class);
private final WorldEdit worldEdit;
@@ -84,17 +83,21 @@ public class SchematicCommands {
}
@Command(
- aliases = { "load" },
- usage = "[] ",
- desc = "Load a schematic into your clipboard",
- min = 1, max = 2
+ name = "load",
+ desc = "Load a schematic into your clipboard"
)
- @CommandPermissions({ "worldedit.clipboard.load", "worldedit.schematic.load" })
- public void load(Player player, LocalSession session, @Optional("sponge") String formatName, String filename) throws FilenameException {
+ @CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load"})
+ public void load(Player player, LocalSession session,
+ @Arg(desc = "File name.")
+ String filename,
+ @Arg(desc = "Format name.", def = "sponge")
+ String formatName) throws FilenameException {
LocalConfiguration config = worldEdit.getConfiguration();
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
- File f = worldEdit.getSafeOpenFile(player, dir, filename, BuiltInClipboardFormat.SPONGE_SCHEMATIC.getPrimaryFileExtension(), ClipboardFormats.getFileExtensionArray());
+ File f = worldEdit.getSafeOpenFile(player, dir, filename,
+ BuiltInClipboardFormat.SPONGE_SCHEMATIC.getPrimaryFileExtension(),
+ ClipboardFormats.getFileExtensionArray());
if (!f.exists()) {
player.printError("Schematic " + filename + " does not exist!");
@@ -122,21 +125,23 @@ public class SchematicCommands {
player.print(filename + " loaded. Paste it with //paste");
} catch (IOException e) {
player.printError("Schematic could not read or it does not exist: " + e.getMessage());
- log.warn("Failed to load a saved clipboard", e);
+ log.warn("Failed to load schematic: " + e.getMessage());
}
}
@Command(
- aliases = { "save" },
- flags = "f",
- usage = "[] ",
- desc = "Save a schematic into your clipboard",
- help = "-f is required to overwrite an existing file",
- min = 1, max = 2
+ name = "save",
+ desc = "Save a schematic into your clipboard"
)
- @CommandPermissions({ "worldedit.clipboard.save", "worldedit.schematic.save" })
- public void save(Player player, LocalSession session, @Optional("sponge") String formatName,
- String filename, @Switch('f') boolean allowOverwrite) throws CommandException, WorldEditException {
+ @CommandPermissions({"worldedit.clipboard.save", "worldedit.schematic.save"})
+ public void save(Player player, LocalSession session,
+ @Arg(desc = "File name.")
+ String filename,
+ @Arg(desc = "Format name.", def = "sponge")
+ String formatName,
+ @Switch(name = 'f', desc = "Overwrite an existing file.")
+ boolean allowOverwrite
+ ) throws WorldEditException {
LocalConfiguration config = worldEdit.getConfiguration();
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
@@ -152,7 +157,7 @@ public class SchematicCommands {
boolean overwrite = f.exists();
if (overwrite) {
if (!player.hasPermission("worldedit.schematic.delete")) {
- throw new CommandException("That schematic already exists!");
+ throw new StopExecutionException(TextComponent.of("That schematic already exists!"));
}
if (!allowOverwrite) {
player.printError("That schematic already exists. Use the -f flag to overwrite it.");
@@ -179,7 +184,8 @@ public class SchematicCommands {
File parent = f.getParentFile();
if (parent != null && !parent.exists()) {
if (!parent.mkdirs()) {
- throw new CommandException("Could not create folder for schematics!");
+ throw new StopExecutionException(TextComponent.of(
+ "Could not create folder for schematics!"));
}
}
@@ -198,15 +204,14 @@ public class SchematicCommands {
}
@Command(
- aliases = { "delete", "d" },
- usage = "",
- desc = "Delete a saved schematic",
- help = "Delete a schematic from the schematic list",
- min = 1,
- max = 1
+ name = "delete",
+ aliases = {"d"},
+ desc = "Delete a saved schematic"
)
@CommandPermissions("worldedit.schematic.delete")
- public void delete(Actor actor, String filename) throws WorldEditException {
+ public void delete(Actor actor,
+ @Arg(desc = "File name.")
+ String filename) throws WorldEditException {
LocalConfiguration config = worldEdit.getConfiguration();
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
@@ -232,12 +237,12 @@ public class SchematicCommands {
}
@Command(
- aliases = {"formats", "listformats", "f"},
- desc = "List available formats",
- max = 0
+ name = "formats",
+ aliases = {"listformats", "f"},
+ desc = "List available formats"
)
@CommandPermissions("worldedit.schematic.formats")
- public void formats(Actor actor) throws WorldEditException {
+ public void formats(Actor actor) {
actor.print("Available clipboard formats (Name: Lookup names)");
StringBuilder builder;
boolean first = true;
@@ -257,18 +262,22 @@ public class SchematicCommands {
}
@Command(
- aliases = {"list", "all", "ls"},
- desc = "List saved schematics",
- max = 1,
- flags = "dnp",
- help = "List all schematics in the schematics directory\n" +
- " -d sorts by date, oldest first\n" +
- " -n sorts by date, newest first\n" +
- " -p prints the requested page\n" +
- "Note: Format is not thoroughly verified until loading."
+ name = "list",
+ aliases = {"all", "ls"},
+ desc = "List saved schematics",
+ descFooter = "Note: Format is not fully verified until loading."
)
@CommandPermissions("worldedit.schematic.list")
- public void list(Actor actor, CommandContext args, @Switch('p') @Optional("1") int page) throws WorldEditException {
+ public void list(Actor actor,
+ @ArgFlag(name = 'p', desc = "Page to view.", def = "1")
+ int page,
+ @Switch(name = 'd', desc = "Sort by date, oldest first")
+ boolean oldFirst,
+ @Switch(name = 'n', desc = "Sort by date, newest first")
+ boolean newFirst) throws WorldEditException {
+ if (oldFirst && newFirst) {
+ throw new StopExecutionException(TextComponent.of("Cannot sort by oldest and newest."));
+ }
File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().saveDir);
List fileList = allFiles(dir);
@@ -280,17 +289,7 @@ public class SchematicCommands {
File[] files = new File[fileList.size()];
fileList.toArray(files);
- int pageCount = files.length / SCHEMATICS_PER_PAGE + 1;
- if (page < 1) {
- actor.printError("Page must be at least 1");
- return;
- }
- if (page > pageCount) {
- actor.printError("Page must be less than " + (pageCount + 1));
- return;
- }
-
- final int sortType = args.hasFlag('d') ? -1 : args.hasFlag('n') ? 1 : 0;
+ final int sortType = oldFirst ? -1 : newFirst ? 1 : 0;
// cleanup file list
Arrays.sort(files, (f1, f2) -> {
// http://stackoverflow.com/questions/203030/best-way-to-list-files-in-java-sorted-by-date-modified
@@ -309,20 +308,9 @@ public class SchematicCommands {
return res;
});
- List schematics = listFiles(worldEdit.getConfiguration().saveDir, files);
- int offset = (page - 1) * SCHEMATICS_PER_PAGE;
-
- actor.print("Available schematics (Filename: Format) [" + page + "/" + pageCount + "]:");
- StringBuilder build = new StringBuilder();
- int limit = Math.min(offset + SCHEMATICS_PER_PAGE, schematics.size());
- for (int i = offset; i < limit;) {
- build.append(schematics.get(i));
- if (++i != limit) {
- build.append("\n");
- }
- }
-
- actor.print(build.toString());
+ String pageCommand = actor.isPlayer() ? "//schem list -p %page%" + (oldFirst ? " -d" : newFirst ? " -n" : "") : null;
+ PaginationBox paginationBox = new SchematicPaginationBox(worldEdit.getConfiguration().saveDir, files, pageCommand);
+ actor.print(paginationBox.create(page));
}
private List allFiles(File root) {
@@ -341,22 +329,4 @@ public class SchematicCommands {
return fileList;
}
- private List listFiles(String prefix, File[] files) {
- if (prefix == null) prefix = "";
- List result = new ArrayList<>();
- for (File file : files) {
- StringBuilder build = new StringBuilder();
-
- build.append("\u00a72");
- //ClipboardFormat format = ClipboardFormats.findByFile(file);
- Multimap exts = ClipboardFormats.getFileExtensionMap();
- ClipboardFormat format = exts.get(Files.getFileExtension(file.getName()))
- .stream().findFirst().orElse(null);
- boolean inRoot = file.getParentFile().getName().equals(prefix);
- build.append(inRoot ? file.getName() : file.getPath().split(Pattern.quote(prefix + File.separator))[1])
- .append(": ").append(format == null ? "Unknown" : format.getName() + "*");
- result.add(build.toString());
- }
- return result;
- }
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java
index 2b7d9a61f..e60a3db51 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java
@@ -19,23 +19,28 @@
package com.sk89q.worldedit.command;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.sk89q.minecraft.util.commands.Logging.LogMode.ALL;
-
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandContext;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
-import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
+import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
import java.io.File;
+import java.util.List;
+import java.util.stream.Stream;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL;
/**
* Commands related to scripting.
*/
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ScriptingCommands {
private final WorldEdit worldEdit;
@@ -51,43 +56,40 @@ public class ScriptingCommands {
}
@Command(
- aliases = { "cs" },
- usage = " [args...]",
- desc = "Execute a CraftScript",
- min = 1,
- max = -1
+ name = "cs",
+ desc = "Execute a CraftScript"
)
@CommandPermissions("worldedit.scripting.execute")
@Logging(ALL)
- public void execute(Player player, LocalSession session, CommandContext args) throws WorldEditException {
-
- String[] scriptArgs = args.getSlice(1);
- String name = args.getString(0);
-
- if (!player.hasPermission("worldedit.scripting.execute." + name)) {
+ public void execute(Player player, LocalSession session,
+ @Arg(desc = "Filename of the CraftScript to load")
+ String filename,
+ @Arg(desc = "Arguments to the CraftScript", def = "", variable = true)
+ List args) throws WorldEditException {
+ if (!player.hasPermission("worldedit.scripting.execute." + filename)) {
player.printError("You don't have permission to use that script.");
return;
}
- session.setLastScript(name);
+ session.setLastScript(filename);
File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir);
- File f = worldEdit.getSafeOpenFile(player, dir, name, "js", "js");
+ File f = worldEdit.getSafeOpenFile(player, dir, filename, "js", "js");
- worldEdit.runScript(player, f, scriptArgs);
+ worldEdit.runScript(player, f, Stream.concat(Stream.of(filename), args.stream())
+ .toArray(String[]::new));
}
@Command(
- aliases = { ".s" },
- usage = "[args...]",
- desc = "Execute last CraftScript",
- min = 0,
- max = -1
+ name = ".s",
+ desc = "Execute last CraftScript"
)
@CommandPermissions("worldedit.scripting.execute")
@Logging(ALL)
- public void executeLast(Player player, LocalSession session, CommandContext args) throws WorldEditException {
-
+ public void executeLast(Player player, LocalSession session,
+ @Arg(desc = "Arguments to the CraftScript", def = "", variable = true)
+ List args) throws WorldEditException {
+
String lastScript = session.getLastScript();
if (!player.hasPermission("worldedit.scripting.execute." + lastScript)) {
@@ -100,11 +102,10 @@ public class ScriptingCommands {
return;
}
- String[] scriptArgs = args.getSlice(0);
-
File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir);
File f = worldEdit.getSafeOpenFile(player, dir, lastScript, "js", "js");
- worldEdit.runScript(player, f, scriptArgs);
+ worldEdit.runScript(player, f, Stream.concat(Stream.of(lastScript), args.stream())
+ .toArray(String[]::new));
}
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java
index 3c1be05fd..bac02819a 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java
@@ -19,19 +19,16 @@
package com.sk89q.worldedit.command;
-import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION;
-import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION;
-
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandContext;
-import com.sk89q.minecraft.util.commands.CommandException;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
-import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItemStack;
+import com.sk89q.worldedit.command.argument.ExpandAmount;
+import com.sk89q.worldedit.command.argument.SelectorChoice;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
+import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits;
@@ -39,6 +36,8 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.block.BlockDistributionCounter;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.visitor.RegionVisitor;
+import com.sk89q.worldedit.internal.annotation.Direction;
+import com.sk89q.worldedit.internal.annotation.MultiDirection;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
@@ -63,16 +62,23 @@ import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.storage.ChunkStore;
-import com.sk89q.worldedit.util.formatting.text.Component;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
+import org.enginehub.piston.annotation.param.Switch;
-import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
+import java.util.stream.Stream;
+
+import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION;
+import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
/**
* Selection commands.
*/
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class SelectionCommands {
private final WorldEdit we;
@@ -82,26 +88,17 @@ public class SelectionCommands {
}
@Command(
- aliases = { "/pos1" },
- usage = "[coordinates]",
- desc = "Set position 1",
- min = 0,
- max = 1
+ name = "/pos1",
+ desc = "Set position 1"
)
@Logging(POSITION)
@CommandPermissions("worldedit.selection.pos")
- public void pos1(Player player, LocalSession session, CommandContext args) throws WorldEditException {
-
+ public void pos1(Player player, LocalSession session,
+ @Arg(desc = "Coordinates to set position 1 to", def = "")
+ BlockVector3 coordinates) throws WorldEditException {
Location pos;
-
- if (args.argsLength() == 1) {
- if (args.getString(0).matches("-?\\d+,-?\\d+,-?\\d+")) {
- String[] coords = args.getString(0).split(",");
- pos = new Location(player.getWorld(), Integer.parseInt(coords[0]), Integer.parseInt(coords[1]), Integer.parseInt(coords[2]));
- } else {
- player.printError("Invalid coordinates " + args.getString(0));
- return;
- }
+ if (coordinates != null) {
+ pos = new Location(player.getWorld(), coordinates.toVector3());
} else {
pos = player.getBlockIn();
}
@@ -116,27 +113,17 @@ public class SelectionCommands {
}
@Command(
- aliases = { "/pos2" },
- usage = "[coordinates]",
- desc = "Set position 2",
- min = 0,
- max = 1
+ name = "/pos2",
+ desc = "Set position 2"
)
@Logging(POSITION)
@CommandPermissions("worldedit.selection.pos")
- public void pos2(Player player, LocalSession session, CommandContext args) throws WorldEditException {
-
+ public void pos2(Player player, LocalSession session,
+ @Arg(desc = "Coordinates to set position 2 to", def = "")
+ BlockVector3 coordinates) throws WorldEditException {
Location pos;
- if (args.argsLength() == 1) {
- if (args.getString(0).matches("-?\\d+,-?\\d+,-?\\d+")) {
- String[] coords = args.getString(0).split(",");
- pos = new Location(player.getWorld(), Integer.parseInt(coords[0]),
- Integer.parseInt(coords[1]),
- Integer.parseInt(coords[2]));
- } else {
- player.printError("Invalid coordinates " + args.getString(0));
- return;
- }
+ if (coordinates != null) {
+ pos = new Location(player.getWorld(), coordinates.toVector3());
} else {
pos = player.getBlockIn();
}
@@ -151,11 +138,8 @@ public class SelectionCommands {
}
@Command(
- aliases = { "/hpos1" },
- usage = "",
- desc = "Set position 1 to targeted block",
- min = 0,
- max = 0
+ name = "/hpos1",
+ desc = "Set position 1 to targeted block"
)
@CommandPermissions("worldedit.selection.hpos")
public void hpos1(Player player, LocalSession session) throws WorldEditException {
@@ -176,11 +160,8 @@ public class SelectionCommands {
}
@Command(
- aliases = { "/hpos2" },
- usage = "",
- desc = "Set position 2 to targeted block",
- min = 0,
- max = 0
+ name = "/hpos2",
+ desc = "Set position 2 to targeted block"
)
@CommandPermissions("worldedit.selection.hpos")
public void hpos2(Player player, LocalSession session) throws WorldEditException {
@@ -201,28 +182,22 @@ public class SelectionCommands {
}
@Command(
- aliases = { "/chunk" },
- usage = "[x,z coordinates]",
- flags = "sc",
- desc = "Set the selection to your current chunk.",
- help =
- "Set the selection to the chunk you are currently in.\n" +
- "With the -s flag, your current selection is expanded\n" +
- "to encompass all chunks that are part of it.\n\n" +
- "Specifying coordinates will use those instead of your\n"+
- "current position. Use -c to specify chunk coordinates,\n" +
- "otherwise full coordinates will be implied.\n" +
- "(for example, the coordinates 5,5 are the same as -c 0,0)",
- min = 0,
- max = 1
+ name = "/chunk",
+ desc = "Set the selection to your current chunk."
)
@Logging(POSITION)
@CommandPermissions("worldedit.selection.chunk")
- public void chunk(Player player, LocalSession session, CommandContext args) throws WorldEditException {
+ public void chunk(Player player, LocalSession session,
+ @Arg(desc = "The chunk to select", def = "")
+ BlockVector2 coordinates,
+ @Switch(name = 's', desc = "Expand your selection to encompass all chunks that are part of it")
+ boolean expandSelection,
+ @Switch(name = 'c', desc = "Use chunk coordinates instead of block coordinates")
+ boolean useChunkCoordinates) throws WorldEditException {
final BlockVector3 min;
final BlockVector3 max;
final World world = player.getWorld();
- if (args.hasFlag('s')) {
+ if (expandSelection) {
Region region = session.getSelection(world);
final BlockVector2 min2D = ChunkStore.toChunk(region.getMinimumPoint());
@@ -236,16 +211,11 @@ public class SelectionCommands {
+ max2D.getBlockX() + ", " + max2D.getBlockZ() + ")");
} else {
final BlockVector2 min2D;
- if (args.argsLength() == 1) {
+ if (coordinates != null) {
// coords specified
- String[] coords = args.getString(0).split(",");
- if (coords.length != 2) {
- throw new InsufficientArgumentsException("Invalid coordinates specified.");
- }
- int x = Integer.parseInt(coords[0]);
- int z = Integer.parseInt(coords[1]);
- BlockVector2 pos = BlockVector2.at(x, z);
- min2D = (args.hasFlag('c')) ? pos : ChunkStore.toChunk(pos.toBlockVector3());
+ min2D = useChunkCoordinates
+ ? coordinates
+ : ChunkStore.toChunk(coordinates.toBlockVector3());
} else {
// use player loc
min2D = ChunkStore.toChunk(player.getBlockIn().toVector().toBlockPoint());
@@ -273,29 +243,21 @@ public class SelectionCommands {
}
@Command(
- aliases = { "/wand" },
- usage = "",
- desc = "Get the wand object",
- min = 0,
- max = 0
+ name = "/wand",
+ desc = "Get the wand object"
)
@CommandPermissions("worldedit.wand")
public void wand(Player player) throws WorldEditException {
-
player.giveItem(new BaseItemStack(ItemTypes.get(we.getConfiguration().wandItem), 1));
player.print("Left click: select pos #1; Right click: select pos #2");
}
@Command(
- aliases = { "toggleeditwand" },
- usage = "",
- desc = "Toggle functionality of the edit wand",
- min = 0,
- max = 0
+ name = "toggleeditwand",
+ desc = "Toggle functionality of the edit wand"
)
@CommandPermissions("worldedit.wand.toggle")
- public void toggleWand(Player player, LocalSession session, CommandContext args) throws WorldEditException {
-
+ public void toggleWand(Player player, LocalSession session) throws WorldEditException {
session.setToolControl(!session.isToolControlEnabled());
if (session.isToolControlEnabled()) {
@@ -306,20 +268,23 @@ public class SelectionCommands {
}
@Command(
- aliases = { "/expand" },
- usage = " [reverse-amount] ",
- desc = "Expand the selection area",
- min = 1,
- max = 3
+ name = "/expand",
+ desc = "Expand the selection area"
)
@Logging(REGION)
@CommandPermissions("worldedit.selection.expand")
- public void expand(Player player, LocalSession session, CommandContext args) throws WorldEditException {
+ public void expand(Player player, LocalSession session,
+ @Arg(desc = "Amount to expand the selection by, can be `vert` to expand to the whole vertical column")
+ ExpandAmount amount,
+ @Arg(desc = "Amount to expand the selection by in the other direction", def = "0")
+ int reverseAmount,
+ @Arg(desc = "Direction to expand", def = Direction.AIM)
+ @MultiDirection
+ List direction) throws WorldEditException {
// Special syntax (//expand vert) to expand the selection between
// sky and bedrock.
- if (args.getString(0).equalsIgnoreCase("vert")
- || args.getString(0).equalsIgnoreCase("vertical")) {
+ if (amount.isVert()) {
Region region = session.getSelection(player.getWorld());
try {
int oldSize = region.getArea();
@@ -338,57 +303,16 @@ public class SelectionCommands {
return;
}
- List dirs = new ArrayList<>();
- int change = args.getInteger(0);
- int reverseChange = 0;
-
- switch (args.argsLength()) {
- case 2:
- // Either a reverse amount or a direction
- try {
- reverseChange = args.getInteger(1);
- dirs.add(we.getDirection(player, "me"));
- } catch (NumberFormatException e) {
- if (args.getString(1).contains(",")) {
- String[] split = args.getString(1).split(",");
- for (String s : split) {
- dirs.add(we.getDirection(player, s.toLowerCase()));
- }
- } else {
- dirs.add(we.getDirection(player, args.getString(1).toLowerCase()));
- }
- }
- break;
-
- case 3:
- // Both reverse amount and direction
- reverseChange = args.getInteger(1);
- if (args.getString(2).contains(",")) {
- String[] split = args.getString(2).split(",");
- for (String s : split) {
- dirs.add(we.getDirection(player, s.toLowerCase()));
- }
- } else {
- dirs.add(we.getDirection(player, args.getString(2).toLowerCase()));
- }
- break;
-
- default:
- dirs.add(we.getDirection(player, "me"));
- break;
-
- }
-
Region region = session.getSelection(player.getWorld());
int oldSize = region.getArea();
- if (reverseChange == 0) {
- for (BlockVector3 dir : dirs) {
- region.expand(dir.multiply(change));
+ if (reverseAmount == 0) {
+ for (BlockVector3 dir : direction) {
+ region.expand(dir.multiply(amount.getAmount()));
}
} else {
- for (BlockVector3 dir : dirs) {
- region.expand(dir.multiply(change), dir.multiply(-reverseChange));
+ for (BlockVector3 dir : direction) {
+ region.expand(dir.multiply(amount.getAmount()), dir.multiply(-reverseAmount));
}
}
@@ -397,70 +321,33 @@ public class SelectionCommands {
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
- player.print("Region expanded " + (newSize - oldSize) + " blocks.");
+ player.print("Region expanded " + (newSize - oldSize) + " block(s).");
}
@Command(
- aliases = { "/contract" },
- usage = " [reverse-amount] [direction]",
- desc = "Contract the selection area",
- min = 1,
- max = 3
+ name = "/contract",
+ desc = "Contract the selection area"
)
@Logging(REGION)
@CommandPermissions("worldedit.selection.contract")
- public void contract(Player player, LocalSession session, CommandContext args) throws WorldEditException {
-
- List dirs = new ArrayList<>();
- int change = args.getInteger(0);
- int reverseChange = 0;
-
- switch (args.argsLength()) {
- case 2:
- // Either a reverse amount or a direction
- try {
- reverseChange = args.getInteger(1);
- dirs.add(we.getDirection(player, "me"));
- } catch (NumberFormatException e) {
- if (args.getString(1).contains(",")) {
- String[] split = args.getString(1).split(",");
- for (String s : split) {
- dirs.add(we.getDirection(player, s.toLowerCase()));
- }
- } else {
- dirs.add(we.getDirection(player, args.getString(1).toLowerCase()));
- }
- }
- break;
-
- case 3:
- // Both reverse amount and direction
- reverseChange = args.getInteger(1);
- if (args.getString(2).contains(",")) {
- String[] split = args.getString(2).split(",");
- for (String s : split) {
- dirs.add(we.getDirection(player, s.toLowerCase()));
- }
- } else {
- dirs.add(we.getDirection(player, args.getString(2).toLowerCase()));
- }
- break;
-
- default:
- dirs.add(we.getDirection(player, "me"));
- break;
- }
-
+ public void contract(Player player, LocalSession session,
+ @Arg(desc = "Amount to contract the selection by")
+ int amount,
+ @Arg(desc = "Amount to contract the selection by in the other direction", def = "0")
+ int reverseAmount,
+ @Arg(desc = "Direction to contract", def = Direction.AIM)
+ @MultiDirection
+ List direction) throws WorldEditException {
try {
Region region = session.getSelection(player.getWorld());
int oldSize = region.getArea();
- if (reverseChange == 0) {
- for (BlockVector3 dir : dirs) {
- region.contract(dir.multiply(change));
+ if (reverseAmount == 0) {
+ for (BlockVector3 dir : direction) {
+ region.contract(dir.multiply(amount));
}
} else {
- for (BlockVector3 dir : dirs) {
- region.contract(dir.multiply(change), dir.multiply(-reverseChange));
+ for (BlockVector3 dir : direction) {
+ region.contract(dir.multiply(amount), dir.multiply(-reverseAmount));
}
}
session.getRegionSelector(player.getWorld()).learnChanges();
@@ -476,35 +363,22 @@ public class SelectionCommands {
}
@Command(
- aliases = { "/shift" },
- usage = " [direction]",
- desc = "Shift the selection area",
- min = 1,
- max = 2
+ name = "/shift",
+ desc = "Shift the selection area"
)
@Logging(REGION)
@CommandPermissions("worldedit.selection.shift")
- public void shift(Player player, LocalSession session, CommandContext args) throws WorldEditException {
-
- List dirs = new ArrayList<>();
- int change = args.getInteger(0);
- if (args.argsLength() == 2) {
- if (args.getString(1).contains(",")) {
- for (String s : args.getString(1).split(",")) {
- dirs.add(we.getDirection(player, s.toLowerCase()));
- }
- } else {
- dirs.add(we.getDirection(player, args.getString(1).toLowerCase()));
- }
- } else {
- dirs.add(we.getDirection(player, "me"));
- }
-
+ public void shift(Player player, LocalSession session,
+ @Arg(desc = "Amount to shift the selection by")
+ int amount,
+ @Arg(desc = "Direction to contract", def = Direction.AIM)
+ @MultiDirection
+ List direction) throws WorldEditException {
try {
Region region = session.getSelection(player.getWorld());
- for (BlockVector3 dir : dirs) {
- region.shift(dir.multiply(change));
+ for (BlockVector3 dir : direction) {
+ region.shift(dir.multiply(amount));
}
session.getRegionSelector(player.getWorld()).learnChanges();
@@ -518,107 +392,92 @@ public class SelectionCommands {
}
@Command(
- aliases = { "/outset" },
- usage = "",
- desc = "Outset the selection area",
- help =
- "Expands the selection by the given amount in all directions.\n" +
- "Flags:\n" +
- " -h only expand horizontally\n" +
- " -v only expand vertically\n",
- flags = "hv",
- min = 1,
- max = 1
+ name = "/outset",
+ desc = "Outset the selection area"
)
@Logging(REGION)
@CommandPermissions("worldedit.selection.outset")
- public void outset(Player player, LocalSession session, CommandContext args) throws WorldEditException {
+ public void outset(Player player, LocalSession session,
+ @Arg(desc = "Amount to expand the selection by in all directions")
+ int amount,
+ @Switch(name = 'h', desc = "Only expand horizontally")
+ boolean onlyHorizontal,
+ @Switch(name = 'v', desc = "Only expand vertically")
+ boolean onlyVertical) throws WorldEditException {
Region region = session.getSelection(player.getWorld());
- region.expand(getChangesForEachDir(args));
+ region.expand(getChangesForEachDir(amount, onlyHorizontal, onlyVertical));
session.getRegionSelector(player.getWorld()).learnChanges();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
player.print("Region outset.");
}
@Command(
- aliases = { "/inset" },
- usage = "",
- desc = "Inset the selection area",
- help =
- "Contracts the selection by the given amount in all directions.\n" +
- "Flags:\n" +
- " -h only contract horizontally\n" +
- " -v only contract vertically\n",
- flags = "hv",
- min = 1,
- max = 1
+ name = "/inset",
+ desc = "Inset the selection area"
)
@Logging(REGION)
@CommandPermissions("worldedit.selection.inset")
- public void inset(Player player, LocalSession session, CommandContext args) throws WorldEditException {
+ public void inset(Player player, LocalSession session,
+ @Arg(desc = "Amount to contract the selection by in all directions")
+ int amount,
+ @Switch(name = 'h', desc = "Only contract horizontally")
+ boolean onlyHorizontal,
+ @Switch(name = 'v', desc = "Only contract vertically")
+ boolean onlyVertical) throws WorldEditException {
Region region = session.getSelection(player.getWorld());
- region.contract(getChangesForEachDir(args));
+ region.contract(getChangesForEachDir(amount, onlyHorizontal, onlyVertical));
session.getRegionSelector(player.getWorld()).learnChanges();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
player.print("Region inset.");
}
- private BlockVector3[] getChangesForEachDir(CommandContext args) {
- List changes = new ArrayList<>(6);
- int change = args.getInteger(0);
+ private BlockVector3[] getChangesForEachDir(int amount, boolean onlyHorizontal, boolean onlyVertical) {
+ Stream.Builder changes = Stream.builder();
- if (!args.hasFlag('h')) {
- changes.add((BlockVector3.UNIT_Y).multiply(change));
- changes.add((BlockVector3.UNIT_MINUS_Y).multiply(change));
+ if (!onlyHorizontal) {
+ changes.add(BlockVector3.UNIT_Y);
+ changes.add(BlockVector3.UNIT_MINUS_Y);
}
- if (!args.hasFlag('v')) {
- changes.add((BlockVector3.UNIT_X).multiply(change));
- changes.add((BlockVector3.UNIT_MINUS_X).multiply(change));
- changes.add((BlockVector3.UNIT_Z).multiply(change));
- changes.add((BlockVector3.UNIT_MINUS_Z).multiply(change));
+ if (!onlyVertical) {
+ changes.add(BlockVector3.UNIT_X);
+ changes.add(BlockVector3.UNIT_MINUS_X);
+ changes.add(BlockVector3.UNIT_Z);
+ changes.add(BlockVector3.UNIT_MINUS_Z);
}
- return changes.toArray(new BlockVector3[0]);
+ return changes.build().map(v -> v.multiply(amount)).toArray(BlockVector3[]::new);
}
@Command(
- aliases = { "/size" },
- flags = "c",
- usage = "",
- desc = "Get information about the selection",
- min = 0,
- max = 0
+ name = "/size",
+ desc = "Get information about the selection"
)
@CommandPermissions("worldedit.selection.size")
- public void size(Player player, LocalSession session, CommandContext args) throws WorldEditException {
- if (args.hasFlag('c')) {
+ public void size(Player player, LocalSession session,
+ @Switch(name = 'c', desc = "Get clipboard info instead")
+ boolean clipboardInfo) throws WorldEditException {
+ Region region;
+ if (clipboardInfo) {
ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard();
- Region region = clipboard.getRegion();
- BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint());
+ region = clipboard.getRegion();
+
BlockVector3 origin = clipboard.getOrigin();
-
- player.print("Cuboid dimensions (max - min): " + size);
player.print("Offset: " + origin);
- player.print("Cuboid distance: " + size.distance(BlockVector3.ONE));
- player.print("# of blocks: " + (int) (size.getX() * size.getY() * size.getZ()));
- return;
- }
+ } else {
+ region = session.getSelection(player.getWorld());
- Region region = session.getSelection(player.getWorld());
+ player.print("Type: " + session.getRegionSelector(player.getWorld()).getTypeName());
+
+ for (String line : session.getRegionSelector(player.getWorld()).getInformationLines()) {
+ player.print(line);
+ }
+ }
BlockVector3 size = region.getMaximumPoint()
.subtract(region.getMinimumPoint())
.add(1, 1, 1);
- player.print("Type: " + session.getRegionSelector(player.getWorld())
- .getTypeName());
-
- for (String line : session.getRegionSelector(player.getWorld())
- .getInformationLines()) {
- player.print(line);
- }
-
player.print("Size: " + size);
player.print("Cuboid distance: " + region.getMaximumPoint().distance(region.getMinimumPoint()));
player.print("# of blocks: " + region.getArea());
@@ -626,48 +485,41 @@ public class SelectionCommands {
@Command(
- aliases = { "/count" },
- usage = "",
- flags = "f",
- desc = "Counts the number of a certain type of block",
- min = 1,
- max = 1
+ name = "/count",
+ desc = "Counts the number of a certain type of block"
)
@CommandPermissions("worldedit.analysis.count")
- public void count(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
-
+ public void count(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The block type(s) to count")
+ String blocks,
+ @Switch(name = 'f', desc = "Fuzzy, match states using a wildcard")
+ boolean fuzzy) throws WorldEditException {
ParserContext context = new ParserContext();
context.setActor(player);
context.setExtent(player.getExtent());
context.setWorld(player.getWorld());
context.setSession(session);
context.setRestricted(false);
- context.setPreferringWildcard(args.hasFlag('f'));
+ context.setPreferringWildcard(fuzzy);
- Set searchBlocks = we.getBlockFactory().parseFromListInput(args.getString(0), context);
+ Set searchBlocks = we.getBlockFactory().parseFromListInput(blocks, context);
int count = editSession.countBlocks(session.getSelection(player.getWorld()), searchBlocks);
player.print("Counted: " + count);
}
@Command(
- aliases = { "/distr" },
- usage = "",
- desc = "Get the distribution of blocks in the selection",
- help =
- "Gets the distribution of blocks in the selection.\n" +
- "The -c flag gets the distribution of your clipboard.\n" +
- "The -d flag separates blocks by state",
- flags = "cd",
- min = 0,
- max = 0
+ name = "/distr",
+ desc = "Get the distribution of blocks in the selection"
)
@CommandPermissions("worldedit.analysis.distr")
- public void distr(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException, CommandException {
-
- boolean separateStates = args.hasFlag('d');
+ public void distr(Player player, LocalSession session, EditSession editSession,
+ @Switch(name = 'c', desc = "Get the distribution of the clipboard instead")
+ boolean clipboardDistr,
+ @Switch(name = 'd', desc = "Separate blocks by state")
+ boolean separateStates) throws WorldEditException {
List> distribution;
- if (args.hasFlag('c')) {
+ if (clipboardDistr) {
Clipboard clipboard = session.getClipboard().getClipboard(); // throws if missing
BlockDistributionCounter count = new BlockDistributionCounter(clipboard, separateStates);
RegionVisitor visitor = new RegionVisitor(clipboard.getRegion(), count);
@@ -707,72 +559,86 @@ public class SelectionCommands {
}
@Command(
- aliases = { "/sel", ";", "/desel", "/deselect" },
- flags = "d",
- usage = "[cuboid|extend|poly|ellipsoid|sphere|cyl|convex]",
- desc = "Choose a region selector",
- min = 0,
- max = 1
+ name = "/sel",
+ aliases = { ";", "/desel", "/deselect" },
+ desc = "Choose a region selector"
)
- public void select(Player player, LocalSession session, CommandContext args) throws WorldEditException {
+ public void select(Player player, LocalSession session,
+ @Arg(desc = "Selector to switch to", def = "")
+ SelectorChoice selector,
+ @Switch(name = 'd', desc = "Set default selector")
+ boolean setDefaultSelector) throws WorldEditException {
final World world = player.getWorld();
- if (args.argsLength() == 0) {
+ if (selector == null) {
session.getRegionSelector(world).clear();
session.dispatchCUISelection(player);
player.print("Selection cleared.");
return;
}
- final String typeName = args.getString(0);
final RegionSelector oldSelector = session.getRegionSelector(world);
- final RegionSelector selector;
- if (typeName.equalsIgnoreCase("cuboid")) {
- selector = new CuboidRegionSelector(oldSelector);
- player.print("Cuboid: left click for point 1, right click for point 2");
- } else if (typeName.equalsIgnoreCase("extend")) {
- selector = new ExtendingCuboidRegionSelector(oldSelector);
- player.print("Cuboid: left click for a starting point, right click to extend");
- } else if (typeName.equalsIgnoreCase("poly")) {
- selector = new Polygonal2DRegionSelector(oldSelector);
- player.print("2D polygon selector: Left/right click to add a point.");
- Optional limit = ActorSelectorLimits.forActor(player).getPolygonVertexLimit();
- limit.ifPresent(integer -> player.print(integer + " points maximum."));
- } else if (typeName.equalsIgnoreCase("ellipsoid")) {
- selector = new EllipsoidRegionSelector(oldSelector);
- player.print("Ellipsoid selector: left click=center, right click to extend");
- } else if (typeName.equalsIgnoreCase("sphere")) {
- selector = new SphereRegionSelector(oldSelector);
- player.print("Sphere selector: left click=center, right click to set radius");
- } else if (typeName.equalsIgnoreCase("cyl")) {
- selector = new CylinderRegionSelector(oldSelector);
- player.print("Cylindrical selector: Left click=center, right click to extend.");
- } else if (typeName.equalsIgnoreCase("convex") || typeName.equalsIgnoreCase("hull") || typeName.equalsIgnoreCase("polyhedron")) {
- selector = new ConvexPolyhedralRegionSelector(oldSelector);
- player.print("Convex polyhedral selector: Left click=First vertex, right click to add more.");
- Optional limit = ActorSelectorLimits.forActor(player).getPolyhedronVertexLimit();
- limit.ifPresent(integer -> player.print(integer + " points maximum."));
- } else {
- CommandListBox box = new CommandListBox("Selection modes");
- TextComponentProducer contents = box.getContents();
- contents.append(SubtleFormat.wrap("Select one of the modes below:")).newline();
+ final RegionSelector newSelector;
+ switch (selector) {
+ case CUBOID:
+ newSelector = new CuboidRegionSelector(oldSelector);
+ player.print("Cuboid: left click for point 1, right click for point 2");
+ break;
+ case EXTEND:
+ newSelector = new ExtendingCuboidRegionSelector(oldSelector);
+ player.print("Cuboid: left click for a starting point, right click to extend");
+ break;
+ case POLY: {
+ newSelector = new Polygonal2DRegionSelector(oldSelector);
+ player.print("2D polygon selector: Left/right click to add a point.");
+ Optional limit = ActorSelectorLimits.forActor(player).getPolygonVertexLimit();
+ limit.ifPresent(integer -> player.print(integer + " points maximum."));
+ break;
+ }
+ case ELLIPSOID:
+ newSelector = new EllipsoidRegionSelector(oldSelector);
+ player.print("Ellipsoid selector: left click=center, right click to extend");
+ break;
+ case SPHERE:
+ newSelector = new SphereRegionSelector(oldSelector);
+ player.print("Sphere selector: left click=center, right click to set radius");
+ break;
+ case CYL:
+ newSelector = new CylinderRegionSelector(oldSelector);
+ player.print("Cylindrical selector: Left click=center, right click to extend.");
+ break;
+ case CONVEX:
+ case HULL:
+ case POLYHEDRON: {
+ newSelector = new ConvexPolyhedralRegionSelector(oldSelector);
+ player.print("Convex polyhedral selector: Left click=First vertex, right click to add more.");
+ Optional limit = ActorSelectorLimits.forActor(player).getPolyhedronVertexLimit();
+ limit.ifPresent(integer -> player.print(integer + " points maximum."));
+ break;
+ }
+ case UNKNOWN:
+ default:
+ CommandListBox box = new CommandListBox("Selection modes", null);
+ box.setHidingHelp(true);
+ TextComponentProducer contents = box.getContents();
+ contents.append(SubtleFormat.wrap("Select one of the modes below:")).newline();
- box.appendCommand("cuboid", "Select two corners of a cuboid", "//sel cuboid");
- box.appendCommand("extend", "Fast cuboid selection mode", "//sel extend");
- box.appendCommand("poly", "Select a 2D polygon with height", "//sel poly");
- box.appendCommand("ellipsoid", "Select an ellipsoid", "//sel ellipsoid");
- box.appendCommand("sphere", "Select a sphere", "//sel sphere");
- box.appendCommand("cyl", "Select a cylinder", "//sel cyl");
- box.appendCommand("convex", "Select a convex polyhedral", "//sel convex");
+ box.appendCommand("cuboid", "Select two corners of a cuboid", "//sel cuboid");
+ box.appendCommand("extend", "Fast cuboid selection mode", "//sel extend");
+ box.appendCommand("poly", "Select a 2D polygon with height", "//sel poly");
+ box.appendCommand("ellipsoid", "Select an ellipsoid", "//sel ellipsoid");
+ box.appendCommand("sphere", "Select a sphere", "//sel sphere");
+ box.appendCommand("cyl", "Select a cylinder", "//sel cyl");
+ box.appendCommand("convex", "Select a convex polyhedral", "//sel convex");
- player.print(box.create());
- return;
+ player.print(box.create(1));
+ return;
}
- if (args.hasFlag('d')) {
+ if (setDefaultSelector) {
RegionSelectorType found = null;
for (RegionSelectorType type : RegionSelectorType.values()) {
- if (type.getSelectorClass() == selector.getClass()) {
+ if (type.getSelectorClass() == newSelector.getClass()) {
found = type;
break;
}
@@ -786,7 +652,7 @@ public class SelectionCommands {
}
}
- session.setRegionSelector(world, selector);
+ session.setRegionSelector(world, newSelector);
session.dispatchCUISelection(player);
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java
index 1c4987734..643b064b1 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java
@@ -21,32 +21,34 @@
package com.sk89q.worldedit.command;
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandContext;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.world.snapshot.InvalidSnapshotException;
import com.sk89q.worldedit.world.snapshot.Snapshot;
import com.sk89q.worldedit.world.storage.MissingWorldException;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
import java.io.File;
import java.io.IOException;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
import java.util.List;
/**
* Snapshot commands.
*/
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class SnapshotCommands {
- private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
-
+ private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z");
+
private final WorldEdit we;
public SnapshotCommands(WorldEdit we) {
@@ -54,14 +56,13 @@ public class SnapshotCommands {
}
@Command(
- aliases = { "list" },
- usage = "[num]",
- desc = "List snapshots",
- min = 0,
- max = 1
+ name = "list",
+ desc = "List snapshots"
)
@CommandPermissions("worldedit.snapshots.list")
- public void list(Player player, CommandContext args) throws WorldEditException {
+ public void list(Player player,
+ @Arg(desc = "# of snapshots to list", def = "5")
+ int num) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
@@ -75,7 +76,7 @@ public class SnapshotCommands {
if (!snapshots.isEmpty()) {
- int num = args.argsLength() > 0 ? Math.min(40, Math.max(5, args.getInteger(0))) : 5;
+ num = Math.min(40, Math.max(5, num));
player.print("Snapshots for world: '" + player.getWorld().getName() + "'");
for (byte i = 0; i < Math.min(num, snapshots.size()); i++) {
@@ -104,14 +105,13 @@ public class SnapshotCommands {
}
@Command(
- aliases = { "use" },
- usage = "",
- desc = "Choose a snapshot to use",
- min = 1,
- max = 1
+ name = "use",
+ desc = "Choose a snapshot to use"
)
@CommandPermissions("worldedit.snapshots.restore")
- public void use(Player player, LocalSession session, CommandContext args) throws WorldEditException {
+ public void use(Player player, LocalSession session,
+ @Arg(desc = "Snapeshot to use")
+ String name) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
@@ -120,8 +120,6 @@ public class SnapshotCommands {
return;
}
- String name = args.getString(0);
-
// Want the latest snapshot?
if (name.equalsIgnoreCase("latest")) {
try {
@@ -147,14 +145,13 @@ public class SnapshotCommands {
}
@Command(
- aliases = { "sel" },
- usage = "",
- desc = "Choose the snapshot based on the list id",
- min = 1,
- max = 1
+ name = "sel",
+ desc = "Choose the snapshot based on the list id"
)
@CommandPermissions("worldedit.snapshots.restore")
- public void sel(Player player, LocalSession session, CommandContext args) throws WorldEditException {
+ public void sel(Player player, LocalSession session,
+ @Arg(desc = "The list ID to select")
+ int index) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
if (config.snapshotRepo == null) {
@@ -162,14 +159,6 @@ public class SnapshotCommands {
return;
}
- int index = -1;
- try {
- index = Integer.parseInt(args.getString(0));
- } catch (NumberFormatException e) {
- player.printError("Invalid index, " + args.getString(0) + " is not a valid integer.");
- return;
- }
-
if (index < 1) {
player.printError("Invalid index, must be equal or higher then 1.");
return;
@@ -194,14 +183,13 @@ public class SnapshotCommands {
}
@Command(
- aliases = { "before" },
- usage = "",
- desc = "Choose the nearest snapshot before a date",
- min = 1,
- max = -1
+ name = "before",
+ desc = "Choose the nearest snapshot before a date"
)
@CommandPermissions("worldedit.snapshots.restore")
- public void before(Player player, LocalSession session, CommandContext args) throws WorldEditException {
+ public void before(Player player, LocalSession session,
+ @Arg(desc = "The soonest date that may be used")
+ ZonedDateTime date) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
@@ -210,37 +198,29 @@ public class SnapshotCommands {
return;
}
- Calendar date = session.detectDate(args.getJoinedStrings(0));
+ try {
+ Snapshot snapshot = config.snapshotRepo.getSnapshotBefore(date, player.getWorld().getName());
- if (date == null) {
- player.printError("Could not detect the date inputted.");
- } else {
- try {
- Snapshot snapshot = config.snapshotRepo.getSnapshotBefore(date, player.getWorld().getName());
-
- if (snapshot == null) {
- dateFormat.setTimeZone(session.getTimeZone());
- player.printError("Couldn't find a snapshot before "
- + dateFormat.format(date.getTime()) + ".");
- } else {
- session.setSnapshot(snapshot);
- player.print("Snapshot set to: " + snapshot.getName());
- }
- } catch (MissingWorldException ex) {
- player.printError("No snapshots were found for this world.");
+ if (snapshot == null) {
+ player.printError("Couldn't find a snapshot before "
+ + dateFormat.withZone(session.getTimeZone()).format(date) + ".");
+ } else {
+ session.setSnapshot(snapshot);
+ player.print("Snapshot set to: " + snapshot.getName());
}
+ } catch (MissingWorldException ex) {
+ player.printError("No snapshots were found for this world.");
}
}
@Command(
- aliases = { "after" },
- usage = "",
- desc = "Choose the nearest snapshot after a date",
- min = 1,
- max = -1
+ name = "after",
+ desc = "Choose the nearest snapshot after a date"
)
@CommandPermissions("worldedit.snapshots.restore")
- public void after(Player player, LocalSession session, CommandContext args) throws WorldEditException {
+ public void after(Player player, LocalSession session,
+ @Arg(desc = "The soonest date that may be used")
+ ZonedDateTime date) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
@@ -249,24 +229,17 @@ public class SnapshotCommands {
return;
}
- Calendar date = session.detectDate(args.getJoinedStrings(0));
-
- if (date == null) {
- player.printError("Could not detect the date inputted.");
- } else {
- try {
- Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date, player.getWorld().getName());
- if (snapshot == null) {
- dateFormat.setTimeZone(session.getTimeZone());
- player.printError("Couldn't find a snapshot after "
- + dateFormat.format(date.getTime()) + ".");
- } else {
- session.setSnapshot(snapshot);
- player.print("Snapshot set to: " + snapshot.getName());
- }
- } catch (MissingWorldException ex) {
- player.printError("No snapshots were found for this world.");
+ try {
+ Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date, player.getWorld().getName());
+ if (snapshot == null) {
+ player.printError("Couldn't find a snapshot after "
+ + dateFormat.withZone(session.getTimeZone()).format(date) + ".");
+ } else {
+ session.setSnapshot(snapshot);
+ player.print("Snapshot set to: " + snapshot.getName());
}
+ } catch (MissingWorldException ex) {
+ player.printError("No snapshots were found for this world.");
}
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java
index 51c5695e5..14a90e2fe 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java
@@ -19,15 +19,14 @@
package com.sk89q.worldedit.command;
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandContext;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
-import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
+import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.DataException;
@@ -36,12 +35,16 @@ import com.sk89q.worldedit.world.snapshot.Snapshot;
import com.sk89q.worldedit.world.snapshot.SnapshotRestore;
import com.sk89q.worldedit.world.storage.ChunkStore;
import com.sk89q.worldedit.world.storage.MissingWorldException;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
import java.io.File;
import java.io.IOException;
-import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION;
+import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class SnapshotUtilCommands {
private final WorldEdit we;
@@ -51,15 +54,15 @@ public class SnapshotUtilCommands {
}
@Command(
- aliases = { "restore", "/restore" },
- usage = "[snapshot]",
- desc = "Restore the selection from a snapshot",
- min = 0,
- max = 1
+ name = "restore",
+ aliases = { "/restore" },
+ desc = "Restore the selection from a snapshot"
)
@Logging(REGION)
@CommandPermissions("worldedit.snapshots.restore")
- public void restore(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
+ public void restore(Player player, LocalSession session, EditSession editSession,
+ @Arg(name = "snapshot", desc = "The snapshot to restore", def = "")
+ String snapshotName) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
@@ -71,9 +74,9 @@ public class SnapshotUtilCommands {
Region region = session.getSelection(player.getWorld());
Snapshot snapshot;
- if (args.argsLength() > 0) {
+ if (snapshotName != null) {
try {
- snapshot = config.snapshotRepo.getSnapshot(args.getString(0));
+ snapshot = config.snapshotRepo.getSnapshot(snapshotName);
} catch (InvalidSnapshotException e) {
player.printError("That snapshot does not exist or is not available.");
return;
@@ -110,7 +113,7 @@ public class SnapshotUtilCommands {
}
}
- ChunkStore chunkStore = null;
+ ChunkStore chunkStore;
// Load chunk store
try {
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java
index a3e21db8a..754473a9a 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java
@@ -19,9 +19,6 @@
package com.sk89q.worldedit.command;
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandContext;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
@@ -29,8 +26,14 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.tool.AreaPickaxe;
import com.sk89q.worldedit.command.tool.RecursivePickaxe;
import com.sk89q.worldedit.command.tool.SinglePickaxe;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.entity.Player;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class SuperPickaxeCommands {
private final WorldEdit we;
@@ -39,32 +42,26 @@ public class SuperPickaxeCommands {
}
@Command(
- aliases = { "single" },
- usage = "",
- desc = "Enable the single block super pickaxe mode",
- min = 0,
- max = 0
+ name = "single",
+ desc = "Enable the single block super pickaxe mode"
)
@CommandPermissions("worldedit.superpickaxe")
public void single(Player player, LocalSession session) throws WorldEditException {
-
session.setSuperPickaxe(new SinglePickaxe());
session.enableSuperPickAxe();
player.print("Mode changed. Left click with a pickaxe. // to disable.");
}
@Command(
- aliases = { "area" },
- usage = "",
- desc = "Enable the area super pickaxe pickaxe mode",
- min = 1,
- max = 1
+ name = "area",
+ desc = "Enable the area super pickaxe pickaxe mode"
)
@CommandPermissions("worldedit.superpickaxe.area")
- public void area(Player player, LocalSession session, CommandContext args) throws WorldEditException {
+ public void area(Player player, LocalSession session,
+ @Arg(desc = "The range of the area pickaxe")
+ int range) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
- int range = args.getInteger(0);
if (range > config.maxSuperPickaxeSize) {
player.printError("Maximum range: " + config.maxSuperPickaxeSize);
@@ -77,17 +74,16 @@ public class SuperPickaxeCommands {
}
@Command(
- aliases = { "recur", "recursive" },
- usage = "",
- desc = "Enable the recursive super pickaxe pickaxe mode",
- min = 1,
- max = 1
+ name = "recursive",
+ aliases = { "recur" },
+ desc = "Enable the recursive super pickaxe pickaxe mode"
)
@CommandPermissions("worldedit.superpickaxe.recursive")
- public void recursive(Player player, LocalSession session, CommandContext args) throws WorldEditException {
+ public void recursive(Player player, LocalSession session,
+ @Arg(desc = "The range of the recursive pickaxe")
+ double range) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
- double range = args.getDouble(0);
if (range > config.maxSuperPickaxeSize) {
player.printError("Maximum range: " + config.maxSuperPickaxeSize);
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java
index c61c2fc92..8242cfec9 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java
@@ -19,9 +19,6 @@
package com.sk89q.worldedit.command;
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandContext;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
@@ -35,12 +32,18 @@ import com.sk89q.worldedit.command.tool.FloodFillTool;
import com.sk89q.worldedit.command.tool.LongRangeBuildTool;
import com.sk89q.worldedit.command.tool.QueryTool;
import com.sk89q.worldedit.command.tool.TreePlanter;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.TreeGenerator;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ToolCommands {
private final WorldEdit we;
@@ -49,11 +52,8 @@ public class ToolCommands {
}
@Command(
- aliases = { "none" },
- usage = "",
- desc = "Unbind a bound tool from your current item",
- min = 0,
- max = 0
+ name = "none",
+ desc = "Unbind a bound tool from your current item"
)
public void none(Player player, LocalSession session) throws WorldEditException {
@@ -62,11 +62,8 @@ public class ToolCommands {
}
@Command(
- aliases = { "info" },
- usage = "",
- desc = "Block information tool",
- min = 0,
- max = 0
+ name = "info",
+ desc = "Block information tool"
)
@CommandPermissions("worldedit.tool.info")
public void info(Player player, LocalSession session) throws WorldEditException {
@@ -78,49 +75,34 @@ public class ToolCommands {
}
@Command(
- aliases = { "tree" },
- usage = "[type]",
- desc = "Tree generator tool",
- min = 0,
- max = 1
+ name = "tree",
+ desc = "Tree generator tool"
)
@CommandPermissions("worldedit.tool.tree")
- public void tree(Player player, LocalSession session, CommandContext args) throws WorldEditException {
-
- TreeGenerator.TreeType type = args.argsLength() > 0
- ? TreeGenerator.lookup(args.getString(0))
- : TreeGenerator.TreeType.TREE;
-
- if (type == null) {
- player.printError("Tree type '" + args.getString(0) + "' is unknown.");
- return;
- }
-
+ public void tree(Player player, LocalSession session,
+ @Arg(desc = "Type of tree to generate", def = "tree")
+ TreeGenerator.TreeType type) throws WorldEditException {
BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(itemStack.getType(), new TreePlanter(type));
player.print("Tree tool bound to " + itemStack.getType().getName() + ".");
}
@Command(
- aliases = { "repl" },
- usage = "",
- desc = "Block replacer tool",
- min = 1,
- max = 1
+ name = "repl",
+ desc = "Block replacer tool"
)
@CommandPermissions("worldedit.tool.replacer")
- public void repl(Player player, LocalSession session, Pattern pattern) throws WorldEditException {
+ public void repl(Player player, LocalSession session,
+ @Arg(desc = "The pattern of blocks to place")
+ Pattern pattern) throws WorldEditException {
BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(itemStack.getType(), new BlockReplacer(pattern));
player.print("Block replacer tool bound to " + itemStack.getType().getName() + ".");
}
@Command(
- aliases = { "cycler" },
- usage = "",
- desc = "Block data cycler tool",
- min = 0,
- max = 0
+ name = "cycler",
+ desc = "Block data cycler tool"
)
@CommandPermissions("worldedit.tool.data-cycler")
public void cycler(Player player, LocalSession session) throws WorldEditException {
@@ -131,14 +113,16 @@ public class ToolCommands {
}
@Command(
- aliases = { "floodfill", "flood" },
- usage = " ",
- desc = "Flood fill tool",
- min = 2,
- max = 2
+ name = "floodfill",
+ aliases = { "flood" },
+ desc = "Flood fill tool"
)
@CommandPermissions("worldedit.tool.flood-fill")
- public void floodFill(Player player, LocalSession session, Pattern pattern, int range) throws WorldEditException {
+ public void floodFill(Player player, LocalSession session,
+ @Arg(desc = "The pattern to flood fill")
+ Pattern pattern,
+ @Arg(desc = "The range to perform the fill")
+ int range) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
@@ -153,11 +137,8 @@ public class ToolCommands {
}
@Command(
- aliases = { "deltree" },
- usage = "",
- desc = "Floating tree remover tool",
- min = 0,
- max = 0
+ name = "deltree",
+ desc = "Floating tree remover tool"
)
@CommandPermissions("worldedit.tool.deltree")
public void deltree(Player player, LocalSession session) throws WorldEditException {
@@ -169,11 +150,8 @@ public class ToolCommands {
}
@Command(
- aliases = { "farwand" },
- usage = "",
- desc = "Wand at a distance tool",
- min = 0,
- max = 0
+ name = "farwand",
+ desc = "Wand at a distance tool"
)
@CommandPermissions("worldedit.tool.farwand")
public void farwand(Player player, LocalSession session) throws WorldEditException {
@@ -184,14 +162,16 @@ public class ToolCommands {
}
@Command(
- aliases = { "lrbuild", "/lrbuild" },
- usage = " ",
- desc = "Long-range building tool",
- min = 2,
- max = 2
+ name = "lrbuild",
+ aliases = { "/lrbuild" },
+ desc = "Long-range building tool"
)
@CommandPermissions("worldedit.tool.lrbuild")
- public void longrangebuildtool(Player player, LocalSession session, Pattern secondary, Pattern primary) throws WorldEditException {
+ public void longrangebuildtool(Player player, LocalSession session,
+ @Arg(desc = "Block to set on left-click")
+ Pattern primary,
+ @Arg(desc = "Block to set on right-click")
+ Pattern secondary) throws WorldEditException {
BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(itemStack.getType(), new LongRangeBuildTool(primary, secondary));
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java
index df1637880..e053eccb8 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java
@@ -19,21 +19,23 @@
package com.sk89q.worldedit.command;
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandContext;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.util.HandSide;
-import com.sk89q.worldedit.util.command.parametric.Optional;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
/**
* Tool commands.
*/
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ToolUtilCommands {
private final WorldEdit we;
@@ -42,44 +44,37 @@ public class ToolUtilCommands {
}
@Command(
- aliases = { "/", "," },
- usage = "[on|off]",
- desc = "Toggle the super pickaxe function",
- min = 0,
- max = 1
+ name = "/",
+ aliases = { "," },
+ desc = "Toggle the super pickaxe function"
)
@CommandPermissions("worldedit.superpickaxe")
- public void togglePickaxe(Player player, LocalSession session, CommandContext args) throws WorldEditException {
-
- String newState = args.getString(0, null);
- if (session.hasSuperPickAxe()) {
- if ("on".equals(newState)) {
- player.printError("Super pick axe already enabled.");
- return;
- }
-
+ public void togglePickaxe(Player player, LocalSession session,
+ @Arg(desc = "The new super pickaxe state", def = "")
+ Boolean superPickaxe) throws WorldEditException {
+ boolean hasSuperPickAxe = session.hasSuperPickAxe();
+ if (superPickaxe != null && superPickaxe == hasSuperPickAxe) {
+ player.printError("Super pickaxe already " + (superPickaxe ? "enabled" : "disabled") + ".");
+ return;
+ }
+ if (hasSuperPickAxe) {
session.disableSuperPickAxe();
- player.print("Super pick axe disabled.");
+ player.print("Super pickaxe disabled.");
} else {
- if ("off".equals(newState)) {
- player.printError("Super pick axe already disabled.");
- return;
- }
session.enableSuperPickAxe();
- player.print("Super pick axe enabled.");
+ player.print("Super pickaxe enabled.");
}
}
@Command(
- aliases = { "mask" },
- usage = "[mask]",
- desc = "Set the brush mask",
- min = 0,
- max = -1
+ name = "mask",
+ desc = "Set the brush mask"
)
@CommandPermissions("worldedit.brush.options.mask")
- public void mask(Player player, LocalSession session, @Optional Mask mask) throws WorldEditException {
+ public void mask(Player player, LocalSession session,
+ @Arg(desc = "The mask to set", def = "")
+ Mask mask) throws WorldEditException {
if (mask == null) {
session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setMask(null);
player.print("Brush mask disabled.");
@@ -90,46 +85,41 @@ public class ToolUtilCommands {
}
@Command(
- aliases = { "mat", "material" },
- usage = "[pattern]",
- desc = "Set the brush material",
- min = 1,
- max = 1
+ name = "material",
+ aliases = { "/material" },
+ desc = "Set the brush material"
)
@CommandPermissions("worldedit.brush.options.material")
- public void material(Player player, LocalSession session, Pattern pattern) throws WorldEditException {
+ public void material(Player player, LocalSession session,
+ @Arg(desc = "The pattern of blocks to use")
+ Pattern pattern) throws WorldEditException {
session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setFill(pattern);
player.print("Brush material set.");
}
@Command(
- aliases = { "range" },
- usage = "[pattern]",
- desc = "Set the brush range",
- min = 1,
- max = 1
- )
+ name = "range",
+ desc = "Set the brush range"
+ )
@CommandPermissions("worldedit.brush.options.range")
- public void range(Player player, LocalSession session, CommandContext args) throws WorldEditException {
- int range = args.getInteger(0);
+ public void range(Player player, LocalSession session,
+ @Arg(desc = "The range of the brush")
+ int range) throws WorldEditException {
session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setRange(range);
player.print("Brush range set.");
}
@Command(
- aliases = { "size" },
- usage = "[pattern]",
- desc = "Set the brush size",
- min = 1,
- max = 1
+ name = "size",
+ desc = "Set the brush size"
)
@CommandPermissions("worldedit.brush.options.size")
- public void size(Player player, LocalSession session, CommandContext args) throws WorldEditException {
+ public void size(Player player, LocalSession session,
+ @Arg(desc = "The size of the brush")
+ int size) throws WorldEditException {
+ we.checkMaxBrushRadius(size);
- int radius = args.getInteger(0);
- we.checkMaxBrushRadius(radius);
-
- session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setSize(radius);
+ session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setSize(size);
player.print("Brush size set.");
}
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java
index 2e2defc19..0e18dbcbd 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java
@@ -19,30 +19,31 @@
package com.sk89q.worldedit.command;
-import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT;
+import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT;
-import com.google.common.base.Joiner;
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandContext;
-import com.sk89q.minecraft.util.commands.CommandException;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
-import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.EditSession;
+import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
+import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.CreatureButcher;
import com.sk89q.worldedit.command.util.EntityRemover;
+import com.sk89q.worldedit.command.util.Logging;
+import com.sk89q.worldedit.command.util.PrintCommandHelp;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.Player;
-import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
-import com.sk89q.worldedit.extension.platform.CommandManager;
import com.sk89q.worldedit.extension.platform.Platform;
+import com.sk89q.worldedit.function.EntityFunction;
+import com.sk89q.worldedit.function.mask.BlockTypeMask;
+import com.sk89q.worldedit.function.mask.ExistingBlockMask;
+import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.Operations;
-import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.EntityVisitor;
import com.sk89q.worldedit.internal.expression.Expression;
@@ -52,32 +53,27 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.CylinderRegion;
import com.sk89q.worldedit.regions.Region;
-import com.sk89q.worldedit.session.SessionOwner;
-import com.sk89q.worldedit.util.command.CommandCallable;
-import com.sk89q.worldedit.util.command.CommandMapping;
-import com.sk89q.worldedit.util.command.Dispatcher;
-import com.sk89q.worldedit.util.command.PrimaryAliasComparator;
-import com.sk89q.worldedit.util.command.binding.Text;
-import com.sk89q.worldedit.util.formatting.component.CodeFormat;
-import com.sk89q.worldedit.util.formatting.component.CommandListBox;
-import com.sk89q.worldedit.util.formatting.component.CommandUsageBox;
-import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
-import com.sk89q.worldedit.util.formatting.component.TextComponentProducer;
-import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.World;
-import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockTypes;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
+import org.enginehub.piston.annotation.param.Switch;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
+import java.util.Locale;
+import java.util.function.Supplier;
/**
* Utility commands.
*/
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class UtilityCommands {
private final WorldEdit we;
@@ -87,357 +83,365 @@ public class UtilityCommands {
}
@Command(
- aliases = { "/fill" },
- usage = " [depth]",
- desc = "Fill a hole",
- min = 2,
- max = 3
+ name = "/fill",
+ desc = "Fill a hole"
)
@CommandPermissions("worldedit.fill")
@Logging(PLACEMENT)
- public void fill(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
-
- ParserContext context = new ParserContext();
- context.setActor(player);
- context.setWorld(player.getWorld());
- context.setSession(session);
- Pattern pattern = we.getPatternFactory().parseFromInput(args.getString(0), context);
-
- double radius = Math.max(1, args.getDouble(1));
+ public int fill(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The blocks to fill with")
+ Pattern pattern,
+ @Arg(desc = "The radius to fill in")
+ double radius,
+ @Arg(desc = "The depth to fill", def = "1")
+ int depth) throws WorldEditException {
+ radius = Math.max(1, radius);
we.checkMaxRadius(radius);
- int depth = args.argsLength() > 2 ? Math.max(1, args.getInteger(2)) : 1;
+ depth = Math.max(1, depth);
BlockVector3 pos = session.getPlacementPosition(player);
int affected = editSession.fillXZ(pos, pattern, radius, depth, false);
player.print(affected + " block(s) have been created.");
+ return affected;
}
@Command(
- aliases = { "/fillr" },
- usage = " [depth]",
- desc = "Fill a hole recursively",
- min = 2,
- max = 3
+ name = "/fillr",
+ desc = "Fill a hole recursively"
)
@CommandPermissions("worldedit.fill.recursive")
@Logging(PLACEMENT)
- public void fillr(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
-
- ParserContext context = new ParserContext();
- context.setActor(player);
- context.setWorld(player.getWorld());
- context.setSession(session);
- Pattern pattern = we.getPatternFactory().parseFromInput(args.getString(0), context);
-
- double radius = Math.max(1, args.getDouble(1));
+ public int fillr(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The blocks to fill with")
+ Pattern pattern,
+ @Arg(desc = "The radius to fill in")
+ double radius,
+ @Arg(desc = "The depth to fill", def = "")
+ Integer depth) throws WorldEditException {
+ radius = Math.max(1, radius);
+ we.checkMaxRadius(radius);
+ depth = depth == null ? Integer.MAX_VALUE : Math.max(1, depth);
we.checkMaxRadius(radius);
- int depth = args.argsLength() > 2 ? Math.max(1, args.getInteger(2)) : Integer.MAX_VALUE;
BlockVector3 pos = session.getPlacementPosition(player);
- int affected = 0;
- if (pattern instanceof BlockPattern) {
- affected = editSession.fillXZ(pos, ((BlockPattern) pattern).getBlock(), radius, depth, true);
- } else {
- affected = editSession.fillXZ(pos, pattern, radius, depth, true);
- }
+ int affected = editSession.fillXZ(pos, pattern, radius, depth, true);
player.print(affected + " block(s) have been created.");
+ return affected;
}
@Command(
- aliases = { "/drain" },
- usage = "",
- flags = "w",
- desc = "Drain a pool",
- help = "Removes all connected water sources.\n" +
- " If -w is specified, also makes waterlogged blocks non-waterlogged.",
- min = 1,
- max = 1
+ name = "/drain",
+ desc = "Drain a pool"
)
@CommandPermissions("worldedit.drain")
@Logging(PLACEMENT)
- public void drain(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
-
- double radius = Math.max(0, args.getDouble(0));
- boolean waterlogged = args.hasFlag('w');
+ public int drain(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The radius to drain")
+ double radius,
+ @Switch(name = 'w', desc = "Also un-waterlog blocks")
+ boolean waterlogged) throws WorldEditException {
+ radius = Math.max(0, radius);
we.checkMaxRadius(radius);
int affected = editSession.drainArea(
- session.getPlacementPosition(player), radius, waterlogged);
+ session.getPlacementPosition(player), radius, waterlogged);
player.print(affected + " block(s) have been changed.");
+ return affected;
}
@Command(
- aliases = { "/fixlava", "fixlava" },
- usage = "",
- desc = "Fix lava to be stationary",
- min = 1,
- max = 1
+ name = "fixlava",
+ aliases = { "/fixlava" },
+ desc = "Fix lava to be stationary"
)
@CommandPermissions("worldedit.fixlava")
@Logging(PLACEMENT)
- public void fixLava(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
-
- double radius = Math.max(0, args.getDouble(0));
+ public int fixLava(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The radius to fix in")
+ double radius) throws WorldEditException {
+ radius = Math.max(0, radius);
we.checkMaxRadius(radius);
int affected = editSession.fixLiquid(session.getPlacementPosition(player), radius, BlockTypes.LAVA);
player.print(affected + " block(s) have been changed.");
+ return affected;
}
@Command(
- aliases = { "/fixwater", "fixwater" },
- usage = "",
- desc = "Fix water to be stationary",
- min = 1,
- max = 1
+ name = "fixwater",
+ aliases = { "/fixwater" },
+ desc = "Fix water to be stationary"
)
@CommandPermissions("worldedit.fixwater")
@Logging(PLACEMENT)
- public void fixWater(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
-
- double radius = Math.max(0, args.getDouble(0));
+ public int fixWater(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The radius to fix in")
+ double radius) throws WorldEditException {
+ radius = Math.max(0, radius);
we.checkMaxRadius(radius);
int affected = editSession.fixLiquid(session.getPlacementPosition(player), radius, BlockTypes.WATER);
player.print(affected + " block(s) have been changed.");
+ return affected;
}
@Command(
- aliases = { "/removeabove", "removeabove" },
- usage = "[size] [height]",
- desc = "Remove blocks above your head.",
- min = 0,
- max = 2
+ name = "removeabove",
+ aliases = { "/removeabove" },
+ desc = "Remove blocks above your head."
)
@CommandPermissions("worldedit.removeabove")
@Logging(PLACEMENT)
- public void removeAbove(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
-
- int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 1;
+ public int removeAbove(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The apothem of the square to remove from", def = "1")
+ int size,
+ @Arg(desc = "The maximum height above you to remove from", def = "")
+ Integer height) throws WorldEditException {
+ size = Math.max(1, size);
we.checkMaxRadius(size);
World world = player.getWorld();
- int height = args.argsLength() > 1 ? Math.min((world.getMaxY() + 1), args.getInteger(1) + 2) : (world.getMaxY() + 1);
+ height = height != null ? Math.min((world.getMaxY() + 1), height + 2) : (world.getMaxY() + 1);
int affected = editSession.removeAbove(
- session.getPlacementPosition(player), size, height);
+ session.getPlacementPosition(player), size, height);
player.print(affected + " block(s) have been removed.");
+ return affected;
}
@Command(
- aliases = { "/removebelow", "removebelow" },
- usage = "[size] [height]",
- desc = "Remove blocks below you.",
- min = 0,
- max = 2
+ name = "removebelow",
+ aliases = { "/removebelow" },
+ desc = "Remove blocks below you."
)
@CommandPermissions("worldedit.removebelow")
@Logging(PLACEMENT)
- public void removeBelow(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
-
- int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 1;
+ public int removeBelow(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The apothem of the square to remove from", def = "1")
+ int size,
+ @Arg(desc = "The maximum height below you to remove from", def = "")
+ Integer height) throws WorldEditException {
+ size = Math.max(1, size);
we.checkMaxRadius(size);
World world = player.getWorld();
- int height = args.argsLength() > 1 ? Math.min((world.getMaxY() + 1), args.getInteger(1) + 2) : (world.getMaxY() + 1);
+ height = height != null ? Math.min((-world.getMaxY() + 1), height + 2) : (world.getMaxY() + 1);
int affected = editSession.removeBelow(session.getPlacementPosition(player), size, height);
player.print(affected + " block(s) have been removed.");
+ return affected;
}
@Command(
- aliases = { "/removenear", "removenear" },
- usage = " [size]",
- desc = "Remove blocks near you.",
- min = 1,
- max = 2
+ name = "removenear",
+ aliases = { "/removenear" },
+ desc = "Remove blocks near you."
)
@CommandPermissions("worldedit.removenear")
@Logging(PLACEMENT)
- public void removeNear(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
+ public int removeNear(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The mask of blocks to remove")
+ Mask mask,
+ @Arg(desc = "The radius of the square to remove from", def = "50")
+ int radius) throws WorldEditException {
+ radius = Math.max(1, radius);
+ we.checkMaxRadius(radius);
- ParserContext context = new ParserContext();
- context.setActor(player);
- context.setWorld(player.getWorld());
- context.setSession(session);
- context.setRestricted(false);
- context.setPreferringWildcard(false);
-
- BaseBlock block = we.getBlockFactory().parseFromInput(args.getString(0), context);
- int size = Math.max(1, args.getInteger(1, 50));
- we.checkMaxRadius(size);
-
- int affected = editSession.removeNear(session.getPlacementPosition(player), block.getBlockType(), size);
+ int affected = editSession.removeNear(session.getPlacementPosition(player), mask, radius);
player.print(affected + " block(s) have been removed.");
+ return affected;
}
@Command(
- aliases = { "/replacenear", "replacenear" },
- usage = " ",
- desc = "Replace nearby blocks",
- flags = "f",
- min = 3,
- max = 3
+ name = "replacenear",
+ aliases = { "/replacenear" },
+ desc = "Replace nearby blocks"
)
@CommandPermissions("worldedit.replacenear")
@Logging(PLACEMENT)
- public void replaceNear(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
-
- int size = Math.max(1, args.getInteger(0));
- we.checkMaxRadius(size);
- int affected;
- Set from;
- Pattern to;
-
- ParserContext context = new ParserContext();
- context.setActor(player);
- context.setWorld(player.getWorld());
- context.setSession(session);
- context.setRestricted(false);
- context.setPreferringWildcard(!args.hasFlag('f'));
-
- if (args.argsLength() == 2) {
- from = null;
- context.setRestricted(true);
- to = we.getPatternFactory().parseFromInput(args.getString(1), context);
- } else {
- from = we.getBlockFactory().parseFromListInput(args.getString(1), context);
- context.setRestricted(true);
- to = we.getPatternFactory().parseFromInput(args.getString(2), context);
- }
+ public int replaceNear(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The radius of the square to remove in")
+ int radius,
+ @Arg(desc = "The mask matching blocks to remove", def = "")
+ Mask from,
+ @Arg(desc = "The pattern of blocks to replace with")
+ Pattern to) throws WorldEditException {
+ radius = Math.max(1, radius);
+ we.checkMaxRadius(radius);
BlockVector3 base = session.getPlacementPosition(player);
- BlockVector3 min = base.subtract(size, size, size);
- BlockVector3 max = base.add(size, size, size);
+ BlockVector3 min = base.subtract(radius, radius, radius);
+ BlockVector3 max = base.add(radius, radius, radius);
Region region = new CuboidRegion(player.getWorld(), min, max);
- if (to instanceof BlockPattern) {
- affected = editSession.replaceBlocks(region, from, ((BlockPattern) to).getBlock());
- } else {
- affected = editSession.replaceBlocks(region, from, to);
+ if (from == null) {
+ from = new ExistingBlockMask(editSession);
}
+
+ int affected = editSession.replaceBlocks(region, from, to);
player.print(affected + " block(s) have been replaced.");
+ return affected;
}
@Command(
- aliases = { "/snow", "snow" },
- usage = "[radius]",
- desc = "Simulates snow",
- min = 0,
- max = 1
+ name = "snow",
+ aliases = { "/snow" },
+ desc = "Simulates snow"
)
@CommandPermissions("worldedit.snow")
@Logging(PLACEMENT)
- public void snow(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
- double size = args.argsLength() > 0 ? Math.max(1, args.getDouble(0)) : 10;
+ public int snow(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The radius of the circle to snow in", def = "10")
+ double size) throws WorldEditException {
+ size = Math.max(1, size);
we.checkMaxRadius(size);
int affected = editSession.simulateSnow(session.getPlacementPosition(player), size);
- player.print(affected + " surfaces covered. Let it snow~");
+ player.print(affected + " surface(s) covered. Let it snow~");
+ return affected;
}
@Command(
- aliases = {"/thaw", "thaw"},
- usage = "[radius]",
- desc = "Thaws the area",
- min = 0,
- max = 1
+ name = "thaw",
+ aliases = { "/thaw" },
+ desc = "Thaws the area"
)
@CommandPermissions("worldedit.thaw")
@Logging(PLACEMENT)
- public void thaw(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
- double size = args.argsLength() > 0 ? Math.max(1, args.getDouble(0)) : 10;
+ public int thaw(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The radius of the circle to thaw in", def = "10")
+ double size) throws WorldEditException {
+ size = Math.max(1, size);
we.checkMaxRadius(size);
int affected = editSession.thaw(session.getPlacementPosition(player), size);
- player.print(affected + " surfaces thawed.");
+ player.print(affected + " surface(s) thawed.");
+ return affected;
}
@Command(
- aliases = { "/green", "green" },
- usage = "[radius]",
- desc = "Greens the area",
- help = "Converts dirt to grass blocks. -f also converts coarse dirt.",
- flags = "f",
- min = 0,
- max = 1
+ name = "green",
+ aliases = { "/green" },
+ desc = "Converts dirt to grass blocks in the area"
)
@CommandPermissions("worldedit.green")
@Logging(PLACEMENT)
- public void green(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
- final double size = args.argsLength() > 0 ? Math.max(1, args.getDouble(0)) : 10;
+ public int green(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The radius of the circle to convert in", def = "10")
+ double size,
+ @Switch(name = 'f', desc = "Also convert coarse dirt")
+ boolean convertCoarse) throws WorldEditException {
+ size = Math.max(1, size);
we.checkMaxRadius(size);
- final boolean onlyNormalDirt = !args.hasFlag('f');
+ final boolean onlyNormalDirt = !convertCoarse;
final int affected = editSession.green(session.getPlacementPosition(player), size, onlyNormalDirt);
- player.print(affected + " surfaces greened.");
+ player.print(affected + " surface(s) greened.");
+ return affected;
}
@Command(
- aliases = { "/ex", "/ext", "/extinguish", "ex", "ext", "extinguish" },
- usage = "[radius]",
- desc = "Extinguish nearby fire",
- min = 0,
- max = 1
- )
+ name = "extinguish",
+ aliases = { "/ex", "/ext", "/extinguish", "ex", "ext" },
+ desc = "Extinguish nearby fire"
+ )
@CommandPermissions("worldedit.extinguish")
@Logging(PLACEMENT)
- public void extinguish(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
+ public void extinguish(Player player, LocalSession session, EditSession editSession,
+ @Arg(desc = "The radius of the square to remove in", def = "")
+ Integer radius) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
int defaultRadius = config.maxRadius != -1 ? Math.min(40, config.maxRadius) : 40;
- int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0))
- : defaultRadius;
+ int size = radius != null ? Math.max(1, radius) : defaultRadius;
we.checkMaxRadius(size);
- int affected = editSession.removeNear(session.getPlacementPosition(player), BlockTypes.FIRE, size);
+ Mask mask = new BlockTypeMask(editSession, BlockTypes.FIRE);
+ int affected = editSession.removeNear(session.getPlacementPosition(player), mask, size);
player.print(affected + " block(s) have been removed.");
}
@Command(
- aliases = { "butcher" },
- usage = "[radius]",
- flags = "plangbtfr",
- desc = "Kill all or nearby mobs",
- help =
- "Kills nearby mobs, based on radius, if none is given uses default in configuration.\n" +
- "Flags:\n" +
- " -p also kills pets.\n" +
- " -n also kills NPCs.\n" +
- " -g also kills Golems.\n" +
- " -a also kills animals.\n" +
- " -b also kills ambient mobs.\n" +
- " -t also kills mobs with name tags.\n" +
- " -f compounds all previous flags.\n" +
- " -r also destroys armor stands.\n" +
- " -l currently does nothing.",
- min = 0,
- max = 1
+ name = "butcher",
+ desc = "Kill all or nearby mobs"
)
@CommandPermissions("worldedit.butcher")
@Logging(PLACEMENT)
- public void butcher(Actor actor, CommandContext args) throws WorldEditException {
+ public int butcher(Actor actor,
+ @Arg(desc = "Radius to kill mobs in", def = "")
+ Integer radius,
+ @Switch(name = 'p', desc = "Also kill pets")
+ boolean killPets,
+ @Switch(name = 'n', desc = "Also kill NPCs")
+ boolean killNpcs,
+ @Switch(name = 'g', desc = "Also kill golems")
+ boolean killGolems,
+ @Switch(name = 'a', desc = "Also kill animals")
+ boolean killAnimals,
+ @Switch(name = 'b', desc = "Also kill ambient mobs")
+ boolean killAmbient,
+ @Switch(name = 't', desc = "Also kill mobs with name tags")
+ boolean killWithName,
+ @Switch(name = 'f', desc = "Also kill all friendly mobs (Applies the flags `-abgnpt`)")
+ boolean killFriendly,
+ @Switch(name = 'r', desc = "Also destroy armor stands")
+ boolean killArmorStands) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
Player player = actor instanceof Player ? (Player) actor : null;
- // technically the default can be larger than the max, but that's not my problem
- int radius = config.butcherDefaultRadius;
-
- // there might be a better way to do this but my brain is fried right now
- if (args.argsLength() > 0) { // user inputted radius, override the default
- radius = args.getInteger(0);
- if (radius < -1) {
- actor.printError("Use -1 to remove all mobs in loaded chunks");
- return;
- }
- if (config.butcherMaxRadius != -1) { // clamp if there is a max
- if (radius == -1) {
- radius = config.butcherMaxRadius;
- } else { // Math.min does not work if radius is -1 (actually highest possible value)
- radius = Math.min(radius, config.butcherMaxRadius);
- }
+ if (radius == null) {
+ radius = config.butcherDefaultRadius;
+ } else if (radius < -1) {
+ actor.printError("Use -1 to remove all mobs in loaded chunks");
+ return 0;
+ } else if (radius == -1) {
+ if (config.butcherMaxRadius != -1) {
+ radius = config.butcherMaxRadius;
}
}
+ if (config.butcherMaxRadius != -1) {
+ radius = Math.min(radius, config.butcherMaxRadius);
+ }
CreatureButcher flags = new CreatureButcher(actor);
- flags.fromCommand(args);
+ flags.or(CreatureButcher.Flags.FRIENDLY, killFriendly); // No permission check here. Flags will instead be filtered by the subsequent calls.
+ flags.or(CreatureButcher.Flags.PETS, killPets, "worldedit.butcher.pets");
+ flags.or(CreatureButcher.Flags.NPCS, killNpcs, "worldedit.butcher.npcs");
+ flags.or(CreatureButcher.Flags.GOLEMS, killGolems, "worldedit.butcher.golems");
+ flags.or(CreatureButcher.Flags.ANIMALS, killAnimals, "worldedit.butcher.animals");
+ flags.or(CreatureButcher.Flags.AMBIENT, killAmbient, "worldedit.butcher.ambient");
+ flags.or(CreatureButcher.Flags.TAGGED, killWithName, "worldedit.butcher.tagged");
+ flags.or(CreatureButcher.Flags.ARMOR_STAND, killArmorStands, "worldedit.butcher.armorstands");
+ int killed = killMatchingEntities(radius, player, flags::createFunction);
+
+ actor.print("Killed " + killed + (killed != 1 ? " mobs" : " mob") + (radius < 0 ? "" : " in a radius of " + radius) + ".");
+
+ return killed;
+ }
+
+ @Command(
+ name = "remove",
+ aliases = { "rem", "rement" },
+ desc = "Remove all entities of a type"
+ )
+ @CommandPermissions("worldedit.remove")
+ @Logging(PLACEMENT)
+ public int remove(Actor actor,
+ @Arg(desc = "The type of entity to remove")
+ EntityRemover remover,
+ @Arg(desc = "The radius of the cuboid to remove from")
+ int radius) throws WorldEditException {
+ Player player = actor instanceof Player ? (Player) actor : null;
+
+ if (radius < -1) {
+ actor.printError("Use -1 to remove all entities in loaded chunks");
+ return 0;
+ }
+
+ int removed = killMatchingEntities(radius, player, remover::createFunction);
+
+ actor.print("Marked " + removed + (removed != 1 ? " entities" : " entity") + " for removal.");
+ return removed;
+ }
+
+ private int killMatchingEntities(Integer radius, Player player, Supplier func) throws IncompleteRegionException, MaxChangedBlocksException {
List visitors = new ArrayList<>();
LocalSession session = null;
EditSession editSession = null;
@@ -453,12 +457,12 @@ public class UtilityCommands {
} else {
entities = editSession.getEntities();
}
- visitors.add(new EntityVisitor(entities.iterator(), flags.createFunction()));
+ visitors.add(new EntityVisitor(entities.iterator(), func.get()));
} else {
Platform platform = we.getPlatformManager().queryCapability(Capability.WORLD_EDITING);
for (World world : platform.getWorlds()) {
List extends Entity> entities = world.getEntities();
- visitors.add(new EntityVisitor(entities.iterator(), flags.createFunction()));
+ visitors.add(new EntityVisitor(entities.iterator(), func.get()));
}
}
@@ -468,245 +472,55 @@ public class UtilityCommands {
killed += visitor.getAffected();
}
- actor.print("Killed " + killed + (killed != 1 ? " mobs" : " mob") + (radius < 0 ? "" : " in a radius of " + radius) + ".");
-
if (editSession != null) {
session.remember(editSession);
editSession.flushSession();
}
+ return killed;
+ }
+
+ // get the formatter with the system locale. in the future, if we can get a local from a player, we can use that
+ private static final DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(Locale.getDefault());
+ static {
+ formatter.applyPattern("#,##0.#####"); // pattern is locale-insensitive. this can translate to "1.234,56789"
}
@Command(
- aliases = { "remove", "rem", "rement" },
- usage = " ",
- desc = "Remove all entities of a type",
- min = 2,
- max = 2
- )
- @CommandPermissions("worldedit.remove")
- @Logging(PLACEMENT)
- public void remove(Actor actor, CommandContext args) throws WorldEditException, CommandException {
- String typeStr = args.getString(0);
- int radius = args.getInteger(1);
- Player player = actor instanceof Player ? (Player) actor : null;
-
- if (radius < -1) {
- actor.printError("Use -1 to remove all entities in loaded chunks");
- return;
- }
-
- EntityRemover remover = new EntityRemover();
- remover.fromString(typeStr);
-
- List visitors = new ArrayList<>();
- LocalSession session = null;
- EditSession editSession = null;
-
- if (player != null) {
- session = we.getSessionManager().get(player);
- BlockVector3 center = session.getPlacementPosition(player);
- editSession = session.createEditSession(player);
- List extends Entity> entities;
- if (radius >= 0) {
- CylinderRegion region = CylinderRegion.createRadius(editSession, center, radius);
- entities = editSession.getEntities(region);
- } else {
- entities = editSession.getEntities();
- }
- visitors.add(new EntityVisitor(entities.iterator(), remover.createFunction()));
- } else {
- Platform platform = we.getPlatformManager().queryCapability(Capability.WORLD_EDITING);
- for (World world : platform.getWorlds()) {
- List extends Entity> entities = world.getEntities();
- visitors.add(new EntityVisitor(entities.iterator(), remover.createFunction()));
- }
- }
-
- int removed = 0;
- for (EntityVisitor visitor : visitors) {
- Operations.completeLegacy(visitor);
- removed += visitor.getAffected();
- }
-
- actor.print("Marked " + removed + (removed != 1 ? " entities" : " entity") + " for removal.");
-
- if (editSession != null) {
- session.remember(editSession);
- editSession.flushSession();
- }
- }
-
- @Command(
- aliases = { "/calc", "/calculate", "/eval", "/evaluate", "/solve" },
- usage = "",
+ name = "/calculate",
+ aliases = { "/calc", "/eval", "/evaluate", "/solve" },
desc = "Evaluate a mathematical expression"
)
@CommandPermissions("worldedit.calc")
- public void calc(Actor actor, @Text String input) throws CommandException {
+ public void calc(Actor actor,
+ @Arg(desc = "Expression to evaluate", variable = true)
+ List input) {
try {
- Expression expression = Expression.compile(input);
- if (actor instanceof SessionOwner) {
- actor.print("= " + expression.evaluate(
- new double[]{}, WorldEdit.getInstance().getSessionManager().get((SessionOwner) actor).getTimeout()));
- } else {
- actor.print("= " + expression.evaluate());
- }
+ Expression expression = Expression.compile(String.join(" ", input));
+ double result = expression.evaluate(
+ new double[]{}, WorldEdit.getInstance().getSessionManager().get(actor).getTimeout());
+ String formatted = formatter.format(result);
+ actor.print(SubtleFormat.wrap(input + " = ")
+ .append(TextComponent.of(formatted, TextColor.LIGHT_PURPLE)));
} catch (EvaluationException e) {
actor.printError(String.format(
- "'%s' could not be evaluated (error: %s)", input, e.getMessage()));
+ "'%s' could not be evaluated (error: %s)", input, e.getMessage()));
} catch (ExpressionException e) {
actor.printError(String.format(
- "'%s' could not be parsed as a valid expression", input));
+ "'%s' could not be parsed as a valid expression", input));
}
}
@Command(
- aliases = { "/help" },
- usage = "[]",
- desc = "Displays help for WorldEdit commands",
- min = 0,
- max = -1
+ name = "/help",
+ desc = "Displays help for WorldEdit commands"
)
@CommandPermissions("worldedit.help")
- public void help(Actor actor, CommandContext args) throws WorldEditException {
- help(args, we, actor);
- }
-
- private static CommandMapping detectCommand(Dispatcher dispatcher, String command, boolean isRootLevel) {
- CommandMapping mapping;
-
- // First try the command as entered
- mapping = dispatcher.get(command);
- if (mapping != null) {
- return mapping;
- }
-
- // Then if we're looking at root commands and the user didn't use
- // any slashes, let's try double slashes and then single slashes.
- // However, be aware that there exists different single slash
- // and double slash commands in WorldEdit
- if (isRootLevel && !command.contains("/")) {
- mapping = dispatcher.get("//" + command);
- if (mapping != null) {
- return mapping;
- }
-
- mapping = dispatcher.get("/" + command);
- if (mapping != null) {
- return mapping;
- }
- }
-
- return null;
- }
-
- public static void help(CommandContext args, WorldEdit we, Actor actor) {
- CommandCallable callable = we.getPlatformManager().getCommandManager().getDispatcher();
-
- int page = 0;
- final int perPage = actor instanceof Player ? 8 : 20; // More pages for console
- int effectiveLength = args.argsLength();
-
- // Detect page from args
- try {
- if (args.argsLength() > 0) {
- page = args.getInteger(args.argsLength() - 1);
- if (page <= 0) {
- page = 1;
- } else {
- page--;
- }
-
- effectiveLength--;
- }
- } catch (NumberFormatException ignored) {
- }
-
- boolean isRootLevel = true;
- List visited = new ArrayList<>();
-
- // Drill down to the command
- for (int i = 0; i < effectiveLength; i++) {
- String command = args.getString(i);
-
- if (callable instanceof Dispatcher) {
- // Chop off the beginning / if we're are the root level
- if (isRootLevel && command.length() > 1 && command.charAt(0) == '/') {
- command = command.substring(1);
- }
-
- CommandMapping mapping = detectCommand((Dispatcher) callable, command, isRootLevel);
- if (mapping != null) {
- callable = mapping.getCallable();
- } else {
- if (isRootLevel) {
- actor.printError(String.format("The command '%s' could not be found.", args.getString(i)));
- return;
- } else {
- actor.printError(String.format("The sub-command '%s' under '%s' could not be found.",
- command, Joiner.on(" ").join(visited)));
- return;
- }
- }
-
- visited.add(args.getString(i));
- isRootLevel = false;
- } else {
- actor.printError(String.format("'%s' has no sub-commands. (Maybe '%s' is for a parameter?)",
- Joiner.on(" ").join(visited), command));
- return;
- }
- }
-
- // Create the message
- if (callable instanceof Dispatcher) {
- Dispatcher dispatcher = (Dispatcher) callable;
-
- // Get a list of aliases
- List aliases = new ArrayList<>(dispatcher.getCommands());
- aliases.sort(new PrimaryAliasComparator(CommandManager.COMMAND_CLEAN_PATTERN));
-
- // Calculate pagination
- int offset = perPage * page;
- int pageTotal = (int) Math.ceil(aliases.size() / (double) perPage);
-
- // Box
- CommandListBox box = new CommandListBox(String.format("Help: page %d/%d ", page + 1, pageTotal));
- TextComponentProducer tip = new TextComponentProducer();
- tip.getBuilder().content("").color(TextColor.GRAY);
- TextComponentProducer contents = box.getContents();
-
- if (offset >= aliases.size()) {
- tip.append(ErrorFormat.wrap(String.format("There is no page %d (total number of pages is %d).", page + 1, pageTotal))).newline();
- } else {
- List list = aliases.subList(offset, Math.min(offset + perPage, aliases.size()));
-
- tip.append("Type ");
- tip.append(CodeFormat.wrap("//help "));
- tip.append(" [] for more information.");
- tip.newline();
-
- // Add each command
- for (CommandMapping mapping : list) {
- StringBuilder builder = new StringBuilder();
- if (isRootLevel) {
- builder.append("/");
- }
- if (!visited.isEmpty()) {
- builder.append(Joiner.on(" ").join(visited));
- builder.append(" ");
- }
- builder.append(mapping.getPrimaryAlias());
- box.appendCommand(builder.toString(), mapping.getDescription().getDescription());
- }
- }
-
- contents.append(tip.create());
- actor.print(box.create());
- } else {
- CommandUsageBox box = new CommandUsageBox(callable, Joiner.on(" ").join(visited));
- actor.print(box.create());
- }
+ public void help(Actor actor,
+ @Arg(desc = "The page to retrieve", def = "1")
+ int page,
+ @Arg(desc = "The command to retrieve help for", def = "", variable = true)
+ List command) throws WorldEditException {
+ PrintCommandHelp.help(command, page, we, actor);
}
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java
index 26c382beb..0d19d1538 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java
@@ -20,12 +20,12 @@
package com.sk89q.worldedit.command;
import com.google.common.io.Files;
-import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandContext;
-import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.command.util.CommandPermissions;
+import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
+import com.sk89q.worldedit.command.util.PrintCommandHelp;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent;
import com.sk89q.worldedit.extension.platform.Actor;
@@ -36,34 +36,40 @@ import com.sk89q.worldedit.util.paste.ActorCallbackPaste;
import com.sk89q.worldedit.util.report.ConfigReport;
import com.sk89q.worldedit.util.report.ReportList;
import com.sk89q.worldedit.util.report.SystemInfoReport;
+import org.enginehub.piston.annotation.Command;
+import org.enginehub.piston.annotation.CommandContainer;
+import org.enginehub.piston.annotation.param.Arg;
+import org.enginehub.piston.annotation.param.Switch;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.TimeZone;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.TextStyle;
+import java.time.zone.ZoneRulesException;
+import java.util.List;
+import java.util.Locale;
+@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class WorldEditCommands {
- private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
-
+ private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z");
+
private final WorldEdit we;
-
+
public WorldEditCommands(WorldEdit we) {
this.we = we;
}
@Command(
- aliases = { "version", "ver" },
- usage = "",
- desc = "Get WorldEdit version",
- min = 0,
- max = 0
+ name = "version",
+ aliases = { "ver" },
+ desc = "Get WorldEdit version"
)
public void version(Actor actor) throws WorldEditException {
actor.print("WorldEdit version " + WorldEdit.getVersion());
- actor.print("https://github.com/sk89q/worldedit/");
+ actor.print("https://github.com/EngineHub/worldedit/");
PlatformManager pm = we.getPlatformManager();
@@ -80,11 +86,8 @@ public class WorldEditCommands {
}
@Command(
- aliases = { "reload" },
- usage = "",
- desc = "Reload configuration",
- min = 0,
- max = 0
+ name = "reload",
+ desc = "Reload configuration"
)
@CommandPermissions("worldedit.reload")
public void reload(Actor actor) throws WorldEditException {
@@ -93,9 +96,14 @@ public class WorldEditCommands {
actor.print("Configuration reloaded!");
}
- @Command(aliases = {"report"}, desc = "Writes a report on WorldEdit", flags = "p", max = 0)
+ @Command(
+ name = "report",
+ desc = "Writes a report on WorldEdit"
+ )
@CommandPermissions({"worldedit.report"})
- public void report(Actor actor, CommandContext args) throws WorldEditException {
+ public void report(Actor actor,
+ @Switch(name = 'p', desc = "Pastebins the report")
+ boolean pastebin) throws WorldEditException {
ReportList report = new ReportList("Report");
report.add(new SystemInfoReport());
report.add(new ConfigReport());
@@ -109,21 +117,18 @@ public class WorldEditCommands {
actor.printError("Failed to write report: " + e.getMessage());
}
- if (args.hasFlag('p')) {
+ if (pastebin) {
actor.checkPermission("worldedit.report.pastebin");
ActorCallbackPaste.pastebin(
we.getSupervisor(), actor, result, "WorldEdit report: %s.report",
- WorldEdit.getInstance().getPlatformManager().getCommandManager().getExceptionConverter()
+ WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getExceptionConverter()
);
}
}
@Command(
- aliases = { "cui" },
- usage = "",
- desc = "Complete CUI handshake (internal usage)",
- min = 0,
- max = 0
+ name = "cui",
+ desc = "Complete CUI handshake (internal usage)"
)
public void cui(Player player, LocalSession session) throws WorldEditException {
session.setCUISupport(true);
@@ -131,29 +136,34 @@ public class WorldEditCommands {
}
@Command(
- aliases = { "tz" },
- usage = "[timezone]",
- desc = "Set your timezone for snapshots",
- min = 1,
- max = 1
+ name = "tz",
+ desc = "Set your timezone for snapshots"
)
- public void tz(Player player, LocalSession session, CommandContext args) throws WorldEditException {
- TimeZone tz = TimeZone.getTimeZone(args.getString(0));
- session.setTimezone(tz);
- player.print("Timezone set for this session to: " + tz.getDisplayName());
- player.print("The current time in that timezone is: "
- + dateFormat.format(Calendar.getInstance(tz).getTime()));
+ public void tz(Player player, LocalSession session,
+ @Arg(desc = "The timezone to set")
+ String timezone) throws WorldEditException {
+ try {
+ ZoneId tz = ZoneId.of(timezone);
+ session.setTimezone(tz);
+ player.print("Timezone set for this session to: " + tz.getDisplayName(
+ TextStyle.FULL, Locale.ENGLISH
+ ));
+ player.print("The current time in that timezone is: " + dateFormat.format(ZonedDateTime.now(tz)));
+ } catch (ZoneRulesException e) {
+ player.printError("Invalid timezone");
+ }
}
@Command(
- aliases = { "help" },
- usage = "[]",
- desc = "Displays help for WorldEdit commands",
- min = 0,
- max = -1
+ name = "help",
+ desc = "Displays help for WorldEdit commands"
)
@CommandPermissions("worldedit.help")
- public void help(Actor actor, CommandContext args) throws WorldEditException {
- UtilityCommands.help(args, we, actor);
+ public void help(Actor actor,
+ @Arg(desc = "The page to retrieve", def = "1")
+ int page,
+ @Arg(desc = "The command to retrieve help for", def = "", variable = true)
+ List command) throws WorldEditException {
+ PrintCommandHelp.help(command, page, we, actor);
}
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/MissingParameterException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/Arguments.java
similarity index 78%
rename from worldedit-core/src/main/java/com/sk89q/worldedit/util/command/MissingParameterException.java
rename to worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/Arguments.java
index bbdf0e0d5..a1b444cbe 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/MissingParameterException.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/Arguments.java
@@ -17,13 +17,16 @@
* along with this program. If not, see .
*/
-package com.sk89q.worldedit.util.command;
+package com.sk89q.worldedit.command.argument;
-import com.sk89q.worldedit.util.command.parametric.ParameterException;
+
+import org.enginehub.piston.inject.InjectedValueAccess;
/**
- * Thrown when there is a missing parameter.
+ * Key-interface for {@link InjectedValueAccess} for the String arguments.
*/
-public class MissingParameterException extends ParameterException {
+public interface Arguments {
+
+ String get();
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentUtils.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java
similarity index 50%
rename from worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentUtils.java
rename to worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java
index 22141fedd..731a736b3 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentUtils.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java
@@ -17,29 +17,29 @@
* along with this program. If not, see .
*/
-package com.sk89q.worldedit.util.command.argument;
+package com.sk89q.worldedit.command.argument;
-import com.google.common.collect.Lists;
+import com.google.common.collect.ImmutableSetMultimap;
+import org.enginehub.piston.CommandManager;
+import org.enginehub.piston.converter.MultiKeyConverter;
+import org.enginehub.piston.inject.Key;
-import java.util.Collection;
-import java.util.List;
+public class BooleanConverter {
-public final class ArgumentUtils {
-
- private ArgumentUtils() {
+ public static void register(CommandManager commandManager) {
+ commandManager.registerConverter(Key.of(Boolean.class),
+ MultiKeyConverter.builder(
+ ImmutableSetMultimap.builder()
+ .putAll(false, "off", "f", "false", "n", "no")
+ .putAll(true, "on", "t", "true", "y", "yes")
+ .build()
+ )
+ .errorMessage(arg -> "Not a boolean value: " + arg)
+ .build()
+ );
}
- public static List getMatchingSuggestions(Collection items, String s) {
- if (s.isEmpty()) {
- return Lists.newArrayList(items);
- }
- List suggestions = Lists.newArrayList();
- for (String item : items) {
- if (item.toLowerCase().startsWith(s)) {
- suggestions.add(item);
- }
- }
- return suggestions;
+ private BooleanConverter() {
}
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanFlag.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanFlag.java
deleted file mode 100644
index 3e849a099..000000000
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanFlag.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * WorldEdit, a Minecraft world manipulation toolkit
- * Copyright (C) sk89q
- * Copyright (C) WorldEdit team and contributors
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by the
- * Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.sk89q.worldedit.command.argument;
-
-import com.sk89q.minecraft.util.commands.CommandException;
-import com.sk89q.minecraft.util.commands.CommandLocals;
-import com.sk89q.worldedit.util.command.argument.CommandArgs;
-import com.sk89q.worldedit.util.command.composition.CommandExecutor;
-
-import java.util.Collections;
-import java.util.List;
-
-public class BooleanFlag implements CommandExecutor {
-
- private final String description;
-
- public BooleanFlag(String description) {
- this.description = description;
- }
-
- @Override
- public Boolean call(CommandArgs args, CommandLocals locals) throws CommandException {
- return true;
- }
-
- @Override
- public List getSuggestions(CommandArgs args, CommandLocals locals) {
- return Collections.emptyList();
- }
-
- @Override
- public String getUsage() {
- return "";
- }
-
- @Override
- public String getDescription() {
- return description;
- }
-
- @Override
- public boolean testPermission(CommandLocals locals) {
- return true;
- }
-
-}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java
new file mode 100644
index 000000000..7479ff375
--- /dev/null
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java
@@ -0,0 +1,91 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.command.argument;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.sk89q.worldedit.util.formatting.text.Component;
+import com.sk89q.worldedit.util.formatting.text.TextComponent;
+import org.enginehub.piston.converter.ArgumentConverter;
+import org.enginehub.piston.converter.ConversionResult;
+import org.enginehub.piston.converter.SuccessfulConversion;
+import org.enginehub.piston.inject.InjectedValueAccess;
+
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.sk89q.worldedit.util.formatting.text.Component.space;
+
+public class CommaSeparatedValuesConverter implements ArgumentConverter {
+
+ public static CommaSeparatedValuesConverter wrap(ArgumentConverter delegate) {
+ return wrapAndLimit(delegate, -1);
+ }
+
+ public static CommaSeparatedValuesConverter wrapAndLimit(ArgumentConverter delegate, int maximum) {
+ return new CommaSeparatedValuesConverter<>(delegate, maximum);
+ }
+
+ private static final Splitter COMMA = Splitter.on(',');
+
+ private final ArgumentConverter delegate;
+ private final int maximum;
+
+ private CommaSeparatedValuesConverter(ArgumentConverter delegate, int maximum) {
+ checkArgument(maximum == -1 || maximum > 1,
+ "Maximum must be bigger than 1, or exactly -1");
+ this.delegate = delegate;
+ this.maximum = maximum;
+ }
+
+ @Override
+ public Component describeAcceptableArguments() {
+ TextComponent.Builder result = TextComponent.builder("");
+ if (maximum > -1) {
+ result.append(TextComponent.of("up to "))
+ .append(Component.of(maximum))
+ .append(space());
+ }
+ result.append(TextComponent.of("comma separated values of: "))
+ .append(delegate.describeAcceptableArguments());
+ return result.build();
+ }
+
+ @Override
+ public List getSuggestions(String input) {
+ String lastInput = Iterables.getLast(COMMA.split(input), "");
+ return delegate.getSuggestions(lastInput);
+ }
+
+ @Override
+ public ConversionResult convert(String argument, InjectedValueAccess context) {
+ ImmutableList.Builder result = ImmutableList.builder();
+ for (String input : COMMA.split(argument)) {
+ ConversionResult temp = delegate.convert(input, context);
+ if (!temp.isSuccessful()) {
+ return temp;
+ }
+ result.addAll(temp.get());
+ }
+ return SuccessfulConversion.from(result.build());
+ }
+
+}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java
new file mode 100644
index 000000000..aacfe4bf5
--- /dev/null
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java
@@ -0,0 +1,119 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.command.argument;
+
+import com.google.auto.value.AutoAnnotation;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.sk89q.worldedit.UnknownDirectionException;
+import com.sk89q.worldedit.WorldEdit;
+import com.sk89q.worldedit.entity.Player;
+import com.sk89q.worldedit.internal.annotation.Direction;
+import com.sk89q.worldedit.internal.annotation.MultiDirection;
+import com.sk89q.worldedit.math.BlockVector3;
+import com.sk89q.worldedit.util.formatting.text.Component;
+import com.sk89q.worldedit.util.formatting.text.TextComponent;
+import org.enginehub.piston.CommandManager;
+import org.enginehub.piston.converter.ArgumentConverter;
+import org.enginehub.piston.converter.ConversionResult;
+import org.enginehub.piston.converter.FailedConversion;
+import org.enginehub.piston.converter.SuccessfulConversion;
+import org.enginehub.piston.inject.InjectedValueAccess;
+import org.enginehub.piston.inject.Key;
+
+import java.util.List;
+
+import static java.util.stream.Collectors.toList;
+import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix;
+
+public class DirectionConverter implements ArgumentConverter {
+
+ @AutoAnnotation
+ private static Direction direction(boolean includeDiagonals) {
+ return new AutoAnnotation_DirectionConverter_direction(includeDiagonals);
+ }
+
+ @AutoAnnotation
+ private static MultiDirection multiDirection(boolean includeDiagonals) {
+ return new AutoAnnotation_DirectionConverter_multiDirection(includeDiagonals);
+ }
+
+ public static void register(WorldEdit worldEdit, CommandManager commandManager) {
+ for (boolean includeDiagonals : new boolean[] { false, true }) {
+ DirectionConverter directionConverter = new DirectionConverter(worldEdit, includeDiagonals);
+ commandManager.registerConverter(
+ Key.of(BlockVector3.class, direction(includeDiagonals)),
+ directionConverter
+ );
+ commandManager.registerConverter(
+ Key.of(BlockVector3.class, multiDirection(includeDiagonals)),
+ CommaSeparatedValuesConverter.wrap(directionConverter)
+ );
+ }
+ }
+
+ private static final ImmutableSet NON_DIAGONALS = ImmutableSet.of(
+ "north", "south", "east", "west", "up", "down"
+ );
+ private static final ImmutableSet RELATIVE = ImmutableSet.of(
+ "me", "forward", "back", "left", "right"
+ );
+ private static final ImmutableSet DIAGONALS = ImmutableSet.of(
+ "northeast", "northwest", "southeast", "southwest"
+ );
+
+ private final WorldEdit worldEdit;
+ private final boolean includeDiagonals;
+ private final ImmutableList suggestions;
+
+ private DirectionConverter(WorldEdit worldEdit, boolean includeDiagonals) {
+ this.worldEdit = worldEdit;
+ this.includeDiagonals = includeDiagonals;
+ suggestions = ImmutableList.builder()
+ .addAll(NON_DIAGONALS)
+ .addAll(RELATIVE)
+ .addAll(includeDiagonals ? DIAGONALS : ImmutableList.of())
+ .build();
+ }
+
+ @Override
+ public ConversionResult convert(String argument, InjectedValueAccess context) {
+ Player player = context.injectedValue(Key.of(Player.class))
+ .orElseThrow(() -> new IllegalStateException("No player available"));
+ try {
+ return SuccessfulConversion.fromSingle(includeDiagonals
+ ? worldEdit.getDiagonalDirection(player, argument)
+ : worldEdit.getDirection(player, argument));
+ } catch (UnknownDirectionException e) {
+ return FailedConversion.from(e);
+ }
+ }
+
+ @Override
+ public Component describeAcceptableArguments() {
+ return TextComponent.of("`me` to use facing direction, or any "
+ + (includeDiagonals ? "direction" : "non-diagonal direction"));
+ }
+
+ @Override
+ public List getSuggestions(String input) {
+ return limitByPrefix(suggestions.stream(), input);
+ }
+}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EditSessionHolder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EditSessionHolder.java
new file mode 100644
index 000000000..b5113f545
--- /dev/null
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EditSessionHolder.java
@@ -0,0 +1,87 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.command.argument;
+
+import com.sk89q.worldedit.EditSession;
+import com.sk89q.worldedit.LocalSession;
+import com.sk89q.worldedit.WorldEdit;
+import com.sk89q.worldedit.entity.Player;
+
+import java.util.concurrent.locks.StampedLock;
+
+/**
+ * Lazily-created {@link EditSession}.
+ */
+public class EditSessionHolder {
+
+ private final StampedLock lock = new StampedLock();
+ private final WorldEdit worldEdit;
+ private final Player player;
+
+ public EditSessionHolder(WorldEdit worldEdit, Player player) {
+ this.worldEdit = worldEdit;
+ this.player = player;
+ }
+
+ private EditSession session;
+
+ /**
+ * Get the session, but does not create it if it doesn't exist.
+ */
+ public EditSession getSession() {
+ long stamp = lock.tryOptimisticRead();
+ EditSession result = session;
+ if (!lock.validate(stamp)) {
+ stamp = lock.readLock();
+ try {
+ result = session;
+ } finally {
+ lock.unlockRead(stamp);
+ }
+ }
+ return result;
+ }
+
+ public EditSession getOrCreateSession() {
+ // use the already-generated result if possible
+ EditSession result = getSession();
+ if (result != null) {
+ return result;
+ }
+ // otherwise, acquire write lock
+ long stamp = lock.writeLock();
+ try {
+ // check session field again -- maybe another writer hit it in between
+ result = session;
+ if (result != null) {
+ return result;
+ }
+ // now we can do the actual creation
+ LocalSession localSession = worldEdit.getSessionManager().get(player);
+ EditSession editSession = localSession.createEditSession(player);
+ editSession.enableStandardMode();
+ localSession.tellVersion(player);
+ return session = editSession;
+ } finally {
+ lock.unlockWrite(stamp);
+ }
+ }
+
+}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EntityRemoverConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EntityRemoverConverter.java
new file mode 100644
index 000000000..d2e4b6e35
--- /dev/null
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EntityRemoverConverter.java
@@ -0,0 +1,57 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.command.argument;
+
+import com.sk89q.worldedit.command.util.EntityRemover;
+import com.sk89q.worldedit.util.formatting.text.Component;
+import com.sk89q.worldedit.util.formatting.text.TextComponent;
+import org.enginehub.piston.CommandManager;
+import org.enginehub.piston.converter.ArgumentConverter;
+import org.enginehub.piston.converter.ConversionResult;
+import org.enginehub.piston.converter.FailedConversion;
+import org.enginehub.piston.converter.SuccessfulConversion;
+import org.enginehub.piston.inject.InjectedValueAccess;
+import org.enginehub.piston.inject.Key;
+
+public class EntityRemoverConverter implements ArgumentConverter {
+
+ public static void register(CommandManager commandManager) {
+ commandManager.registerConverter(Key.of(EntityRemover.class), new EntityRemoverConverter());
+ }
+
+ private EntityRemoverConverter() {
+ }
+
+ @Override
+ public Component describeAcceptableArguments() {
+ return TextComponent.of(
+ "projectiles, items, paintings, itemframes, boats, minecarts, tnt, xp, or all"
+ );
+ }
+
+ @Override
+ public ConversionResult convert(String argument, InjectedValueAccess context) {
+ try {
+ return SuccessfulConversion.fromSingle(EntityRemover.fromString(argument));
+ } catch (Exception e) {
+ return FailedConversion.from(e);
+ }
+ }
+}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java
new file mode 100644
index 000000000..14a49b38c
--- /dev/null
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java
@@ -0,0 +1,71 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.command.argument;
+
+import com.google.common.collect.ImmutableSet;
+import com.sk89q.worldedit.EditSession;
+import com.sk89q.worldedit.util.TreeGenerator;
+import org.enginehub.piston.CommandManager;
+import org.enginehub.piston.converter.ArgumentConverter;
+import org.enginehub.piston.converter.MultiKeyConverter;
+import org.enginehub.piston.inject.Key;
+
+import javax.annotation.Nullable;
+import java.util.EnumSet;
+import java.util.Set;
+import java.util.function.Function;
+
+public class EnumConverter {
+
+ public static void register(CommandManager commandManager) {
+ commandManager.registerConverter(Key.of(SelectorChoice.class),
+ basic(SelectorChoice.class, SelectorChoice.UNKNOWN));
+ commandManager.registerConverter(Key.of(TreeGenerator.TreeType.class),
+ full(TreeGenerator.TreeType.class,
+ t -> ImmutableSet.copyOf(t.lookupKeys),
+ null));
+ commandManager.registerConverter(Key.of(EditSession.ReorderMode.class),
+ full(EditSession.ReorderMode.class,
+ r -> ImmutableSet.of(r.getDisplayName()),
+ null));
+ }
+
+ private static > ArgumentConverter basic(Class enumClass) {
+ return full(enumClass, e -> ImmutableSet.of(e.name()), null);
+ }
+
+ private static > ArgumentConverter basic(Class enumClass, E unknownValue) {
+ return full(enumClass, e -> ImmutableSet.of(e.name()), unknownValue);
+ }
+
+ private static > ArgumentConverter full(Class enumClass,
+ Function> lookupKeys,
+ @Nullable E unknownValue) {
+ return MultiKeyConverter.from(
+ EnumSet.allOf(enumClass),
+ lookupKeys,
+ unknownValue
+ );
+ }
+
+ private EnumConverter() {
+ }
+
+}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParameterException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmount.java
similarity index 56%
rename from worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParameterException.java
rename to worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmount.java
index 2fe681ba7..062a330c9 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParameterException.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmount.java
@@ -17,27 +17,35 @@
* along with this program. If not, see .
*/
-package com.sk89q.worldedit.util.command.parametric;
+package com.sk89q.worldedit.command.argument;
-/**
- * Thrown if there is an error with a parameter.
- */
-public class ParameterException extends Exception {
+import javax.annotation.Nullable;
- public ParameterException() {
- super();
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public final class ExpandAmount {
+
+ public static ExpandAmount vert() {
+ return new ExpandAmount(null);
}
- public ParameterException(String message) {
- super(message);
+ public static ExpandAmount from(int amount) {
+ return new ExpandAmount(amount);
}
- public ParameterException(Throwable cause) {
- super(cause);
+ @Nullable
+ private final Integer amount;
+
+ private ExpandAmount(@Nullable Integer amount) {
+ this.amount = amount;
}
- public ParameterException(String message, Throwable cause) {
- super(message, cause);
+ public boolean isVert() {
+ return amount == null;
+ }
+
+ public int getAmount() {
+ return checkNotNull(amount, "This amount is vertical, i.e. undefined");
}
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java
new file mode 100644
index 000000000..4d431ebca
--- /dev/null
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java
@@ -0,0 +1,70 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.command.argument;
+
+import com.google.common.reflect.TypeToken;
+import com.sk89q.worldedit.util.formatting.text.Component;
+import com.sk89q.worldedit.util.formatting.text.TextComponent;
+import org.enginehub.piston.CommandManager;
+import org.enginehub.piston.converter.ArgumentConverter;
+import org.enginehub.piston.converter.ArgumentConverters;
+import org.enginehub.piston.converter.ConversionResult;
+import org.enginehub.piston.converter.SuccessfulConversion;
+import org.enginehub.piston.inject.InjectedValueAccess;
+import org.enginehub.piston.inject.Key;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix;
+
+public class ExpandAmountConverter implements ArgumentConverter {
+
+ public static void register(CommandManager commandManager) {
+ commandManager.registerConverter(Key.of(ExpandAmount.class), new ExpandAmountConverter());
+ }
+
+ private final ArgumentConverter integerConverter =
+ ArgumentConverters.get(TypeToken.of(int.class));
+
+ private ExpandAmountConverter() {
+ }
+
+ @Override
+ public Component describeAcceptableArguments() {
+ return TextComponent.of("`vert` or " + integerConverter.describeAcceptableArguments());
+ }
+
+ @Override
+ public List getSuggestions(String input) {
+ return limitByPrefix(Stream.concat(
+ Stream.of("vert"), integerConverter.getSuggestions(input).stream()
+ ), input);
+ }
+
+ @Override
+ public ConversionResult convert(String argument, InjectedValueAccess context) {
+ if (argument.equalsIgnoreCase("vert")
+ || argument.equalsIgnoreCase("vertical")) {
+ return SuccessfulConversion.fromSingle(ExpandAmount.vert());
+ }
+ return integerConverter.convert(argument, context).mapSingle(ExpandAmount::from);
+ }
+}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java
new file mode 100644
index 000000000..0de24e5a7
--- /dev/null
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java
@@ -0,0 +1,98 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.command.argument;
+
+import com.sk89q.worldedit.LocalSession;
+import com.sk89q.worldedit.WorldEdit;
+import com.sk89q.worldedit.blocks.BaseItem;
+import com.sk89q.worldedit.entity.Entity;
+import com.sk89q.worldedit.extension.input.InputParseException;
+import com.sk89q.worldedit.extension.input.ParserContext;
+import com.sk89q.worldedit.extension.platform.Actor;
+import com.sk89q.worldedit.extent.Extent;
+import com.sk89q.worldedit.function.mask.Mask;
+import com.sk89q.worldedit.function.pattern.Pattern;
+import com.sk89q.worldedit.internal.registry.AbstractFactory;
+import com.sk89q.worldedit.util.formatting.text.Component;
+import com.sk89q.worldedit.util.formatting.text.TextComponent;
+import com.sk89q.worldedit.world.World;
+import org.enginehub.piston.CommandManager;
+import org.enginehub.piston.converter.ArgumentConverter;
+import org.enginehub.piston.converter.ConversionResult;
+import org.enginehub.piston.converter.FailedConversion;
+import org.enginehub.piston.converter.SuccessfulConversion;
+import org.enginehub.piston.inject.InjectedValueAccess;
+import org.enginehub.piston.inject.Key;
+
+import java.util.function.Function;
+
+public class FactoryConverter implements ArgumentConverter {
+
+ public static void register(WorldEdit worldEdit, CommandManager commandManager) {
+ commandManager.registerConverter(Key.of(Pattern.class),
+ new FactoryConverter<>(worldEdit, WorldEdit::getPatternFactory, "pattern"));
+ commandManager.registerConverter(Key.of(Mask.class),
+ new FactoryConverter<>(worldEdit, WorldEdit::getMaskFactory, "mask"));
+ commandManager.registerConverter(Key.of(BaseItem.class),
+ new FactoryConverter<>(worldEdit, WorldEdit::getItemFactory, "item"));
+ }
+
+ private final WorldEdit worldEdit;
+ private final Function> factoryExtractor;
+ private final String description;
+
+ private FactoryConverter(WorldEdit worldEdit,
+ Function> factoryExtractor,
+ String description) {
+ this.worldEdit = worldEdit;
+ this.factoryExtractor = factoryExtractor;
+ this.description = description;
+ }
+
+ @Override
+ public ConversionResult convert(String argument, InjectedValueAccess context) {
+ Actor actor = context.injectedValue(Key.of(Actor.class))
+ .orElseThrow(() -> new IllegalStateException("No actor"));
+ LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor);
+
+ ParserContext parserContext = new ParserContext();
+ parserContext.setActor(actor);
+ if (actor instanceof Entity) {
+ Extent extent = ((Entity) actor).getExtent();
+ if (extent instanceof World) {
+ parserContext.setWorld((World) extent);
+ }
+ }
+ parserContext.setSession(session);
+
+ try {
+ return SuccessfulConversion.fromSingle(
+ factoryExtractor.apply(worldEdit).parseFromInput(argument, parserContext)
+ );
+ } catch (InputParseException e) {
+ return FailedConversion.from(e);
+ }
+ }
+
+ @Override
+ public Component describeAcceptableArguments() {
+ return TextComponent.of("any " + description);
+ }
+}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemParser.java
deleted file mode 100644
index 880c17fb8..000000000
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemParser.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * WorldEdit, a Minecraft world manipulation toolkit
- * Copyright (C) sk89q
- * Copyright (C) WorldEdit team and contributors
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by the
- * Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.sk89q.worldedit.command.argument;
-
-import com.sk89q.minecraft.util.commands.CommandException;
-import com.sk89q.minecraft.util.commands.CommandLocals;
-import com.sk89q.worldedit.LocalSession;
-import com.sk89q.worldedit.WorldEdit;
-import com.sk89q.worldedit.blocks.BaseItem;
-import com.sk89q.worldedit.entity.Entity;
-import com.sk89q.worldedit.extension.input.InputParseException;
-import com.sk89q.worldedit.extension.input.ParserContext;
-import com.sk89q.worldedit.extension.platform.Actor;
-import com.sk89q.worldedit.extent.Extent;
-import com.sk89q.worldedit.util.command.argument.CommandArgs;
-import com.sk89q.worldedit.util.command.composition.SimpleCommand;
-import com.sk89q.worldedit.world.World;
-
-public class ItemParser extends SimpleCommand {
-
- private final StringParser stringParser;
-
- public ItemParser(String name) {
- stringParser = addParameter(new StringParser(name, "The item name", null));
- }
-
- public ItemParser(String name, String defaultSuggestion) {
- stringParser = addParameter(new StringParser(name, "The item name", defaultSuggestion));
- }
-
- @Override
- public BaseItem call(CommandArgs args, CommandLocals locals) throws CommandException {
- String itemString = stringParser.call(args, locals);
-
- Actor actor = locals.get(Actor.class);
- LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor);
-
- ParserContext parserContext = new ParserContext();
- parserContext.setActor(actor);
- if (actor instanceof Entity) {
- Extent extent = ((Entity) actor).getExtent();
- if (extent instanceof World) {
- parserContext.setWorld((World) extent);
- }
- }
- parserContext.setSession(session);
-
- try {
- return WorldEdit.getInstance().getItemFactory().parseFromInput(itemString, parserContext);
- } catch (InputParseException e) {
- throw new CommandException(e.getMessage(), e);
- }
- }
-
- @Override
- public String getDescription() {
- return "Match an item";
- }
-
- @Override
- protected boolean testPermission0(CommandLocals locals) {
- return true;
- }
-
-}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemUseParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemUseParser.java
deleted file mode 100644
index f6da447a1..000000000
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemUseParser.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * WorldEdit, a Minecraft world manipulation toolkit
- * Copyright (C) sk89q
- * Copyright (C) WorldEdit team and contributors
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by the
- * Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.sk89q.worldedit.command.argument;
-
-import com.sk89q.minecraft.util.commands.CommandException;
-import com.sk89q.minecraft.util.commands.CommandLocals;
-import com.sk89q.worldedit.EditSession;
-import com.sk89q.worldedit.WorldEditException;
-import com.sk89q.worldedit.blocks.BaseItem;
-import com.sk89q.worldedit.function.Contextual;
-import com.sk89q.worldedit.function.EditContext;
-import com.sk89q.worldedit.function.RegionFunction;
-import com.sk89q.worldedit.math.BlockVector3;
-import com.sk89q.worldedit.util.Direction;
-import com.sk89q.worldedit.util.command.argument.CommandArgs;
-import com.sk89q.worldedit.util.command.composition.SimpleCommand;
-import com.sk89q.worldedit.world.World;
-
-public class ItemUseParser extends SimpleCommand> {
-
- private final ItemParser itemParser = addParameter(new ItemParser("item", "minecraft:bone_meal"));
-
- @Override
- public Contextual call(CommandArgs args, CommandLocals locals) throws CommandException {
- BaseItem item = itemParser.call(args, locals);
- return new ItemUseFactory(item);
- }
-
- @Override
- public String getDescription() {
- return "Applies an item";
- }
-
- @Override
- protected boolean testPermission0(CommandLocals locals) {
- return true;
- }
-
- private static final class ItemUseFactory implements Contextual {
- private final BaseItem item;
-
- private ItemUseFactory(BaseItem item) {
- this.item = item;
- }
-
- @Override
- public RegionFunction createFromContext(EditContext input) {
- World world = ((EditSession) input.getDestination()).getWorld();
- return new ItemUseFunction(world, item);
- }
-
- @Override
- public String toString() {
- return "application of the item " + item.getType() + ":" + item.getNbtData();
- }
- }
-
- private static final class ItemUseFunction implements RegionFunction {
- private final World world;
- private final BaseItem item;
-
- private ItemUseFunction(World world, BaseItem item) {
- this.world = world;
- this.item = item;
- }
-
- @Override
- public boolean apply(BlockVector3 position) throws WorldEditException {
- return world.useItem(position, item, Direction.UP);
- }
- }
-
-}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/NumberParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/NumberParser.java
deleted file mode 100644
index 349089e50..000000000
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/NumberParser.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * WorldEdit, a Minecraft world manipulation toolkit
- * Copyright (C) sk89q
- * Copyright (C) WorldEdit team and contributors
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by the
- * Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.sk89q.worldedit.command.argument;
-
-import com.google.common.collect.Lists;
-import com.sk89q.minecraft.util.commands.CommandException;
-import com.sk89q.minecraft.util.commands.CommandLocals;
-import com.sk89q.worldedit.util.command.argument.CommandArgs;
-import com.sk89q.worldedit.util.command.argument.MissingArgumentException;
-import com.sk89q.worldedit.util.command.composition.CommandExecutor;
-
-import java.util.Collections;
-import java.util.List;
-
-public class NumberParser implements CommandExecutor {
-
- private final String name;
- private final String description;
- private final String defaultSuggestion;
-
- public NumberParser(String name, String description) {
- this(name, description, null);
- }
-
- public NumberParser(String name, String description, String defaultSuggestion) {
- this.name = name;
- this.description = description;
- this.defaultSuggestion = defaultSuggestion;
- }
-
- @Override
- public Number call(CommandArgs args, CommandLocals locals) throws CommandException {
- try {
- String next = args.next();
- try {
- return Double.parseDouble(next);
- } catch (NumberFormatException ignored) {
- throw new CommandException("The value for <" + name + "> should be a number. '" + next + "' is not a number.");
- }
- } catch (MissingArgumentException e) {
- throw new CommandException("Missing value for <" + name + "> (try a number).");
- }
- }
-
- @Override
- public List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException {
- String value = args.next();
- return value.isEmpty() && defaultSuggestion != null ? Lists.newArrayList(defaultSuggestion) : Collections.emptyList();
- }
-
- @Override
- public String getUsage() {
- return "<" + name + ">";
- }
-
- @Override
- public String getDescription() {
- return description;
- }
-
- @Override
- public boolean testPermission(CommandLocals locals) {
- return true;
- }
-
-}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PatternParser.java
deleted file mode 100644
index e8d209e4c..000000000
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PatternParser.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * WorldEdit, a Minecraft world manipulation toolkit
- * Copyright (C) sk89q
- * Copyright (C) WorldEdit team and contributors
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by the
- * Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.sk89q.worldedit.command.argument;
-
-import com.sk89q.minecraft.util.commands.CommandException;
-import com.sk89q.minecraft.util.commands.CommandLocals;
-import com.sk89q.worldedit.LocalSession;
-import com.sk89q.worldedit.WorldEdit;
-import com.sk89q.worldedit.entity.Entity;
-import com.sk89q.worldedit.extension.input.InputParseException;
-import com.sk89q.worldedit.extension.input.ParserContext;
-import com.sk89q.worldedit.extension.platform.Actor;
-import com.sk89q.worldedit.extent.Extent;
-import com.sk89q.worldedit.function.pattern.Pattern;
-import com.sk89q.worldedit.util.command.argument.CommandArgs;
-import com.sk89q.worldedit.util.command.composition.SimpleCommand;
-import com.sk89q.worldedit.world.World;
-
-public class PatternParser extends SimpleCommand {
-
- private final StringParser stringParser;
-
- public PatternParser(String name) {
- stringParser = addParameter(new StringParser(name, "The pattern"));
- }
-
- @Override
- public Pattern call(CommandArgs args, CommandLocals locals) throws CommandException {
- String patternString = stringParser.call(args, locals);
-
- Actor actor = locals.get(Actor.class);
- LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor);
-
- ParserContext parserContext = new ParserContext();
- parserContext.setActor(actor);
- if (actor instanceof Entity) {
- Extent extent = ((Entity) actor).getExtent();
- if (extent instanceof World) {
- parserContext.setWorld((World) extent);
- }
- }
- parserContext.setSession(session);
-
- try {
- return WorldEdit.getInstance().getPatternFactory().parseFromInput(patternString, parserContext);
- } catch (InputParseException e) {
- throw new CommandException(e.getMessage(), e);
- }
- }
-
- @Override
- public String getDescription() {
- return "Choose a pattern";
- }
-
- @Override
- public boolean testPermission0(CommandLocals locals) {
- return true;
- }
-
-}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryConverter.java
new file mode 100644
index 000000000..15624d31b
--- /dev/null
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryConverter.java
@@ -0,0 +1,49 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.command.argument;
+
+import com.google.common.collect.ImmutableSetMultimap;
+import com.sk89q.worldedit.regions.factory.CuboidRegionFactory;
+import com.sk89q.worldedit.regions.factory.CylinderRegionFactory;
+import com.sk89q.worldedit.regions.factory.RegionFactory;
+import com.sk89q.worldedit.regions.factory.SphereRegionFactory;
+import org.enginehub.piston.CommandManager;
+import org.enginehub.piston.converter.MultiKeyConverter;
+import org.enginehub.piston.inject.Key;
+
+public class RegionFactoryConverter {
+
+ public static void register(CommandManager commandManager) {
+ commandManager.registerConverter(Key.of(RegionFactory.class),
+ MultiKeyConverter.builder(
+ ImmutableSetMultimap.builder()
+ .put(new CuboidRegionFactory(), "cuboid")
+ .put(new SphereRegionFactory(), "sphere")
+ .putAll(new CylinderRegionFactory(1), "cyl", "cylinder")
+ .build()
+ )
+ .errorMessage(arg -> "Not a known region type: " + arg)
+ .build()
+ );
+ }
+
+ private RegionFactoryConverter() {
+ }
+}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryParser.java
deleted file mode 100644
index 9ec0ce101..000000000
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryParser.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * WorldEdit, a Minecraft world manipulation toolkit
- * Copyright (C) sk89q
- * Copyright (C) WorldEdit team and contributors
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by the
- * Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.sk89q.worldedit.command.argument;
-
-import com.google.common.collect.Lists;
-import com.sk89q.minecraft.util.commands.CommandException;
-import com.sk89q.minecraft.util.commands.CommandLocals;
-import com.sk89q.worldedit.regions.factory.CuboidRegionFactory;
-import com.sk89q.worldedit.regions.factory.CylinderRegionFactory;
-import com.sk89q.worldedit.regions.factory.RegionFactory;
-import com.sk89q.worldedit.regions.factory.SphereRegionFactory;
-import com.sk89q.worldedit.util.command.argument.ArgumentUtils;
-import com.sk89q.worldedit.util.command.argument.CommandArgs;
-import com.sk89q.worldedit.util.command.argument.MissingArgumentException;
-import com.sk89q.worldedit.util.command.composition.CommandExecutor;
-
-import java.util.List;
-
-public class RegionFactoryParser implements CommandExecutor {
-
- @Override
- public RegionFactory call(CommandArgs args, CommandLocals locals) throws CommandException {
- try {
- String type = args.next();
-
- switch (type) {
- case "cuboid":
- return new CuboidRegionFactory();
- case "sphere":
- return new SphereRegionFactory();
- case "cyl":
- case "cylinder":
- return new CylinderRegionFactory(1); // TODO: Adjustable height
-
- default:
- throw new CommandException("Unknown shape type: " + type + " (try one of " + getUsage() + ")");
- }
- } catch (MissingArgumentException e) {
- throw new CommandException("Missing shape type (try one of " + getUsage() + ")");
-
- }
- }
-
- @Override
- public List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException {
- return ArgumentUtils.getMatchingSuggestions(Lists.newArrayList("cuboid", "sphere", "cyl"), args.next());
- }
-
- @Override
- public String getUsage() {
- return "(cuboid | sphere | cyl)";
- }
-
- @Override
- public String getDescription() {
- return "Defines a region";
- }
-
- @Override
- public boolean testPermission(CommandLocals locals) {
- return true;
- }
-
-}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java
new file mode 100644
index 000000000..7bafb86e9
--- /dev/null
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java
@@ -0,0 +1,110 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.command.argument;
+
+import com.google.common.collect.ImmutableList;
+import com.sk89q.worldedit.registry.Registry;
+import com.sk89q.worldedit.util.formatting.text.Component;
+import com.sk89q.worldedit.util.formatting.text.TextComponent;
+import com.sk89q.worldedit.world.biome.BiomeType;
+import com.sk89q.worldedit.world.block.BlockCategory;
+import com.sk89q.worldedit.world.block.BlockType;
+import com.sk89q.worldedit.world.entity.EntityType;
+import com.sk89q.worldedit.world.fluid.FluidCategory;
+import com.sk89q.worldedit.world.fluid.FluidType;
+import com.sk89q.worldedit.world.gamemode.GameMode;
+import com.sk89q.worldedit.world.item.ItemCategory;
+import com.sk89q.worldedit.world.item.ItemType;
+import com.sk89q.worldedit.world.weather.WeatherType;
+import org.enginehub.piston.CommandManager;
+import org.enginehub.piston.converter.ArgumentConverter;
+import org.enginehub.piston.converter.ConversionResult;
+import org.enginehub.piston.converter.FailedConversion;
+import org.enginehub.piston.converter.SuccessfulConversion;
+import org.enginehub.piston.inject.InjectedValueAccess;
+import org.enginehub.piston.inject.Key;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix;
+
+public class RegistryConverter implements ArgumentConverter {
+
+ @SuppressWarnings("unchecked")
+ public static void register(CommandManager commandManager) {
+ ImmutableList.of(
+ BlockType.class,
+ BlockCategory.class,
+ ItemType.class,
+ ItemCategory.class,
+ BiomeType.class,
+ EntityType.class,
+ FluidType.class,
+ FluidCategory.class,
+ GameMode.class,
+ WeatherType.class
+ ).stream()
+ .map(c -> (Class