Merge pull request #464 from EngineHub/feature/piston-commands

Piston command system.
This commit is contained in:
wizjany 2019-05-01 00:33:43 -04:00 committed by GitHub
commit b47c70025e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
175 changed files with 5122 additions and 9247 deletions

View File

@ -78,6 +78,11 @@ subprojects {
maven { url "http://maven.sk89q.com/repo/" } maven { url "http://maven.sk89q.com/repo/" }
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
} }
configurations.all {
resolutionStrategy {
cacheChangingModulesFor 5, 'minutes'
}
}
} }
configure(['core', 'bukkit', 'forge', 'sponge'].collect { project(":worldedit-$it") }) { configure(['core', 'bukkit', 'forge', 'sponge'].collect { project(":worldedit-$it") }) {

View File

@ -53,5 +53,13 @@
<!-- <module name="PackageName"/> Unlikely that we would miss this in a PR --> <!-- <module name="PackageName"/> Unlikely that we would miss this in a PR -->
<module name="ParameterName"/> <module name="ParameterName"/>
<!-- <module name="TypeName"/> Unlikely that we would miss this in a PR --> <!-- <module name="TypeName"/> Unlikely that we would miss this in a PR -->
<!-- Validate assignment operators -->
<module name="WhitespaceAround">
<property name="tokens" value="ASSIGN"/>
</module>
</module>
<!-- Validate that command annotations are formatted correctly -->
<module name="RegexpMultiline">
<property name="format" value="^( +)@(Arg|Switch|Command)\(.*?\n\1 {5,}"/>
</module> </module>
</module> </module>

View File

@ -16,6 +16,7 @@
<allow pkg="net.royawesome.jlibnoise"/> <allow pkg="net.royawesome.jlibnoise"/>
<allow pkg="org.json.simple" /> <allow pkg="org.json.simple" />
<allow pkg="org.slf4j"/> <allow pkg="org.slf4j"/>
<allow pkg="org.enginehub"/>
<subpackage name="util.yaml"> <subpackage name="util.yaml">
<allow pkg="org.yaml.snakeyaml"/> <allow pkg="org.yaml.snakeyaml"/>
@ -38,6 +39,7 @@
<subpackage name="worldedit"> <subpackage name="worldedit">
<allow pkg="org.mozilla.javascript"/> <allow pkg="org.mozilla.javascript"/>
<allow pkg="de.schlichtherle"/> <allow pkg="de.schlichtherle"/>
<allow pkg="com.google.auto"/>
<subpackage name="bukkit"> <subpackage name="bukkit">
<allow pkg="org.bukkit"/> <allow pkg="org.bukkit"/>

View File

@ -1,5 +1,6 @@
#Thu Mar 14 00:19:48 PDT 2019
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip

View File

@ -5,4 +5,5 @@ include 'worldedit-libs'
['bukkit', 'core', 'forge', 'sponge'].forEach { ['bukkit', 'core', 'forge', 'sponge'].forEach {
include "worldedit-libs:$it" include "worldedit-libs:$it"
include "worldedit-$it" include "worldedit-$it"
} }
include "worldedit-libs:core:ap"

View File

@ -8,6 +8,12 @@ repositories {
maven { url 'https://papermc.io/repo/repository/maven-public/' } 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 { dependencies {
compile project(':worldedit-core') compile project(':worldedit-core')
compile project(':worldedit-libs:bukkit') compile project(':worldedit-libs:bukkit')

View File

@ -31,6 +31,8 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@Deprecated
@SuppressWarnings("deprecation")
public class CommandsManagerRegistration extends CommandRegistration { public class CommandsManagerRegistration extends CommandRegistration {
protected CommandsManager<?> commands; protected CommandsManager<?> commands;

View File

@ -35,6 +35,7 @@ import java.util.List;
/** /**
* An implementation of a dynamically registered {@link org.bukkit.command.Command} attached to a plugin * 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 { public class DynamicPluginCommand extends org.bukkit.command.Command implements PluginIdentifiableCommand {
protected final CommandExecutor owner; protected final CommandExecutor owner;

View File

@ -30,6 +30,7 @@ import org.bukkit.help.HelpTopicFactory;
import java.util.Map; import java.util.Map;
@SuppressWarnings("deprecation")
public class DynamicPluginCommandHelpTopic extends HelpTopic { public class DynamicPluginCommandHelpTopic extends HelpTopic {
private final DynamicPluginCommand cmd; private final DynamicPluginCommand cmd;

View File

@ -20,25 +20,31 @@
package com.sk89q.worldedit.bukkit; package com.sk89q.worldedit.bukkit;
import com.sk89q.bukkit.util.CommandInspector; import com.sk89q.bukkit.util.CommandInspector;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.extension.platform.Actor; 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.Command;
import org.bukkit.command.CommandSender; 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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Optional;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.bukkit.BukkitTextAdapter.reduceToText;
class BukkitCommandInspector implements CommandInspector { class BukkitCommandInspector implements CommandInspector {
private static final Logger logger = LoggerFactory.getLogger(BukkitCommandInspector.class); private static final Logger logger = LoggerFactory.getLogger(BukkitCommandInspector.class);
private final WorldEditPlugin plugin; 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(plugin);
checkNotNull(dispatcher); checkNotNull(dispatcher);
this.plugin = plugin; this.plugin = plugin;
@ -47,9 +53,9 @@ class BukkitCommandInspector implements CommandInspector {
@Override @Override
public String getShortText(Command command) { public String getShortText(Command command) {
CommandMapping mapping = dispatcher.get(command.getName()); Optional<org.enginehub.piston.Command> mapping = dispatcher.getCommand(command.getName());
if (mapping != null) { if (mapping.isPresent()) {
return mapping.getDescription().getDescription(); return reduceToText(mapping.get().getDescription());
} else { } else {
logger.warn("BukkitCommandInspector doesn't know how about the command '" + command + "'"); logger.warn("BukkitCommandInspector doesn't know how about the command '" + command + "'");
return "Help text not available"; return "Help text not available";
@ -58,10 +64,9 @@ class BukkitCommandInspector implements CommandInspector {
@Override @Override
public String getFullText(Command command) { public String getFullText(Command command) {
CommandMapping mapping = dispatcher.get(command.getName()); Optional<org.enginehub.piston.Command> mapping = dispatcher.getCommand(command.getName());
if (mapping != null) { if (mapping.isPresent()) {
Description description = mapping.getDescription(); return reduceToText(mapping.get().getFullHelp());
return "Usage: " + description.getUsage() + (description.getHelp() != null ? "\n" + description.getHelp() : "");
} else { } else {
logger.warn("BukkitCommandInspector doesn't know how about the command '" + command + "'"); logger.warn("BukkitCommandInspector doesn't know how about the command '" + command + "'");
return "Help text not available"; return "Help text not available";
@ -70,11 +75,15 @@ class BukkitCommandInspector implements CommandInspector {
@Override @Override
public boolean testPermission(CommandSender sender, Command command) { public boolean testPermission(CommandSender sender, Command command) {
CommandMapping mapping = dispatcher.get(command.getName()); Optional<org.enginehub.piston.Command> mapping = dispatcher.getCommand(command.getName());
if (mapping != null) { if (mapping.isPresent()) {
CommandLocals locals = new CommandLocals(); InjectedValueStore store = MapBackedValueStore.create();
locals.put(Actor.class, plugin.wrapCommandSender(sender)); store.injectValue(Key.of(Actor.class), context ->
return mapping.getCallable().testPermission(locals); Optional.of(plugin.wrapCommandSender(sender)));
CommandParameters parameters = NoInputCommandParameters.builder()
.injectedValues(MemoizingValueAccess.wrap(store))
.build();
return mapping.get().getCondition().satisfied(parameters);
} else { } else {
logger.warn("BukkitCommandInspector doesn't know how about the command '" + command + "'"); logger.warn("BukkitCommandInspector doesn't know how about the command '" + command + "'");
return false; return false;

View File

@ -26,7 +26,7 @@ import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.internal.cui.CUIEvent;
import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.session.SessionKey;
import com.sk89q.worldedit.util.auth.AuthorizationException; 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 com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -94,7 +94,7 @@ public class BukkitCommandSender implements Actor {
} }
@Override @Override
public void print(TextComponent component) { public void print(Component component) {
TextAdapter.sendComponent(sender, component); TextAdapter.sendComponent(sender, component);
} }

View File

@ -31,13 +31,13 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.session.SessionKey;
import com.sk89q.worldedit.util.HandSide; 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.World;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldedit.world.gamemode.GameModes; 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 com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@ -127,7 +127,7 @@ public class BukkitPlayer extends AbstractPlayerActor {
} }
@Override @Override
public void print(TextComponent component) { public void print(Component component) {
TextAdapter.sendComponent(player, component); TextAdapter.sendComponent(player, component);
} }

View File

@ -22,27 +22,29 @@ package com.sk89q.worldedit.bukkit;
import com.sk89q.bukkit.util.CommandInfo; import com.sk89q.bukkit.util.CommandInfo;
import com.sk89q.bukkit.util.CommandRegistration; import com.sk89q.bukkit.util.CommandRegistration;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.command.util.PermissionCondition;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.MultiUserPlatform; import com.sk89q.worldedit.extension.platform.MultiUserPlatform;
import com.sk89q.worldedit.extension.platform.Preference; 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 com.sk89q.worldedit.world.registry.Registries;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.enginehub.piston.CommandManager;
import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.List; import java.util.List;
import java.util.Map; 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 class BukkitServerInterface implements MultiUserPlatform {
public Server server; public Server server;
@ -70,7 +72,7 @@ public class BukkitServerInterface implements MultiUserPlatform {
if (plugin.getBukkitImplAdapter() != null) { if (plugin.getBukkitImplAdapter() != null) {
return plugin.getBukkitImplAdapter().getDataVersion(); return plugin.getBukkitImplAdapter().getDataVersion();
} }
return 0; return -1;
} }
@Override @Override
@ -124,20 +126,25 @@ public class BukkitServerInterface implements MultiUserPlatform {
} }
@Override @Override
public void registerCommands(Dispatcher dispatcher) { public void registerCommands(CommandManager dispatcher) {
List<CommandInfo> toRegister = new ArrayList<>();
BukkitCommandInspector inspector = new BukkitCommandInspector(plugin, dispatcher); BukkitCommandInspector inspector = new BukkitCommandInspector(plugin, dispatcher);
for (CommandMapping command : dispatcher.getCommands()) {
Description description = command.getDescription();
List<String> 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 @Override

View File

@ -0,0 +1,48 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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() {
}
}

View File

@ -21,13 +21,11 @@
package com.sk89q.worldedit.bukkit; package com.sk89q.worldedit.bukkit;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.util.StringUtil; import com.sk89q.util.StringUtil;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.command.CommandMapping;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.event.Event.Result; 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.PlayerGameModeChangeEvent;
import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot; 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.Optional;
import java.util.stream.Collectors;
/** /**
* Handles all events thrown in relation to a Player * Handles all events thrown in relation to a Player
@ -87,7 +91,7 @@ public class WorldEditListener implements Listener {
if (split.length > 0) { if (split.length > 0) {
split[0] = split[0].substring(1); 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, " "); final String newMessage = "/" + StringUtil.joinString(split, " ");
@ -108,13 +112,19 @@ public class WorldEditListener implements Listener {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerCommand(PlayerCommandSendEvent event) { public void onPlayerCommand(PlayerCommandSendEvent event) {
CommandLocals locals = new CommandLocals(); InjectedValueStore store = MapBackedValueStore.create();
locals.put(Actor.class, plugin.wrapCommandSender(event.getPlayer())); store.injectValue(Key.of(Actor.class), context ->
Set<String> toRemove = plugin.getWorldEdit().getPlatformManager().getCommandManager().getDispatcher().getCommands().stream() Optional.of(plugin.wrapCommandSender(event.getPlayer())));
.filter(commandMapping -> !commandMapping.getCallable().testPermission(locals)) CommandParameters parameters = NoInputCommandParameters.builder()
.map(CommandMapping::getPrimaryAlias) .injectedValues(MemoizingValueAccess.wrap(store))
.collect(Collectors.toSet()); .build();
event.getCommands().removeIf(toRemove::contains); 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()
);
} }
/** /**

View File

@ -289,7 +289,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
// code of WorldEdit expects it // code of WorldEdit expects it
String[] split = new String[args.length + 1]; String[] split = new String[args.length + 1];
System.arraycopy(args, 0, split, 1, args.length); 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)); CommandEvent event = new CommandEvent(wrapCommandSender(sender), Joiner.on(" ").join(split));
getWorldEdit().getEventBus().post(event); getWorldEdit().getEventBus().post(event);
@ -303,7 +303,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
// code of WorldEdit expects it // code of WorldEdit expects it
String[] split = new String[args.length + 1]; String[] split = new String[args.length + 1];
System.arraycopy(args, 0, split, 1, args.length); 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)); CommandSuggestionEvent event = new CommandSuggestionEvent(wrapCommandSender(sender), Joiner.on(" ").join(split));
getWorldEdit().getEventBus().post(event); getWorldEdit().getEventBus().post(event);

View File

@ -1,28 +1,52 @@
apply plugin: 'eclipse' plugins {
apply plugin: 'idea' id("net.ltgt.apt") version "0.21"
}
dependencies {
compile project(':worldedit-libs:core') apply plugin: 'java-library'
compile 'de.schlichtherle:truezip:6.8.3' apply plugin: 'eclipse'
compile 'rhino:js:1.7R2' apply plugin: 'idea'
compile 'org.yaml:snakeyaml:1.9' apply plugin: 'net.ltgt.apt-eclipse'
compile 'com.google.guava:guava:21.0' apply plugin: 'net.ltgt.apt-idea'
compile 'com.google.code.findbugs:jsr305:1.3.9'
compile 'com.google.code.gson:gson:2.8.0' configurations.all { Configuration it ->
compile 'com.googlecode.json-simple:json-simple:1.1.1' it.resolutionStrategy { ResolutionStrategy rs ->
compile 'org.slf4j:slf4j-api:1.7.26' rs.force("com.google.guava:guava:21.0")
//compile 'net.sf.trove4j:trove4j:3.0.3' }
testCompile 'org.mockito:mockito-core:1.9.0-rc1' }
}
dependencies {
sourceSets { compile project(':worldedit-libs:core')
main { compile 'de.schlichtherle:truezip:6.8.3'
java { compile 'rhino:js:1.7R2'
srcDir 'src/main/java' compile 'org.yaml:snakeyaml:1.9'
srcDir 'src/legacy/java' compile 'com.google.guava:guava:21.0'
} compile 'com.google.code.findbugs:jsr305:1.3.9'
resources { compile 'com.google.code.gson:gson:2.8.0'
srcDir 'src/main/resources' 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'
}
}
}

View File

@ -90,7 +90,7 @@ public class MobSpawnerBlock extends BaseBlock {
/** /**
* Get the spawn delay. * Get the spawn delay.
* *
* @return the delay * @return the delay
*/ */
public short getDelay() { public short getDelay() {
@ -99,13 +99,13 @@ public class MobSpawnerBlock extends BaseBlock {
/** /**
* Set the spawn delay. * Set the spawn delay.
* *
* @param delay the delay to set * @param delay the delay to set
*/ */
public void setDelay(short delay) { public void setDelay(short delay) {
this.delay = delay; this.delay = delay;
} }
@Override @Override
public boolean hasNbtData() { public boolean hasNbtData() {
return true; return true;
@ -208,7 +208,7 @@ public class MobSpawnerBlock extends BaseBlock {
this.spawnCount = spawnCountTag.getValue(); this.spawnCount = spawnCountTag.getValue();
} }
if (spawnRangeTag != null) { if (spawnRangeTag != null) {
this.spawnRange =spawnRangeTag.getValue(); this.spawnRange = spawnRangeTag.getValue();
} }
if (minSpawnDelayTag != null) { if (minSpawnDelayTag != null) {
this.minSpawnDelay = minSpawnDelayTag.getValue(); this.minSpawnDelay = minSpawnDelayTag.getValue();

View File

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
<format>tar.gz</format>
<format>tar.bz2</format>
<format>zip</format>
</formats>
<files>
<file>
<source>${project.build.directory}/${artifactId}-${project.version}.jar</source>
<destName>WorldEdit.jar</destName>
<outputDirectory>/</outputDirectory>
<filtered>false</filtered>
</file>
<file>
<source>README.html</source>
<outputDirectory>/</outputDirectory>
<filtered>true</filtered>
</file>
</files>
<fileSets>
<fileSet>
<includes>
<include>LICENSE.txt</include>
<include>CHANGELOG.txt</include>
<include>contrib/craftscripts/*</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View File

@ -60,6 +60,7 @@ import java.util.Set;
* @param <T> command sender class * @param <T> command sender class
*/ */
@SuppressWarnings("ProtectedField") @SuppressWarnings("ProtectedField")
@Deprecated
public abstract class CommandsManager<T> { public abstract class CommandsManager<T> {
protected static final Logger logger = protected static final Logger logger =

View File

@ -0,0 +1,24 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
/**
* 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;

View File

@ -122,7 +122,6 @@ import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
@ -175,15 +174,6 @@ public class EditSession implements Extent, AutoCloseable {
public String getDisplayName() { public String getDisplayName() {
return this.displayName; return this.displayName;
} }
public static Optional<ReorderMode> getFromDisplayName(String name) {
for (ReorderMode mode : values()) {
if (mode.getDisplayName().equalsIgnoreCase(name)) {
return Optional.of(mode);
}
}
return Optional.empty();
}
} }
@SuppressWarnings("ProtectedField") @SuppressWarnings("ProtectedField")
@ -914,16 +904,15 @@ public class EditSession implements Extent, AutoCloseable {
* Remove blocks of a certain type nearby a given position. * Remove blocks of a certain type nearby a given position.
* *
* @param position center position of cuboid * @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 * @param apothem an apothem of the cuboid, where the minimum is 1
* @return number of blocks affected * @return number of blocks affected
* @throws MaxChangedBlocksException thrown if too many blocks are changed * @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); checkNotNull(position);
checkArgument(apothem >= 1, "apothem >= 1"); checkArgument(apothem >= 1, "apothem >= 1");
Mask mask = new BlockTypeMask(this, blockType);
BlockVector3 adjustment = BlockVector3.ONE.multiply(apothem - 1); BlockVector3 adjustment = BlockVector3.ONE.multiply(apothem - 1);
Region region = new CuboidRegion( Region region = new CuboidRegion(
getWorld(), // Causes clamping of Y range getWorld(), // Causes clamping of Y range

View File

@ -52,6 +52,7 @@ import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.snapshot.Snapshot; import com.sk89q.worldedit.world.snapshot.Snapshot;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.time.ZoneId;
import java.util.Calendar; import java.util.Calendar;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
@ -91,7 +92,7 @@ public class LocalSession {
private transient int cuiVersion = -1; private transient int cuiVersion = -1;
private transient boolean fastMode = false; private transient boolean fastMode = false;
private transient Mask mask; private transient Mask mask;
private transient TimeZone timezone = TimeZone.getDefault(); private transient ZoneId timezone = ZoneId.systemDefault();
private transient BlockVector3 cuiTemporaryBlock; private transient BlockVector3 cuiTemporaryBlock;
private transient EditSession.ReorderMode reorderMode = EditSession.ReorderMode.MULTI_STAGE; private transient EditSession.ReorderMode reorderMode = EditSession.ReorderMode.MULTI_STAGE;
@ -169,7 +170,7 @@ public class LocalSession {
* *
* @return the timezone * @return the timezone
*/ */
public TimeZone getTimeZone() { public ZoneId getTimeZone() {
return timezone; return timezone;
} }
@ -178,7 +179,7 @@ public class LocalSession {
* *
* @param timezone the user's timezone * @param timezone the user's timezone
*/ */
public void setTimezone(TimeZone timezone) { public void setTimezone(ZoneId timezone) {
checkNotNull(timezone); checkNotNull(timezone);
this.timezone = timezone; this.timezone = timezone;
} }
@ -849,9 +850,10 @@ public class LocalSession {
public Calendar detectDate(String input) { public Calendar detectDate(String input) {
checkNotNull(input); checkNotNull(input);
Time.setTimeZone(getTimeZone()); TimeZone tz = TimeZone.getTimeZone(getTimeZone());
Time.setTimeZone(tz);
Options opt = new com.sk89q.jchronic.Options(); Options opt = new com.sk89q.jchronic.Options();
opt.setNow(Calendar.getInstance(getTimeZone())); opt.setNow(Calendar.getInstance(tz));
Span date = Chronic.parse(input, opt); Span date = Chronic.parse(input, opt);
if (date == null) { if (date == null) {
return null; return null;

View File

@ -303,6 +303,17 @@ public final class WorldEdit {
if (exts.size() != 1) { if (exts.size() != 1) {
exts = exts.subList(0, 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; File result = null;
for (Iterator<String> iter = exts.iterator(); iter.hasNext() && (result == null || (!isSave && !result.exists()));) { for (Iterator<String> 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) { private File getSafeFileWithExtension(File dir, String filename, String extension) {
if (extension != null) { if (extension != null) {
int dot = filename.lastIndexOf('.'); 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; filename += "." + extension;
} }
} }

View File

@ -0,0 +1,133 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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));
}
}

View File

@ -19,17 +19,13 @@
package com.sk89q.worldedit.command; 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.EditSession;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; 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.entity.Player;
import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.function.FlatRegionFunction; 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.Region;
import com.sk89q.worldedit.regions.Regions; import com.sk89q.worldedit.regions.Regions;
import com.sk89q.worldedit.util.Location; 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.World;
import com.sk89q.worldedit.world.biome.BiomeData; import com.sk89q.worldedit.world.biome.BiomeData;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.registry.BiomeRegistry; 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.HashSet;
import java.util.Objects;
import java.util.Set; 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". * Implements biome-related commands such as "/biomelist".
*/ */
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class BiomeCommands { public class BiomeCommands {
private final WorldEdit worldEdit;
/** /**
* Create a new instance. * Create a new instance.
*
* @param worldEdit reference to WorldEdit
*/ */
public BiomeCommands(WorldEdit worldEdit) { public BiomeCommands() {
checkNotNull(worldEdit);
this.worldEdit = worldEdit;
} }
@Command( @Command(
aliases = { "biomelist", "biomels" }, name = "biomelist",
usage = "[page]", aliases = { "biomels" },
desc = "Gets all biomes available.", desc = "Gets all biomes available."
max = 1
) )
@CommandPermissions("worldedit.biome.list") @CommandPermissions("worldedit.biome.list")
public void biomeList(Player player, CommandContext args) throws WorldEditException { public void biomeList(Player player,
int page; @Arg(desc = "Page number.", def = "1")
int offset; int page) throws WorldEditException {
int count = 0;
if (args.argsLength() == 0 || (page = args.getInteger(0)) < 2) {
page = 1;
offset = 0;
} else {
offset = (page - 1) * 19;
}
BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager() BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry(); .queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry();
Collection<BiomeType> biomes = BiomeType.REGISTRY.values();
int totalPages = biomes.size() / 19 + 1; PaginationBox paginationBox = PaginationBox.fromStrings("Available Biomes", "/biomelist %page%",
player.print("Available Biomes (page " + page + "/" + totalPages + ") :"); BiomeType.REGISTRY.values().stream()
for (BiomeType biome : biomes) { .map(biomeRegistry::getData).filter(Objects::nonNull)
if (offset > 0) { .map(BiomeData::getName).collect(Collectors.toList()));
offset--; player.print(paginationBox.create(page));
} else {
BiomeData data = biomeRegistry.getData(biome);
if (data != null) {
player.print(" " + data.getName());
if (++count == 19) {
break;
}
} else {
player.print(" <unknown #" + biome.getId() + ">");
}
}
}
} }
@Command( @Command(
aliases = { "biomeinfo" }, name = "biomeinfo",
flags = "pt",
desc = "Get the biome of the targeted block.", desc = "Get the biome of the targeted block.",
help = descFooter = "By default, uses all blocks in your selection."
"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
) )
@CommandPermissions("worldedit.biome.info") @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() BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry(); .queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry();
Set<BiomeType> biomes = new HashSet<>(); Set<BiomeType> biomes = new HashSet<>();
String qualifier; String qualifier;
if (args.hasFlag('t')) { if (useLineOfSight) {
Location blockPosition = player.getBlockTrace(300); Location blockPosition = player.getBlockTrace(300);
if (blockPosition == null) { if (blockPosition == null) {
player.printError("No block in sight!"); player.printError("No block in sight!");
@ -143,7 +117,7 @@ public class BiomeCommands {
biomes.add(biome); biomes.add(biome);
qualifier = "at line of sight point"; qualifier = "at line of sight point";
} else if (args.hasFlag('p')) { } else if (usePosition) {
BiomeType biome = player.getWorld().getBiome(player.getLocation().toVector().toBlockPoint().toBlockVector2()); BiomeType biome = player.getWorld().getBiome(player.getLocation().toVector().toBlockPoint().toBlockVector2());
biomes.add(biome); biomes.add(biome);
@ -177,18 +151,16 @@ public class BiomeCommands {
} }
@Command( @Command(
aliases = { "/setbiome" }, name = "/setbiome",
usage = "<biome>", desc = "Sets the biome of your current block or region.",
flags = "p", descFooter = "By default, uses all the blocks in your selection"
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"
) )
@Logging(REGION) @Logging(REGION)
@CommandPermissions("worldedit.biome.set") @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(); World world = player.getWorld();
Region region; Region region;
Mask mask = editSession.getMask(); Mask mask = editSession.getMask();

View File

@ -19,15 +19,12 @@
package com.sk89q.worldedit.command; 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.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; 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.BrushTool;
import com.sk89q.worldedit.command.tool.brush.ButcherBrush; import com.sk89q.worldedit.command.tool.brush.ButcherBrush;
import com.sk89q.worldedit.command.tool.brush.ClipboardBrush; 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.GravityBrush;
import com.sk89q.worldedit.command.tool.brush.HollowCylinderBrush; import com.sk89q.worldedit.command.tool.brush.HollowCylinderBrush;
import com.sk89q.worldedit.command.tool.brush.HollowSphereBrush; 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.SmoothBrush;
import com.sk89q.worldedit.command.tool.brush.SphereBrush; 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.command.util.CreatureButcher;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.clipboard.Clipboard; 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.BlockTypeMask;
import com.sk89q.worldedit.function.mask.Mask; 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.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.factory.RegionFactory;
import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.session.request.RequestExtent; import com.sk89q.worldedit.session.request.RequestExtent;
import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.world.block.BlockTypes; 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. * Commands to set brush shape.
*/ */
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class BrushCommands { public class BrushCommands {
private final WorldEdit worldEdit; private final WorldEdit worldEdit;
@ -70,19 +83,18 @@ public class BrushCommands {
} }
@Command( @Command(
aliases = { "sphere", "s" }, name = "sphere",
usage = "<pattern> [radius]", aliases = { "s" },
flags = "h", desc = "Choose the sphere brush"
desc = "Choose the sphere brush",
help =
"Chooses the sphere brush.\n" +
"The -h flag creates hollow spheres instead.",
min = 1,
max = 2
) )
@CommandPermissions("worldedit.brush.sphere") @CommandPermissions("worldedit.brush.sphere")
public void sphereBrush(Player player, LocalSession session, Pattern fill, public void sphereBrush(Player player, LocalSession session,
@Optional("2") double radius, @Switch('h') boolean hollow) throws WorldEditException { @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); worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType());
@ -99,19 +111,20 @@ public class BrushCommands {
} }
@Command( @Command(
aliases = { "cylinder", "cyl", "c" }, name = "cylinder",
usage = "<block> [radius] [height]", aliases = { "cyl", "c" },
flags = "h", desc = "Choose the cylinder brush"
desc = "Choose the cylinder brush",
help =
"Chooses the cylinder brush.\n" +
"The -h flag creates hollow cylinders instead.",
min = 1,
max = 3
) )
@CommandPermissions("worldedit.brush.cylinder") @CommandPermissions("worldedit.brush.cylinder")
public void cylinderBrush(Player player, LocalSession session, Pattern fill, public void cylinderBrush(Player player, LocalSession session,
@Optional("2") double radius, @Optional("1") int height, @Switch('h') boolean hollow) throws WorldEditException { @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(radius);
worldEdit.checkMaxBrushRadius(height); worldEdit.checkMaxBrushRadius(height);
@ -129,20 +142,22 @@ public class BrushCommands {
} }
@Command( @Command(
aliases = { "clipboard", "copy" }, name = "clipboard",
usage = "", aliases = { "copy" },
flags = "aoebm", desc = "Choose the clipboard brush"
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."
) )
@CommandPermissions("worldedit.brush.clipboard") @CommandPermissions("worldedit.brush.clipboard")
public void clipboardBrush(Player player, LocalSession session, @Switch('a') boolean ignoreAir, @Switch('o') boolean usingOrigin, public void clipboardBrush(Player player, LocalSession session,
@Switch('e') boolean pasteEntities, @Switch('b') boolean pasteBiomes, @Switch('m') Mask sourceMask) throws WorldEditException { @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(); ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard(); Clipboard clipboard = holder.getClipboard();
@ -159,18 +174,18 @@ public class BrushCommands {
} }
@Command( @Command(
aliases = { "smooth" }, name = "smooth",
usage = "[size] [iterations] [filter]",
desc = "Choose the terrain softener brush", desc = "Choose the terrain softener brush",
help = descFooter = "Example: '/brush smooth 2 4 grass_block,dirt,stone'"
"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
) )
@CommandPermissions("worldedit.brush.smooth") @CommandPermissions("worldedit.brush.smooth")
public void smoothBrush(Player player, LocalSession session, 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); worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType());
@ -181,14 +196,14 @@ public class BrushCommands {
} }
@Command( @Command(
aliases = { "ex", "extinguish" }, name = "extinguish",
usage = "[radius]", aliases = { "ex" },
desc = "Shortcut fire extinguisher brush", desc = "Shortcut fire extinguisher brush"
min = 0,
max = 1
) )
@CommandPermissions("worldedit.brush.ex") @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); worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType());
@ -202,19 +217,16 @@ public class BrushCommands {
} }
@Command( @Command(
aliases = { "gravity", "grav" }, name = "gravity",
usage = "[radius]", aliases = { "grav" },
flags = "h", desc = "Gravity brush, simulates the effect of gravity"
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
) )
@CommandPermissions("worldedit.brush.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); worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); 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).", player.print(String.format("Gravity brush equipped (%.0f).",
radius)); radius));
} }
@Command( @Command(
aliases = { "butcher", "kill" }, name = "butcher",
usage = "[radius]", aliases = { "kill" },
flags = "plangbtfr", desc = "Butcher brush, kills mobs within a radius"
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
) )
@CommandPermissions("worldedit.brush.butcher") @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(); LocalConfiguration config = worldEdit.getConfiguration();
double radius = args.argsLength() > 0 ? args.getDouble(0) : 5;
double maxRadius = config.maxBrushRadius; double maxRadius = config.maxBrushRadius;
// hmmmm not horribly worried about this because -1 is still rather efficient, // 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 // 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); 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()); BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType());
tool.setSize(radius); tool.setSize(radius);
@ -270,4 +292,106 @@ public class BrushCommands {
player.print(String.format("Butcher brush equipped (%.0f).", radius)); 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);
}
} }

View File

@ -20,49 +20,51 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import static com.google.common.base.Preconditions.checkNotNull; 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.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; 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.entity.Player;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.MathUtils; import com.sk89q.worldedit.math.MathUtils;
import com.sk89q.worldedit.util.Location; 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.LegacyChunkStore;
import com.sk89q.worldedit.world.storage.McRegionChunkStore; 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.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
/** /**
* Commands for working with chunks. * Commands for working with chunks.
*/ */
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ChunkCommands { public class ChunkCommands {
private final WorldEdit worldEdit; private final WorldEdit worldEdit;
public ChunkCommands(WorldEdit worldEdit) { public ChunkCommands(WorldEdit worldEdit) {
checkNotNull(worldEdit); checkNotNull(worldEdit);
this.worldEdit = worldEdit; this.worldEdit = worldEdit;
} }
@Command( @Command(
aliases = { "chunkinfo" }, name = "chunkinfo",
usage = "", desc = "Get information about the chunk you're inside"
desc = "Get information about the chunk that you are inside",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.chunkinfo") @CommandPermissions("worldedit.chunkinfo")
public void chunkInfo(Player player) throws WorldEditException { public void chunkInfo(Player player) {
Location pos = player.getBlockIn(); Location pos = player.getBlockIn();
int chunkX = (int) Math.floor(pos.getBlockX() / 16.0); int chunkX = (int) Math.floor(pos.getBlockX() / 16.0);
int chunkZ = (int) Math.floor(pos.getBlockZ() / 16.0); int chunkZ = (int) Math.floor(pos.getBlockZ() / 16.0);
@ -79,27 +81,22 @@ public class ChunkCommands {
} }
@Command( @Command(
aliases = { "listchunks" }, name = "listchunks",
usage = "", desc = "List chunks that your selection includes"
desc = "List chunks that your selection includes",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.listchunks") @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<BlockVector2> chunks = session.getSelection(player.getWorld()).getChunks(); Set<BlockVector2> chunks = session.getSelection(player.getWorld()).getChunks();
for (BlockVector2 chunk : chunks) { PaginationBox paginationBox = PaginationBox.fromStrings("Selected Chunks", "/listchunks %page%",
player.print(LegacyChunkStore.getFilename(chunk)); chunks.stream().map(BlockVector2::toString).collect(Collectors.toList()));
} player.print(paginationBox.create(page));
} }
@Command( @Command(
aliases = { "delchunks" }, name = "delchunks",
usage = "", desc = "Delete chunks that your selection includes"
desc = "Delete chunks that your selection includes",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.delchunks") @CommandPermissions("worldedit.delchunks")
@Logging(REGION) @Logging(REGION)

View File

@ -19,18 +19,13 @@
package com.sk89q.worldedit.command; 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.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.EditSession;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; 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.entity.Player;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard; 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.RegionSelector;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.session.PasteBuilder; import org.enginehub.piston.annotation.Command;
import com.sk89q.worldedit.util.command.binding.Switch; import org.enginehub.piston.annotation.CommandContainer;
import com.sk89q.worldedit.util.command.parametric.Optional; 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 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. * Clipboard commands.
*/ */
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ClipboardCommands { public class ClipboardCommands {
private final WorldEdit worldEdit;
/** /**
* Create a new instance. * Create a new instance.
*
* @param worldEdit reference to WorldEdit
*/ */
public ClipboardCommands(WorldEdit worldEdit) { public ClipboardCommands() {
checkNotNull(worldEdit);
this.worldEdit = worldEdit;
} }
@Command( @Command(
aliases = { "/copy" }, name = "/copy",
flags = "em", desc = "Copy the selection to the clipboard"
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
) )
@CommandPermissions("worldedit.clipboard.copy") @CommandPermissions("worldedit.clipboard.copy")
public void copy(Player player, LocalSession session, EditSession editSession, public void copy(Player player, LocalSession session, EditSession editSession,
@Selection Region region, @Switch('e') boolean copyEntities, @Selection Region region,
@Switch('m') Mask mask, @Switch('b') boolean copyBiomes) throws WorldEditException { @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); BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
clipboard.setOrigin(session.getPlacementPosition(player)); clipboard.setOrigin(session.getPlacementPosition(player));
ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint());
@ -106,24 +97,22 @@ public class ClipboardCommands {
} }
@Command( @Command(
aliases = { "/cut" }, name = "/cut",
flags = "em",
usage = "[leave-pattern]",
desc = "Cut the selection to the clipboard", desc = "Cut the selection to the clipboard",
help = "Copy the selection to the clipboard\n" + descFooter = "WARNING: Cutting and pasting entities cannot be undone!"
"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
) )
@CommandPermissions("worldedit.clipboard.cut") @CommandPermissions("worldedit.clipboard.cut")
@Logging(REGION) @Logging(REGION)
public void cut(Player player, LocalSession session, EditSession editSession, public void cut(Player player, LocalSession session, EditSession editSession,
@Selection Region region, @Optional("air") Pattern leavePattern, @Switch('e') boolean copyEntities, @Selection Region region,
@Switch('m') Mask mask, @Switch('b') boolean copyBiomes) throws WorldEditException { @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); BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
clipboard.setOrigin(session.getPlacementPosition(player)); clipboard.setOrigin(session.getPlacementPosition(player));
@ -144,26 +133,24 @@ public class ClipboardCommands {
} }
@Command( @Command(
aliases = { "/paste" }, name = "/paste",
flags = "saobem:", desc = "Paste the clipboard's contents"
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 [<mask>] skips matching blocks in the clipboard\n" +
" -o pastes at the original position\n" +
" -s selects the region after pasting\n",
max = 0
) )
@CommandPermissions("worldedit.clipboard.paste") @CommandPermissions("worldedit.clipboard.paste")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void paste(Player player, LocalSession session, EditSession editSession, public void paste(Player player, LocalSession session, EditSession editSession,
@Switch('a') boolean ignoreAirBlocks, @Switch('o') boolean atOrigin, @Switch(name = 'a', desc = "Skip air blocks")
@Switch('s') boolean selectPasted, @Switch('e') boolean pasteEntities, boolean ignoreAirBlocks,
@Switch('b') boolean pasteBiomes, @Switch('m') Mask sourceMask) throws WorldEditException { @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(); ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard(); Clipboard clipboard = holder.getClipboard();
@ -197,42 +184,43 @@ public class ClipboardCommands {
} }
@Command( @Command(
aliases = { "/rotate" }, name = "/rotate",
usage = "<y-axis> [<x-axis>] [<z-axis>]",
desc = "Rotate the contents of the clipboard", desc = "Rotate the contents of the clipboard",
help = "Non-destructively rotate the contents of the clipboard.\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. " + "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" "Multiple rotations can be stacked. Interpolation is not performed so angles should be a multiple of 90 degrees.\n"
) )
@CommandPermissions("worldedit.clipboard.rotate") @CommandPermissions("worldedit.clipboard.rotate")
public void rotate(Player player, LocalSession session, Double yRotate, @Optional Double xRotate, @Optional Double zRotate) throws WorldEditException { public void rotate(Player player, LocalSession session,
if ((yRotate != null && Math.abs(yRotate % 90) > 0.001) || @Arg(desc = "Amount to rotate on the y-axis")
xRotate != null && Math.abs(xRotate % 90) > 0.001 || double yRotate,
zRotate != null && Math.abs(zRotate % 90) > 0.001) { @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."); player.printDebug("Note: Interpolation is not yet supported, so angles that are multiples of 90 is recommended.");
} }
ClipboardHolder holder = session.getClipboard(); ClipboardHolder holder = session.getClipboard();
AffineTransform transform = new AffineTransform(); AffineTransform transform = new AffineTransform();
transform = transform.rotateY(-(yRotate != null ? yRotate : 0)); transform = transform.rotateY(-yRotate);
transform = transform.rotateX(-(xRotate != null ? xRotate : 0)); transform = transform.rotateX(-xRotate);
transform = transform.rotateZ(-(zRotate != null ? zRotate : 0)); transform = transform.rotateZ(-zRotate);
holder.setTransform(holder.getTransform().combine(transform)); holder.setTransform(holder.getTransform().combine(transform));
player.print("The clipboard copy has been rotated."); player.print("The clipboard copy has been rotated.");
} }
@Command( @Command(
aliases = { "/flip" }, name = "/flip",
usage = "[<direction>]", desc = "Flip the contents of the clipboard across the origin"
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
) )
@CommandPermissions("worldedit.clipboard.flip") @CommandPermissions("worldedit.clipboard.flip")
public void flip(Player player, LocalSession session, 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(); ClipboardHolder holder = session.getClipboard();
AffineTransform transform = new AffineTransform(); AffineTransform transform = new AffineTransform();
transform = transform.scale(direction.abs().multiply(-2).add(1, 1, 1).toVector3()); transform = transform.scale(direction.abs().multiply(-2).add(1, 1, 1).toVector3());
@ -241,11 +229,8 @@ public class ClipboardCommands {
} }
@Command( @Command(
aliases = { "clearclipboard" }, name = "clearclipboard",
usage = "", desc = "Clear your clipboard"
desc = "Clear your clipboard",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.clipboard.clear") @CommandPermissions("worldedit.clipboard.clear")
public void clearClipboard(Player player, LocalSession session) throws WorldEditException { public void clearClipboard(Player player, LocalSession session) throws WorldEditException {

View File

@ -19,28 +19,31 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.Sets; 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.EditSession;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; 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.entity.Player;
import com.sk89q.worldedit.extension.input.DisallowedUsageException; import com.sk89q.worldedit.extension.input.DisallowedUsageException;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.function.mask.Mask; 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.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes; 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. * General WorldEdit commands.
*/ */
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class GeneralCommands { public class GeneralCommands {
private final WorldEdit worldEdit; private final WorldEdit worldEdit;
@ -56,19 +59,18 @@ public class GeneralCommands {
} }
@Command( @Command(
aliases = { "/limit" }, name = "/limit",
usage = "[limit]", desc = "Modify block change limit"
desc = "Modify block change limit",
min = 0,
max = 1
) )
@CommandPermissions("worldedit.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(); LocalConfiguration config = worldEdit.getConfiguration();
boolean mayDisable = player.hasPermission("worldedit.limit.unrestricted"); 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 (!mayDisable && config.maxChangeLimit > -1) {
if (limit > config.maxChangeLimit) { if (limit > config.maxChangeLimit) {
player.printError("Your maximum allowable limit is " + config.maxChangeLimit + "."); player.printError("Your maximum allowable limit is " + config.maxChangeLimit + ".");
@ -86,19 +88,18 @@ public class GeneralCommands {
} }
@Command( @Command(
aliases = { "/timeout" }, name = "/timeout",
usage = "[time]", desc = "Modify evaluation timeout time."
desc = "Modify evaluation timeout time.",
min = 0,
max = 1
) )
@CommandPermissions("worldedit.timeout") @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(); LocalConfiguration config = worldEdit.getConfiguration();
boolean mayDisable = player.hasPermission("worldedit.timeout.unrestricted"); 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 (!mayDisable && config.maxCalculationTimeout > -1) {
if (limit > config.maxCalculationTimeout) { if (limit > config.maxCalculationTimeout) {
player.printError("Your maximum allowable timeout is " + config.maxCalculationTimeout + " ms."); player.printError("Your maximum allowable timeout is " + config.maxCalculationTimeout + " ms.");
@ -116,89 +117,65 @@ public class GeneralCommands {
} }
@Command( @Command(
aliases = { "/fast" }, name = "/fast",
usage = "[on|off]", desc = "Toggle fast mode"
desc = "Toggle fast mode",
min = 0,
max = 1
) )
@CommandPermissions("worldedit.fast") @CommandPermissions("worldedit.fast")
public void fast(Player player, LocalSession session, CommandContext args) throws WorldEditException { public void fast(Player player, LocalSession session,
@Arg(desc = "The new fast mode state", def = "")
String newState = args.getString(0, null); Boolean fastMode) throws WorldEditException {
if (session.hasFastMode()) { boolean hasFastMode = session.hasFastMode();
if ("on".equals(newState)) { if (fastMode != null && fastMode == hasFastMode) {
player.printError("Fast mode already enabled."); player.printError("Fast mode already " + (fastMode ? "enabled" : "disabled") + ".");
return; return;
} }
if (hasFastMode) {
session.setFastMode(false); session.setFastMode(false);
player.print("Fast mode disabled."); player.print("Fast mode disabled.");
} else { } else {
if ("off".equals(newState)) {
player.printError("Fast mode already disabled.");
return;
}
session.setFastMode(true); 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."); player.print("Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes.");
} }
} }
@Command( @Command(
aliases = { "/reorder" }, name = "/reorder",
usage = "[multi|fast|none]", desc = "Sets the reorder mode of WorldEdit"
desc = "Sets the reorder mode of WorldEdit",
min = 0,
max = 1
) )
@CommandPermissions("worldedit.reorder") @CommandPermissions("worldedit.reorder")
public void reorderMode(Player player, LocalSession session, CommandContext args) throws WorldEditException { public void reorderMode(Player player, LocalSession session,
String newState = args.getString(0, null); @Arg(desc = "The reorder mode", def = "")
if (newState == null) { EditSession.ReorderMode reorderMode) throws WorldEditException {
if (reorderMode == null) {
player.print("The reorder mode is " + session.getReorderMode().getDisplayName()); player.print("The reorder mode is " + session.getReorderMode().getDisplayName());
} else { } else {
java.util.Optional<EditSession.ReorderMode> reorderModeOptional = EditSession.ReorderMode.getFromDisplayName(newState);
if (!reorderModeOptional.isPresent()) {
player.printError("Unknown reorder mode!");
return;
}
EditSession.ReorderMode reorderMode = reorderModeOptional.get();
session.setReorderMode(reorderMode); session.setReorderMode(reorderMode);
player.print("The reorder mode is now " + session.getReorderMode().getDisplayName()); player.print("The reorder mode is now " + session.getReorderMode().getDisplayName());
} }
} }
@Command( @Command(
aliases = { "/drawsel" }, name = "/drawsel",
usage = "[on|off]", desc = "Toggle drawing the current selection"
desc = "Toggle drawing the current selection",
min = 0,
max = 1
) )
@CommandPermissions("worldedit.drawsel") @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) { if (!WorldEdit.getInstance().getConfiguration().serverSideCUI) {
throw new DisallowedUsageException("This functionality is disabled in the configuration!"); throw new DisallowedUsageException("This functionality is disabled in the configuration!");
} }
String newState = args.getString(0, null); boolean useServerCui = session.shouldUseServerCUI();
if (session.shouldUseServerCUI()) { if (drawSelection != null && drawSelection == useServerCui) {
if ("on".equals(newState)) { player.printError("Server CUI already " + (useServerCui ? "enabled" : "disabled") + ".");
player.printError("Server CUI already enabled."); return;
return; }
} if (useServerCui) {
session.setUseServerCUI(false); session.setUseServerCUI(false);
session.updateServerCUI(player); session.updateServerCUI(player);
player.print("Server CUI disabled."); player.print("Server CUI disabled.");
} else { } else {
if ("off".equals(newState)) {
player.printError("Server CUI already disabled.");
return;
}
session.setUseServerCUI(true); session.setUseServerCUI(true);
session.updateServerCUI(player); session.updateServerCUI(player);
player.print("Server CUI enabled. This only supports cuboid regions, with a maximum size of 32x32x32."); player.print("Server CUI enabled. This only supports cuboid regions, with a maximum size of 32x32x32.");
@ -206,14 +183,14 @@ public class GeneralCommands {
} }
@Command( @Command(
aliases = { "/gmask", "gmask" }, name = "gmask",
usage = "[mask]", aliases = {"/gmask"},
desc = "Set the global mask", desc = "Set the global mask"
min = 0,
max = -1
) )
@CommandPermissions("worldedit.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) { if (mask == null) {
session.setMask((Mask) null); session.setMask((Mask) null);
player.print("Global mask disabled."); player.print("Global mask disabled.");
@ -224,11 +201,9 @@ public class GeneralCommands {
} }
@Command( @Command(
aliases = { "/toggleplace", "toggleplace" }, name = "toggleplace",
usage = "", aliases = {"/toggleplace"},
desc = "Switch between your position and pos1 for placement", desc = "Switch between your position and pos1 for placement"
min = 0,
max = 0
) )
public void togglePlace(Player player, LocalSession session) throws WorldEditException { public void togglePlace(Player player, LocalSession session) throws WorldEditException {
@ -240,24 +215,17 @@ public class GeneralCommands {
} }
@Command( @Command(
aliases = { "/searchitem", "/l", "/search", "searchitem" }, name = "searchitem",
usage = "<query>", aliases = {"/searchitem", "/l", "/search"},
flags = "bi", desc = "Search for an item"
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
) )
public void searchItem(Actor actor, CommandContext args) throws WorldEditException { public void searchItem(Actor actor,
@Arg(desc = "Item query")
String query = args.getString(0).trim().toLowerCase(); String query,
boolean blocksOnly = args.hasFlag('b'); @Switch(name = 'b', desc = "Only search for blocks")
boolean itemsOnly = args.hasFlag('i'); boolean blocksOnly,
@Switch(name = 'i', desc = "Only search for items")
boolean itemsOnly) throws WorldEditException {
ItemType type = ItemTypes.get(query); ItemType type = ItemTypes.get(query);
if (type != null) { if (type != null) {

View File

@ -19,35 +19,39 @@
package com.sk89q.worldedit.command; 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.EditSession;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; 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.entity.Player;
import com.sk89q.worldedit.function.pattern.Pattern; 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.annotation.Selection;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.TreeGenerator.TreeType; 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 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. * Commands for the generation of shapes and other objects.
*/ */
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class GenerationCommands { public class GenerationCommands {
private final WorldEdit worldEdit; private final WorldEdit worldEdit;
@ -63,54 +67,52 @@ public class GenerationCommands {
} }
@Command( @Command(
aliases = { "/hcyl" }, name = "/hcyl",
usage = "<pattern> <radius>[,<radius>] [height]", desc = "Generates a hollow cylinder."
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
) )
@CommandPermissions("worldedit.generation.cylinder") @CommandPermissions("worldedit.generation.cylinder")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void hcyl(Player player, LocalSession session, EditSession editSession, Pattern pattern, String radiusString, @Optional("1") int height) throws WorldEditException { public int hcyl(Player player, LocalSession session, EditSession editSession,
cyl(player, session, editSession, pattern, radiusString, height, true); @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<Double> radii,
@Arg(desc = "The height of the cylinder", def = "1")
int height) throws WorldEditException {
return cyl(player, session, editSession, pattern, radii, height, true);
} }
@Command( @Command(
aliases = { "/cyl" }, name = "/cyl",
usage = "<block> <radius>[,<radius>] [height]", desc = "Generates a cylinder."
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
) )
@CommandPermissions("worldedit.generation.cylinder") @CommandPermissions("worldedit.generation.cylinder")
@Logging(PLACEMENT) @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 { public int cyl(Player player, LocalSession session, EditSession editSession,
String[] radii = radiusString.split(","); @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<Double> 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; final double radiusX, radiusZ;
switch (radii.length) { switch (radii.size()) {
case 1: case 1:
radiusX = radiusZ = Math.max(1, Double.parseDouble(radii[0])); radiusX = radiusZ = Math.max(1, radii.get(0));
break; break;
case 2: case 2:
radiusX = Math.max(1, Double.parseDouble(radii[0])); radiusX = Math.max(1, radii.get(0));
radiusZ = Math.max(1, Double.parseDouble(radii[1])); radiusZ = Math.max(1, radii.get(1));
break; break;
default: default:
player.printError("You must either specify 1 or 2 radius values."); player.printError("You must either specify 1 or 2 radius values.");
return; return 0;
} }
worldEdit.checkMaxRadius(radiusX); worldEdit.checkMaxRadius(radiusX);
@ -120,58 +122,57 @@ public class GenerationCommands {
BlockVector3 pos = session.getPlacementPosition(player); BlockVector3 pos = session.getPlacementPosition(player);
int affected = editSession.makeCylinder(pos, pattern, radiusX, radiusZ, height, !hollow); int affected = editSession.makeCylinder(pos, pattern, radiusX, radiusZ, height, !hollow);
player.print(affected + " block(s) have been created."); player.print(affected + " block(s) have been created.");
return affected;
} }
@Command( @Command(
aliases = { "/hsphere" }, name = "/hsphere",
usage = "<block> <radius>[,<radius>,<radius>] [raised?]", desc = "Generates a hollow sphere."
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
) )
@CommandPermissions("worldedit.generation.sphere") @CommandPermissions("worldedit.generation.sphere")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void hsphere(Player player, LocalSession session, EditSession editSession, Pattern pattern, String radiusString, @Optional("false") boolean raised) throws WorldEditException { public int hsphere(Player player, LocalSession session, EditSession editSession,
sphere(player, session, editSession, pattern, radiusString, raised, true); @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<Double> 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( @Command(
aliases = { "/sphere" }, name = "/sphere",
usage = "<block> <radius>[,<radius>,<radius>] [raised?]", desc = "Generates a filled sphere."
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
) )
@CommandPermissions("worldedit.generation.sphere") @CommandPermissions("worldedit.generation.sphere")
@Logging(PLACEMENT) @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 { public int sphere(Player player, LocalSession session, EditSession editSession,
String[] radii = radiusString.split(","); @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<Double> 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; final double radiusX, radiusY, radiusZ;
switch (radii.length) { switch (radii.size()) {
case 1: case 1:
radiusX = radiusY = radiusZ = Math.max(1, Double.parseDouble(radii[0])); radiusX = radiusY = radiusZ = Math.max(1, radii.get(0));
break; break;
case 3: case 3:
radiusX = Math.max(1, Double.parseDouble(radii[0])); radiusX = Math.max(1, radii.get(0));
radiusY = Math.max(1, Double.parseDouble(radii[1])); radiusY = Math.max(1, radii.get(1));
radiusZ = Math.max(1, Double.parseDouble(radii[2])); radiusZ = Math.max(1, radii.get(2));
break; break;
default: default:
player.printError("You must either specify 1 or 3 radius values."); player.printError("You must either specify 1 or 3 radius values.");
return; return 0;
} }
worldEdit.checkMaxRadius(radiusX); worldEdit.checkMaxRadius(radiusX);
@ -186,98 +187,102 @@ public class GenerationCommands {
int affected = editSession.makeSphere(pos, pattern, radiusX, radiusY, radiusZ, !hollow); int affected = editSession.makeSphere(pos, pattern, radiusX, radiusY, radiusZ, !hollow);
player.findFreePosition(); player.findFreePosition();
player.print(affected + " block(s) have been created."); player.print(affected + " block(s) have been created.");
return affected;
} }
@Command( @Command(
aliases = { "forestgen" }, name = "forestgen",
usage = "[size] [type] [density]", desc = "Generate a forest"
desc = "Generate a forest",
min = 0,
max = 3
) )
@CommandPermissions("worldedit.generation.forest") @CommandPermissions("worldedit.generation.forest")
@Logging(POSITION) @Logging(POSITION)
public void forestGen(Player player, LocalSession session, EditSession editSession, @Optional("10") int size, public int forestGen(Player player, LocalSession session, EditSession editSession,
@Optional("tree") TreeType type, @Optional("5") @Range(min = 0, max = 100) double density) throws WorldEditException { @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; density = density / 100;
int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type); int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type);
player.print(affected + " trees created."); player.print(affected + " trees created.");
return affected;
} }
@Command( @Command(
aliases = { "pumpkins" }, name = "pumpkins",
usage = "[size]", desc = "Generate pumpkin patches"
desc = "Generate pumpkin patches",
min = 0,
max = 1
) )
@CommandPermissions("worldedit.generation.pumpkins") @CommandPermissions("worldedit.generation.pumpkins")
@Logging(POSITION) @Logging(POSITION)
public void pumpkins(Player player, LocalSession session, EditSession editSession, @Optional("10") int apothem) throws WorldEditException { public int pumpkins(Player player, LocalSession session, EditSession editSession,
int affected = editSession.makePumpkinPatches(session.getPlacementPosition(player), apothem); @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."); player.print(affected + " pumpkin patches created.");
return affected;
} }
@Command( @Command(
aliases = { "/hpyramid" }, name = "/hpyramid",
usage = "<block> <size>", desc = "Generate a hollow pyramid"
desc = "Generate a hollow pyramid",
min = 2,
max = 2
) )
@CommandPermissions("worldedit.generation.pyramid") @CommandPermissions("worldedit.generation.pyramid")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void hollowPyramid(Player player, LocalSession session, EditSession editSession, Pattern pattern, @Range(min = 1) int size) throws WorldEditException { public int hollowPyramid(Player player, LocalSession session, EditSession editSession,
pyramid(player, session, editSession, pattern, size, true); @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( @Command(
aliases = { "/pyramid" }, name = "/pyramid",
usage = "<block> <size>", desc = "Generate a filled pyramid"
flags = "h",
desc = "Generate a filled pyramid",
min = 2,
max = 2
) )
@CommandPermissions("worldedit.generation.pyramid") @CommandPermissions("worldedit.generation.pyramid")
@Logging(PLACEMENT) @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); BlockVector3 pos = session.getPlacementPosition(player);
worldEdit.checkMaxRadius(size); worldEdit.checkMaxRadius(size);
int affected = editSession.makePyramid(pos, pattern, size, !hollow); int affected = editSession.makePyramid(pos, pattern, size, !hollow);
player.findFreePosition(); player.findFreePosition();
player.print(affected + " block(s) have been created."); player.print(affected + " block(s) have been created.");
return affected;
} }
@Command( @Command(
aliases = { "/generate", "/gen", "/g" }, name = "/generate",
usage = "<block> <expression>", aliases = { "/gen", "/g" },
desc = "Generates a shape according to a formula.", desc = "Generates a shape according to a formula.",
help = descFooter = "See also https://tinyurl.com/wesyntax."
"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
) )
@CommandPermissions("worldedit.generation.shape") @CommandPermissions("worldedit.generation.shape")
@Logging(ALL) @Logging(ALL)
public void generate(Player player, LocalSession session, EditSession editSession, public int generate(Player player, LocalSession session, EditSession editSession,
@Selection Region region, @Selection Region region,
Pattern pattern, @Arg(desc = "The pattern of blocks to set")
@Text String expression, Pattern pattern,
@Switch('h') boolean hollow, @Arg(desc = "Expression to test block placement locations and set block type", variable = true)
@Switch('r') boolean useRawCoords, List<String> expression,
@Switch('o') boolean offset, @Switch(name = 'h', desc = "Generate a hollow shape")
@Switch('c') boolean offsetCenter) throws WorldEditException { 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; final Vector3 zero;
Vector3 unit; Vector3 unit;
@ -307,43 +312,38 @@ public class GenerationCommands {
} }
try { 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.findFreePosition();
player.print(affected + " block(s) have been created."); player.print(affected + " block(s) have been created.");
return affected;
} catch (ExpressionException e) { } catch (ExpressionException e) {
player.printError(e.getMessage()); player.printError(e.getMessage());
return 0;
} }
} }
@Command( @Command(
aliases = { "/generatebiome", "/genbiome", "/gb" }, name = "/generatebiome",
usage = "<biome> <expression>", aliases = { "/genbiome", "/gb" },
desc = "Sets biome according to a formula.", desc = "Sets biome according to a formula.",
help = descFooter = "See also https://tinyurl.com/wesyntax."
"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
) )
@CommandPermissions("worldedit.generation.shape.biome") @CommandPermissions("worldedit.generation.shape.biome")
@Logging(ALL) @Logging(ALL)
public void generateBiome(Player player, LocalSession session, EditSession editSession, public int generateBiome(Player player, LocalSession session, EditSession editSession,
@Selection Region region, @Selection Region region,
BiomeType target, @Arg(desc = "The biome type to set")
@Text String expression, BiomeType target,
@Switch('h') boolean hollow, @Arg(desc = "Expression to test block placement locations and set biome type", variable = true)
@Switch('r') boolean useRawCoords, List<String> expression,
@Switch('o') boolean offset, @Switch(name = 'h', desc = "Generate a hollow shape")
@Switch('c') boolean offsetCenter) throws WorldEditException { 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; final Vector3 zero;
Vector3 unit; Vector3 unit;
@ -372,11 +372,13 @@ public class GenerationCommands {
} }
try { 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.findFreePosition();
player.print("" + affected + " columns affected."); player.print("" + affected + " columns affected.");
return affected;
} catch (ExpressionException e) { } catch (ExpressionException e) {
player.printError(e.getMessage()); player.printError(e.getMessage());
return 0;
} }
} }

View File

@ -19,20 +19,23 @@
package com.sk89q.worldedit.command; 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.EditSession;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; 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.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. * Commands to undo, redo, and clear history.
*/ */
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class HistoryCommands { public class HistoryCommands {
private final WorldEdit worldEdit; private final WorldEdit worldEdit;
@ -48,28 +51,29 @@ public class HistoryCommands {
} }
@Command( @Command(
aliases = { "/undo", "undo" }, name = "undo",
usage = "[times] [player]", aliases = { "/undo" },
desc = "Undoes the last action", desc = "Undoes the last action (from history)"
min = 0,
max = 2
) )
@CommandPermissions("worldedit.history.undo") @CommandPermissions("worldedit.history.undo")
public void undo(Player player, LocalSession session, CommandContext args) throws WorldEditException { public void undo(Player player, LocalSession session,
int times = Math.max(1, args.getInteger(0, 1)); @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) { for (int i = 0; i < times; ++i) {
EditSession undone; LocalSession undoSession = session;
if (args.argsLength() < 2) { if (playerName != null) {
undone = session.undo(session.getBlockBag(player), player);
} else {
player.checkPermission("worldedit.history.undo.other"); player.checkPermission("worldedit.history.undo.other");
LocalSession sess = worldEdit.getSessionManager().findByName(args.getString(1)); LocalSession sess = worldEdit.getSessionManager().findByName(playerName);
if (sess == null) { if (sess == null) {
player.printError("Unable to find session for " + args.getString(1)); player.printError("Unable to find session for " + playerName);
break; break;
} }
undone = sess.undo(session.getBlockBag(player), player); undoSession = session;
} }
EditSession undone = undoSession.undo(undoSession.getBlockBag(player), player);
if (undone != null) { if (undone != null) {
player.print("Undo successful."); player.print("Undo successful.");
worldEdit.flushBlockBag(player, undone); worldEdit.flushBlockBag(player, undone);
@ -81,30 +85,29 @@ public class HistoryCommands {
} }
@Command( @Command(
aliases = { "/redo", "redo" }, name = "redo",
usage = "[times] [player]", aliases = { "/redo" },
desc = "Redoes the last action (from history)", desc = "Redoes the last action (from history)"
min = 0,
max = 2
) )
@CommandPermissions("worldedit.history.redo") @CommandPermissions("worldedit.history.redo")
public void redo(Player player, LocalSession session, CommandContext args) throws WorldEditException { public void redo(Player player, LocalSession session,
@Arg(desc = "Number of redoes to perform", def = "1")
int times = Math.max(1, args.getInteger(0, 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) { for (int i = 0; i < times; ++i) {
EditSession redone; LocalSession redoSession = session;
if (args.argsLength() < 2) { if (playerName != null) {
redone = session.redo(session.getBlockBag(player), player);
} else {
player.checkPermission("worldedit.history.redo.other"); player.checkPermission("worldedit.history.redo.other");
LocalSession sess = worldEdit.getSessionManager().findByName(args.getString(1)); LocalSession sess = worldEdit.getSessionManager().findByName(playerName);
if (sess == null) { if (sess == null) {
player.printError("Unable to find session for " + args.getString(1)); player.printError("Unable to find session for " + playerName);
break; break;
} }
redone = sess.redo(session.getBlockBag(player), player); redoSession = session;
} }
EditSession redone = redoSession.redo(redoSession.getBlockBag(player), player);
if (redone != null) { if (redone != null) {
player.print("Redo successful."); player.print("Redo successful.");
worldEdit.flushBlockBag(player, redone); worldEdit.flushBlockBag(player, redone);
@ -116,11 +119,9 @@ public class HistoryCommands {
} }
@Command( @Command(
aliases = { "/clearhistory", "clearhistory" }, name = "clearhistory",
usage = "", aliases = { "/clearhistory" },
desc = "Clear your history", desc = "Clear your history"
min = 0,
max = 0
) )
@CommandPermissions("worldedit.history.clear") @CommandPermissions("worldedit.history.clear")
public void clearHistory(Player player, LocalSession session) throws WorldEditException { public void clearHistory(Player player, LocalSession session) throws WorldEditException {

View File

@ -19,23 +19,26 @@
package com.sk89q.worldedit.command; 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.LocalConfiguration;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; 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.entity.Player;
import com.sk89q.worldedit.util.Location; 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. * Commands for moving the player around.
*/ */
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class NavigationCommands { public class NavigationCommands {
private final WorldEdit worldEdit; private final WorldEdit worldEdit;
@ -51,80 +54,78 @@ public class NavigationCommands {
} }
@Command( @Command(
aliases = { "unstuck", "!" }, name = "unstuck",
usage = "", aliases = { "!" },
desc = "Escape from being stuck inside a block", desc = "Escape from being stuck inside a block"
min = 0,
max = 0
) )
@CommandPermissions("worldedit.navigation.unstuck") @CommandPermissions("worldedit.navigation.unstuck")
public void unstuck(Player player) throws WorldEditException { public void unstuck(Player player) throws WorldEditException {
player.print("There you go!");
player.findFreePosition(); player.findFreePosition();
player.print("There you go!");
} }
@Command( @Command(
aliases = { "ascend", "asc" }, name = "ascend",
usage = "[# of levels]", aliases = { "asc" },
desc = "Go up a floor", desc = "Go up a floor"
min = 0,
max = 1
) )
@CommandPermissions("worldedit.navigation.ascend") @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; int ascentLevels = 0;
while (player.ascendLevel()) { while (player.ascendLevel()) {
++ascentLevels; ++ascentLevels;
if (levelsToAscend == ascentLevels) { if (levels == ascentLevels) {
break; break;
} }
} }
if (ascentLevels == 0) { if (ascentLevels == 0) {
player.printError("No free spot above you found."); player.printError("No free spot above you found.");
} else { } else {
player.print((ascentLevels != 1) ? "Ascended " + Integer.toString(ascentLevels) + " levels." : "Ascended a level."); player.print((ascentLevels != 1) ? "Ascended " + ascentLevels + " levels." : "Ascended a level.");
} }
} }
@Command( @Command(
aliases = { "descend", "desc" }, name = "descend",
usage = "[# of floors]", aliases = { "desc" },
desc = "Go down a floor", desc = "Go down a floor"
min = 0,
max = 1
) )
@CommandPermissions("worldedit.navigation.descend") @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; int descentLevels = 0;
while (player.descendLevel()) { while (player.descendLevel()) {
++descentLevels; ++descentLevels;
if (levelsToDescend == descentLevels) { if (levels == descentLevels) {
break; break;
} }
} }
if (descentLevels == 0) { if (descentLevels == 0) {
player.printError("No free spot below you found."); player.printError("No free spot below you found.");
} else { } else {
player.print((descentLevels != 1) ? "Descended " + Integer.toString(descentLevels) + " levels." : "Descended a level."); player.print((descentLevels != 1) ? "Descended " + descentLevels + " levels." : "Descended a level.");
} }
} }
@Command( @Command(
aliases = { "ceil" }, name = "ceil",
usage = "[clearance]", desc = "Go to the ceiling"
desc = "Go to the celing",
flags = "fg",
min = 0,
max = 1
) )
@CommandPermissions("worldedit.navigation.ceiling") @CommandPermissions("worldedit.navigation.ceiling")
@Logging(POSITION) @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 ? boolean alwaysGlass = getAlwaysGlass(forceFlight, forceGlass);
Math.max(0, args.getInteger(0)) : 0;
final boolean alwaysGlass = getAlwaysGlass(args);
if (player.ascendToCeiling(clearance, alwaysGlass)) { if (player.ascendToCeiling(clearance, alwaysGlass)) {
player.print("Whoosh!"); player.print("Whoosh!");
} else { } else {
@ -133,11 +134,8 @@ public class NavigationCommands {
} }
@Command( @Command(
aliases = { "thru" }, name = "thru",
usage = "", desc = "Pass through walls"
desc = "Passthrough walls",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.navigation.thru.command") @CommandPermissions("worldedit.navigation.thru.command")
public void thru(Player player) throws WorldEditException { public void thru(Player player) throws WorldEditException {
@ -149,11 +147,9 @@ public class NavigationCommands {
} }
@Command( @Command(
aliases = { "jumpto", "j" }, name = "jumpto",
usage = "", aliases = { "j" },
desc = "Teleport to a location", desc = "Teleport to a location"
min = 0,
max = 0
) )
@CommandPermissions("worldedit.navigation.jumpto.command") @CommandPermissions("worldedit.navigation.jumpto.command")
public void jumpTo(Player player) throws WorldEditException { public void jumpTo(Player player) throws WorldEditException {
@ -168,19 +164,19 @@ public class NavigationCommands {
} }
@Command( @Command(
aliases = { "up" }, name = "up",
usage = "<block>", desc = "Go upwards some distance"
desc = "Go upwards some distance",
flags = "fg",
min = 1,
max = 1
) )
@CommandPermissions("worldedit.navigation.up") @CommandPermissions("worldedit.navigation.up")
@Logging(POSITION) @Logging(POSITION)
public void up(Player player, CommandContext args) throws WorldEditException { public void up(Player player,
final int distance = args.getInteger(0); @Arg(desc = "Distance to go upwards")
int distance,
final boolean alwaysGlass = getAlwaysGlass(args); @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)) { if (player.ascendUpwards(distance, alwaysGlass)) {
player.print("Whoosh!"); player.print("Whoosh!");
} else { } else {
@ -190,16 +186,14 @@ public class NavigationCommands {
/** /**
* Helper function for /up and /ceil. * 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 * @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 LocalConfiguration config = worldEdit.getConfiguration();
final boolean forceFlight = args.hasFlag('f');
final boolean forceGlass = args.hasFlag('g');
return forceGlass || (config.navigationUseGlass && !forceFlight); return forceGlass || (config.navigationUseGlass && !forceFlight);
} }
} }

View File

@ -0,0 +1,139 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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));
}
}

View File

@ -19,31 +19,26 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.base.Joiner;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.ALL; import com.google.common.collect.Lists;
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.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; 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.entity.Player;
import com.sk89q.worldedit.function.GroundFunction; 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.FloraGenerator;
import com.sk89q.worldedit.function.generator.ForestGenerator;
import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.NoiseFilter2D; import com.sk89q.worldedit.function.mask.NoiseFilter2D;
import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.LayerVisitor; 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.Direction;
import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.internal.annotation.Selection;
import com.sk89q.worldedit.internal.expression.ExpressionException; 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.Region;
import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.regions.RegionOperationException;
import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.util.command.binding.Range; import org.enginehub.piston.annotation.Command;
import com.sk89q.worldedit.util.command.binding.Switch; import org.enginehub.piston.annotation.CommandContainer;
import com.sk89q.worldedit.util.command.binding.Text; import org.enginehub.piston.annotation.param.Arg;
import com.sk89q.worldedit.util.command.parametric.Optional; import org.enginehub.piston.annotation.param.Switch;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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. * Commands that operate on regions.
*/ */
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class RegionCommands { public class RegionCommands {
private final WorldEdit worldEdit;
/** /**
* Create a new instance. * Create a new instance.
*
* @param worldEdit reference to WorldEdit
*/ */
public RegionCommands(WorldEdit worldEdit) { public RegionCommands() {
checkNotNull(worldEdit);
this.worldEdit = worldEdit;
} }
@Command( @Command(
aliases = { "/line" }, name = "/set",
usage = "<pattern> [thickness]", desc = "Sets all the blocks in the region"
desc = "Draws a line segment between cuboid selection corners", )
help = @CommandPermissions("worldedit.region.set")
"Draws a line segment between cuboid selection corners.\n" + @Logging(REGION)
"Can only be used with cuboid selections.\n" + public int set(Player player, EditSession editSession,
"Flags:\n" + @Selection Region region,
" -h generates only a shell", @Arg(desc = "The patter of blocks to set")
flags = "h", Pattern pattern) {
min = 1, RegionFunction set = new BlockReplace(editSession, pattern);
max = 2 RegionVisitor visitor = new RegionVisitor(region, set);
Operations.completeBlindly(visitor);
List<String> 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") @CommandPermissions("worldedit.region.line")
@Logging(REGION) @Logging(REGION)
public void line(Player player, EditSession editSession, public int line(Player player, EditSession editSession,
@Selection Region region, @Selection Region region,
Pattern pattern, @Arg(desc = "The pattern of blocks to place")
@Optional("0") @Range(min = 0) int thickness, Pattern pattern,
@Switch('h') boolean shell) throws WorldEditException { @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)) { if (!(region instanceof CuboidRegion)) {
player.printError("//line only works with cuboid selections"); player.printError("//line only works with cuboid selections");
return; return 0;
} }
checkArgument(thickness >= 0, "Thickness must be >= 0");
CuboidRegion cuboidregion = (CuboidRegion) region; CuboidRegion cuboidregion = (CuboidRegion) region;
BlockVector3 pos1 = cuboidregion.getPos1(); BlockVector3 pos1 = cuboidregion.getPos1();
@ -115,32 +133,29 @@ public class RegionCommands {
int blocksChanged = editSession.drawLine(pattern, pos1, pos2, thickness, !shell); int blocksChanged = editSession.drawLine(pattern, pos1, pos2, thickness, !shell);
player.print(blocksChanged + " block(s) have been changed."); player.print(blocksChanged + " block(s) have been changed.");
return blocksChanged;
} }
@Command( @Command(
aliases = { "/curve" }, name = "/curve",
usage = "<pattern> [thickness]", desc = "Draws a spline through selected points",
desc = "Draws a spline through selected points", descFooter = "Can only be used with a convex polyhedral selection"
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
) )
@CommandPermissions("worldedit.region.curve") @CommandPermissions("worldedit.region.curve")
@Logging(REGION) @Logging(REGION)
public void curve(Player player, EditSession editSession, public int curve(Player player, EditSession editSession,
@Selection Region region, @Selection Region region,
Pattern pattern, @Arg(desc = "The pattern of blocks to place")
@Optional("0") @Range(min = 0) int thickness, Pattern pattern,
@Switch('h') boolean shell) throws WorldEditException { @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)) { if (!(region instanceof ConvexPolyhedralRegion)) {
player.printError("//curve only works with convex polyhedral selections"); player.printError("//curve only works with convex polyhedral selections");
return; return 0;
} }
checkArgument(thickness >= 0, "Thickness must be >= 0");
ConvexPolyhedralRegion cpregion = (ConvexPolyhedralRegion) region; ConvexPolyhedralRegion cpregion = (ConvexPolyhedralRegion) region;
List<BlockVector3> vectors = new ArrayList<>(cpregion.getVertices()); List<BlockVector3> vectors = new ArrayList<>(cpregion.getVertices());
@ -148,139 +163,140 @@ public class RegionCommands {
int blocksChanged = editSession.drawSpline(pattern, vectors, 0, 0, 0, 10, thickness, !shell); int blocksChanged = editSession.drawSpline(pattern, vectors, 0, 0, 0, 10, thickness, !shell);
player.print(blocksChanged + " block(s) have been changed."); player.print(blocksChanged + " block(s) have been changed.");
return blocksChanged;
} }
@Command( @Command(
aliases = { "/replace", "/re", "/rep" }, name = "/replace",
usage = "[from-block] <to-block>", aliases = { "/re", "/rep" },
desc = "Replace all blocks in the selection with another", desc = "Replace all blocks in the selection with another"
flags = "f",
min = 1,
max = 2
) )
@CommandPermissions("worldedit.region.replace") @CommandPermissions("worldedit.region.replace")
@Logging(REGION) @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) { if (from == null) {
from = new ExistingBlockMask(editSession); from = new ExistingBlockMask(editSession);
} }
int affected = editSession.replaceBlocks(region, from, to); int affected = editSession.replaceBlocks(region, from, to);
player.print(affected + " block(s) have been replaced."); player.print(affected + " block(s) have been replaced.");
return affected;
} }
@Command( @Command(
aliases = { "/overlay" }, name = "/overlay",
usage = "<pattern>", desc = "Set a block on top of blocks in the region"
desc = "Set a block on top of blocks in the region",
min = 1,
max = 1
) )
@CommandPermissions("worldedit.region.overlay") @CommandPermissions("worldedit.region.overlay")
@Logging(REGION) @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); int affected = editSession.overlayCuboidBlocks(region, pattern);
player.print(affected + " block(s) have been overlaid."); player.print(affected + " block(s) have been overlaid.");
return affected;
} }
@Command( @Command(
aliases = { "/center", "/middle" }, name = "/center",
usage = "<pattern>", aliases = { "/middle" },
desc = "Set the center block(s)", desc = "Set the center block(s)"
min = 1,
max = 1
) )
@Logging(REGION) @Logging(REGION)
@CommandPermissions("worldedit.region.center") @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); int affected = editSession.center(region, pattern);
player.print("Center set ("+ affected + " blocks changed)"); player.print("Center set (" + affected + " block(s) changed)");
return affected;
} }
@Command( @Command(
aliases = { "/naturalize" }, name = "/naturalize",
usage = "", desc = "3 layers of dirt on top then rock below"
desc = "3 layers of dirt on top then rock below",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.region.naturalize") @CommandPermissions("worldedit.region.naturalize")
@Logging(REGION) @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); int affected = editSession.naturalizeCuboidBlocks(region);
player.print(affected + " block(s) have been made to look more natural."); player.print(affected + " block(s) have been made to look more natural.");
return affected;
} }
@Command( @Command(
aliases = { "/walls" }, name = "/walls",
usage = "<pattern>", desc = "Build the four sides of the selection"
desc = "Build the four sides of the selection",
min = 1,
max = 1
) )
@CommandPermissions("worldedit.region.walls") @CommandPermissions("worldedit.region.walls")
@Logging(REGION) @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); int affected = editSession.makeWalls(region, pattern);
player.print(affected + " block(s) have been changed."); player.print(affected + " block(s) have been changed.");
return affected;
} }
@Command( @Command(
aliases = { "/faces", "/outline" }, name = "/faces",
usage = "<pattern>", aliases = { "/outline" },
desc = "Build the walls, ceiling, and floor of a selection", desc = "Build the walls, ceiling, and floor of a selection"
min = 1,
max = 1
) )
@CommandPermissions("worldedit.region.faces") @CommandPermissions("worldedit.region.faces")
@Logging(REGION) @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); int affected = editSession.makeCuboidFaces(region, pattern);
player.print(affected + " block(s) have been changed."); player.print(affected + " block(s) have been changed.");
return affected;
} }
@Command( @Command(
aliases = { "/smooth" }, name = "/smooth",
usage = "[iterations] [filter]",
desc = "Smooth the elevation in the selection", desc = "Smooth the elevation in the selection",
help = descFooter = "Example: '//smooth 1 grass_block,dirt,stone' would only smooth natural surface terrain."
"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
) )
@CommandPermissions("worldedit.region.smooth") @CommandPermissions("worldedit.region.smooth")
@Logging(REGION) @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); HeightMap heightMap = new HeightMap(editSession, region, mask);
HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0)); HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0));
int affected = heightMap.applyFilter(filter, iterations); int affected = heightMap.applyFilter(filter, iterations);
player.print("Terrain's height map smoothed. " + affected + " block(s) changed."); player.print("Terrain's height map smoothed. " + affected + " block(s) changed.");
return affected;
} }
@Command( @Command(
aliases = { "/move" }, name = "/move",
usage = "[count] [direction] [leave-id]", desc = "Move the contents of the selection"
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 <leave-id>.",
min = 0,
max = 3
) )
@CommandPermissions("worldedit.region.move") @CommandPermissions("worldedit.region.move")
@Logging(ORIENTATION_REGION) @Logging(ORIENTATION_REGION)
public void move(Player player, EditSession editSession, LocalSession session, public int move(Player player, EditSession editSession, LocalSession session,
@Selection Region region, @Selection Region region,
@Optional("1") @Range(min = 1) int count, @Arg(desc = "# of blocks to move", def = "1")
@Optional(Direction.AIM) @Direction(includeDiagonals = true) BlockVector3 direction, int count,
@Optional("air") Pattern replace, @Arg(desc = "The direction to move", def = Direction.AIM)
@Switch('s') boolean moveSelection, @Direction(includeDiagonals = true)
@Switch('a') boolean ignoreAirBlocks) throws WorldEditException { 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); 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( @Command(
aliases = { "/stack" }, name = "/stack",
usage = "[count] [direction]", desc = "Repeat the contents of the selection"
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
) )
@CommandPermissions("worldedit.region.stack") @CommandPermissions("worldedit.region.stack")
@Logging(ORIENTATION_REGION) @Logging(ORIENTATION_REGION)
public void stack(Player player, EditSession editSession, LocalSession session, public int stack(Player player, EditSession editSession, LocalSession session,
@Selection Region region, @Selection Region region,
@Optional("1") @Range(min = 1) int count, @Arg(desc = "# of copies to stack", def = "1")
@Optional(Direction.AIM) @Direction(includeDiagonals = true) BlockVector3 direction, int count,
@Switch('s') boolean moveSelection, @Arg(desc = "The direction to stack", def = Direction.AIM)
@Switch('a') boolean ignoreAirBlocks) throws WorldEditException { @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); int affected = editSession.stackCuboidRegion(region, direction, count, !ignoreAirBlocks);
if (moveSelection) { 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( @Command(
aliases = { "/regen" }, name = "/regen",
usage = "",
desc = "Regenerates the contents of the selection", desc = "Regenerates the contents of the selection",
help = descFooter = "This command might affect things outside the selection,\n" +
"Regenerates the contents of the current selection.\n" + "if they are within the same chunk."
"This command might affect things outside the selection,\n" +
"if they are within the same chunk.",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.regen") @CommandPermissions("worldedit.regen")
@Logging(REGION) @Logging(REGION)
public void regenerateChunk(Player player, LocalSession session, EditSession editSession, @Selection Region region) throws WorldEditException { public void regenerateChunk(Player player, LocalSession session, EditSession editSession, @Selection Region region) throws WorldEditException {
Mask mask = session.getMask(); Mask mask = session.getMask();
try { try {
session.setMask((Mask) null); session.setMask(null);
player.getWorld().regenerate(region, editSession); player.getWorld().regenerate(region, editSession);
} finally { } finally {
session.setMask(mask); session.setMask(mask);
@ -363,25 +372,22 @@ public class RegionCommands {
} }
@Command( @Command(
aliases = { "/deform" }, name = "/deform",
usage = "<expression>", desc = "Deforms a selected region with an expression",
desc = "Deforms a selected region with an expression", descFooter = "The expression is executed for each block and is expected\n" +
help = "to modify the variables x, y and z to point to a new block\n" +
"Deforms a selected region with an expression\n" + "to fetch. See also tinyurl.com/wesyntax."
"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
) )
@CommandPermissions("worldedit.region.deform") @CommandPermissions("worldedit.region.deform")
@Logging(ALL) @Logging(ALL)
public void deform(Player player, LocalSession session, EditSession editSession, public int deform(Player player, LocalSession session, EditSession editSession,
@Selection Region region, @Selection Region region,
@Text String expression, @Arg(desc = "The expression to use", variable = true)
@Switch('r') boolean useRawCoords, List<String> expression,
@Switch('o') boolean offset) throws WorldEditException { @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; final Vector3 zero;
Vector3 unit; Vector3 unit;
@ -404,61 +410,63 @@ public class RegionCommands {
} }
try { 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.findFreePosition();
player.print(affected + " block(s) have been deformed."); player.print(affected + " block(s) have been deformed.");
return affected;
} catch (ExpressionException e) { } catch (ExpressionException e) {
player.printError(e.getMessage()); player.printError(e.getMessage());
return 0;
} }
} }
@Command( @Command(
aliases = { "/hollow" }, name = "/hollow",
usage = "[<thickness>[ <pattern>]]",
desc = "Hollows out the object contained in this selection", desc = "Hollows out the object contained in this selection",
help = descFooter = "Thickness is measured in manhattan distance."
"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
) )
@CommandPermissions("worldedit.region.hollow") @CommandPermissions("worldedit.region.hollow")
@Logging(REGION) @Logging(REGION)
public void hollow(Player player, EditSession editSession, public int hollow(Player player, EditSession editSession,
@Selection Region region, @Selection Region region,
@Optional("0") @Range(min = 0) int thickness, @Arg(desc = "Thickness of the shell to leave", def = "0")
@Optional("air") Pattern pattern) throws WorldEditException { 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); int affected = editSession.hollowOutRegion(region, thickness, pattern);
player.print(affected + " block(s) have been changed."); player.print(affected + " block(s) have been changed.");
return affected;
} }
@Command( @Command(
aliases = { "/forest" }, name = "/forest",
usage = "[type] [density]", desc = "Make a forest within the region"
desc = "Make a forest within the region",
min = 0,
max = 2
) )
@CommandPermissions("worldedit.region.forest") @CommandPermissions("worldedit.region.forest")
@Logging(REGION) @Logging(REGION)
public void forest(Player player, EditSession editSession, @Selection Region region, @Optional("tree") TreeType type, public int forest(Player player, EditSession editSession, @Selection Region region,
@Optional("5") @Range(min = 0, max = 100) double density) throws WorldEditException { @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); int affected = editSession.makeForest(region, density / 100, type);
player.print(affected + " trees created."); player.print(affected + " trees created.");
return affected;
} }
@Command( @Command(
aliases = { "/flora" }, name = "/flora",
usage = "[density]", desc = "Make flora within the region"
desc = "Make flora within the region",
min = 0,
max = 1
) )
@CommandPermissions("worldedit.region.flora") @CommandPermissions("worldedit.region.flora")
@Logging(REGION) @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; density = density / 100;
FloraGenerator generator = new FloraGenerator(editSession); FloraGenerator generator = new FloraGenerator(editSession);
GroundFunction ground = new GroundFunction(new ExistingBlockMask(editSession), generator); GroundFunction ground = new GroundFunction(new ExistingBlockMask(editSession), generator);
@ -466,7 +474,9 @@ public class RegionCommands {
visitor.setMask(new NoiseFilter2D(new RandomNoise(), density)); visitor.setMask(new NoiseFilter2D(new RandomNoise(), density));
Operations.completeLegacy(visitor); Operations.completeLegacy(visitor);
player.print(ground.getAffected() + " flora created."); int affected = ground.getAffected();
player.print(affected + " flora created.");
return affected;
} }
} }

View File

@ -19,16 +19,12 @@
package com.sk89q.worldedit.command; 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.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; 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.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; 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.function.operation.Operations;
import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.command.parametric.Optional; 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.Closer;
import com.sk89q.worldedit.util.io.file.FilenameException; 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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.enginehub.piston.exception.StopExecutionException;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
@ -57,19 +60,15 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* Commands that work with schematic files. * Commands that work with schematic files.
*/ */
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class SchematicCommands { 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 static final Logger log = LoggerFactory.getLogger(SchematicCommands.class);
private final WorldEdit worldEdit; private final WorldEdit worldEdit;
@ -84,17 +83,21 @@ public class SchematicCommands {
} }
@Command( @Command(
aliases = { "load" }, name = "load",
usage = "[<format>] <filename>", desc = "Load a schematic into your clipboard"
desc = "Load a schematic into your clipboard",
min = 1, max = 2
) )
@CommandPermissions({ "worldedit.clipboard.load", "worldedit.schematic.load" }) @CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load"})
public void load(Player player, LocalSession session, @Optional("sponge") String formatName, String filename) throws FilenameException { 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(); LocalConfiguration config = worldEdit.getConfiguration();
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); 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()) { if (!f.exists()) {
player.printError("Schematic " + filename + " does not exist!"); player.printError("Schematic " + filename + " does not exist!");
@ -122,21 +125,23 @@ public class SchematicCommands {
player.print(filename + " loaded. Paste it with //paste"); player.print(filename + " loaded. Paste it with //paste");
} catch (IOException e) { } catch (IOException e) {
player.printError("Schematic could not read or it does not exist: " + e.getMessage()); 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( @Command(
aliases = { "save" }, name = "save",
flags = "f", desc = "Save a schematic into your clipboard"
usage = "[<format>] <filename>",
desc = "Save a schematic into your clipboard",
help = "-f is required to overwrite an existing file",
min = 1, max = 2
) )
@CommandPermissions({ "worldedit.clipboard.save", "worldedit.schematic.save" }) @CommandPermissions({"worldedit.clipboard.save", "worldedit.schematic.save"})
public void save(Player player, LocalSession session, @Optional("sponge") String formatName, public void save(Player player, LocalSession session,
String filename, @Switch('f') boolean allowOverwrite) throws CommandException, WorldEditException { @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(); LocalConfiguration config = worldEdit.getConfiguration();
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
@ -152,7 +157,7 @@ public class SchematicCommands {
boolean overwrite = f.exists(); boolean overwrite = f.exists();
if (overwrite) { if (overwrite) {
if (!player.hasPermission("worldedit.schematic.delete")) { if (!player.hasPermission("worldedit.schematic.delete")) {
throw new CommandException("That schematic already exists!"); throw new StopExecutionException(TextComponent.of("That schematic already exists!"));
} }
if (!allowOverwrite) { if (!allowOverwrite) {
player.printError("That schematic already exists. Use the -f flag to overwrite it."); player.printError("That schematic already exists. Use the -f flag to overwrite it.");
@ -179,7 +184,8 @@ public class SchematicCommands {
File parent = f.getParentFile(); File parent = f.getParentFile();
if (parent != null && !parent.exists()) { if (parent != null && !parent.exists()) {
if (!parent.mkdirs()) { 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( @Command(
aliases = { "delete", "d" }, name = "delete",
usage = "<filename>", aliases = {"d"},
desc = "Delete a saved schematic", desc = "Delete a saved schematic"
help = "Delete a schematic from the schematic list",
min = 1,
max = 1
) )
@CommandPermissions("worldedit.schematic.delete") @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(); LocalConfiguration config = worldEdit.getConfiguration();
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
@ -232,12 +237,12 @@ public class SchematicCommands {
} }
@Command( @Command(
aliases = {"formats", "listformats", "f"}, name = "formats",
desc = "List available formats", aliases = {"listformats", "f"},
max = 0 desc = "List available formats"
) )
@CommandPermissions("worldedit.schematic.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)"); actor.print("Available clipboard formats (Name: Lookup names)");
StringBuilder builder; StringBuilder builder;
boolean first = true; boolean first = true;
@ -257,18 +262,22 @@ public class SchematicCommands {
} }
@Command( @Command(
aliases = {"list", "all", "ls"}, name = "list",
desc = "List saved schematics", aliases = {"all", "ls"},
max = 1, desc = "List saved schematics",
flags = "dnp", descFooter = "Note: Format is not fully verified until loading."
help = "List all schematics in the schematics directory\n" +
" -d sorts by date, oldest first\n" +
" -n sorts by date, newest first\n" +
" -p <page> prints the requested page\n" +
"Note: Format is not thoroughly verified until loading."
) )
@CommandPermissions("worldedit.schematic.list") @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); File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().saveDir);
List<File> fileList = allFiles(dir); List<File> fileList = allFiles(dir);
@ -280,17 +289,7 @@ public class SchematicCommands {
File[] files = new File[fileList.size()]; File[] files = new File[fileList.size()];
fileList.toArray(files); fileList.toArray(files);
int pageCount = files.length / SCHEMATICS_PER_PAGE + 1; final int sortType = oldFirst ? -1 : newFirst ? 1 : 0;
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;
// cleanup file list // cleanup file list
Arrays.sort(files, (f1, f2) -> { Arrays.sort(files, (f1, f2) -> {
// http://stackoverflow.com/questions/203030/best-way-to-list-files-in-java-sorted-by-date-modified // 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; return res;
}); });
List<String> schematics = listFiles(worldEdit.getConfiguration().saveDir, files); String pageCommand = actor.isPlayer() ? "//schem list -p %page%" + (oldFirst ? " -d" : newFirst ? " -n" : "") : null;
int offset = (page - 1) * SCHEMATICS_PER_PAGE; PaginationBox paginationBox = new SchematicPaginationBox(worldEdit.getConfiguration().saveDir, files, pageCommand);
actor.print(paginationBox.create(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());
} }
private List<File> allFiles(File root) { private List<File> allFiles(File root) {
@ -341,22 +329,4 @@ public class SchematicCommands {
return fileList; return fileList;
} }
private List<String> listFiles(String prefix, File[] files) {
if (prefix == null) prefix = "";
List<String> result = new ArrayList<>();
for (File file : files) {
StringBuilder build = new StringBuilder();
build.append("\u00a72");
//ClipboardFormat format = ClipboardFormats.findByFile(file);
Multimap<String, ClipboardFormat> 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;
}
} }

View File

@ -19,23 +19,28 @@
package com.sk89q.worldedit.command; 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.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; 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.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.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. * Commands related to scripting.
*/ */
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ScriptingCommands { public class ScriptingCommands {
private final WorldEdit worldEdit; private final WorldEdit worldEdit;
@ -51,43 +56,40 @@ public class ScriptingCommands {
} }
@Command( @Command(
aliases = { "cs" }, name = "cs",
usage = "<filename> [args...]", desc = "Execute a CraftScript"
desc = "Execute a CraftScript",
min = 1,
max = -1
) )
@CommandPermissions("worldedit.scripting.execute") @CommandPermissions("worldedit.scripting.execute")
@Logging(ALL) @Logging(ALL)
public void execute(Player player, LocalSession session, CommandContext args) throws WorldEditException { public void execute(Player player, LocalSession session,
@Arg(desc = "Filename of the CraftScript to load")
String[] scriptArgs = args.getSlice(1); String filename,
String name = args.getString(0); @Arg(desc = "Arguments to the CraftScript", def = "", variable = true)
List<String> args) throws WorldEditException {
if (!player.hasPermission("worldedit.scripting.execute." + name)) { if (!player.hasPermission("worldedit.scripting.execute." + filename)) {
player.printError("You don't have permission to use that script."); player.printError("You don't have permission to use that script.");
return; return;
} }
session.setLastScript(name); session.setLastScript(filename);
File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir); 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( @Command(
aliases = { ".s" }, name = ".s",
usage = "[args...]", desc = "Execute last CraftScript"
desc = "Execute last CraftScript",
min = 0,
max = -1
) )
@CommandPermissions("worldedit.scripting.execute") @CommandPermissions("worldedit.scripting.execute")
@Logging(ALL) @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<String> args) throws WorldEditException {
String lastScript = session.getLastScript(); String lastScript = session.getLastScript();
if (!player.hasPermission("worldedit.scripting.execute." + lastScript)) { if (!player.hasPermission("worldedit.scripting.execute." + lastScript)) {
@ -100,11 +102,10 @@ public class ScriptingCommands {
return; return;
} }
String[] scriptArgs = args.getSlice(0);
File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir); File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir);
File f = worldEdit.getSafeOpenFile(player, dir, lastScript, "js", "js"); 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));
} }
} }

View File

@ -19,19 +19,16 @@
package com.sk89q.worldedit.command; 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.EditSession;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItemStack; 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.entity.Player;
import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits; 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.block.BlockDistributionCounter;
import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.visitor.RegionVisitor; 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.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region; 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.block.BlockState;
import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.storage.ChunkStore; 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.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set; 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. * Selection commands.
*/ */
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class SelectionCommands { public class SelectionCommands {
private final WorldEdit we; private final WorldEdit we;
@ -82,26 +88,17 @@ public class SelectionCommands {
} }
@Command( @Command(
aliases = { "/pos1" }, name = "/pos1",
usage = "[coordinates]", desc = "Set position 1"
desc = "Set position 1",
min = 0,
max = 1
) )
@Logging(POSITION) @Logging(POSITION)
@CommandPermissions("worldedit.selection.pos") @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; Location pos;
if (coordinates != null) {
if (args.argsLength() == 1) { pos = new Location(player.getWorld(), coordinates.toVector3());
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;
}
} else { } else {
pos = player.getBlockIn(); pos = player.getBlockIn();
} }
@ -116,27 +113,17 @@ public class SelectionCommands {
} }
@Command( @Command(
aliases = { "/pos2" }, name = "/pos2",
usage = "[coordinates]", desc = "Set position 2"
desc = "Set position 2",
min = 0,
max = 1
) )
@Logging(POSITION) @Logging(POSITION)
@CommandPermissions("worldedit.selection.pos") @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; Location pos;
if (args.argsLength() == 1) { if (coordinates != null) {
if (args.getString(0).matches("-?\\d+,-?\\d+,-?\\d+")) { pos = new Location(player.getWorld(), coordinates.toVector3());
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;
}
} else { } else {
pos = player.getBlockIn(); pos = player.getBlockIn();
} }
@ -151,11 +138,8 @@ public class SelectionCommands {
} }
@Command( @Command(
aliases = { "/hpos1" }, name = "/hpos1",
usage = "", desc = "Set position 1 to targeted block"
desc = "Set position 1 to targeted block",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.selection.hpos") @CommandPermissions("worldedit.selection.hpos")
public void hpos1(Player player, LocalSession session) throws WorldEditException { public void hpos1(Player player, LocalSession session) throws WorldEditException {
@ -176,11 +160,8 @@ public class SelectionCommands {
} }
@Command( @Command(
aliases = { "/hpos2" }, name = "/hpos2",
usage = "", desc = "Set position 2 to targeted block"
desc = "Set position 2 to targeted block",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.selection.hpos") @CommandPermissions("worldedit.selection.hpos")
public void hpos2(Player player, LocalSession session) throws WorldEditException { public void hpos2(Player player, LocalSession session) throws WorldEditException {
@ -201,28 +182,22 @@ public class SelectionCommands {
} }
@Command( @Command(
aliases = { "/chunk" }, name = "/chunk",
usage = "[x,z coordinates]", desc = "Set the selection to your current chunk."
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
) )
@Logging(POSITION) @Logging(POSITION)
@CommandPermissions("worldedit.selection.chunk") @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 min;
final BlockVector3 max; final BlockVector3 max;
final World world = player.getWorld(); final World world = player.getWorld();
if (args.hasFlag('s')) { if (expandSelection) {
Region region = session.getSelection(world); Region region = session.getSelection(world);
final BlockVector2 min2D = ChunkStore.toChunk(region.getMinimumPoint()); final BlockVector2 min2D = ChunkStore.toChunk(region.getMinimumPoint());
@ -236,16 +211,11 @@ public class SelectionCommands {
+ max2D.getBlockX() + ", " + max2D.getBlockZ() + ")"); + max2D.getBlockX() + ", " + max2D.getBlockZ() + ")");
} else { } else {
final BlockVector2 min2D; final BlockVector2 min2D;
if (args.argsLength() == 1) { if (coordinates != null) {
// coords specified // coords specified
String[] coords = args.getString(0).split(","); min2D = useChunkCoordinates
if (coords.length != 2) { ? coordinates
throw new InsufficientArgumentsException("Invalid coordinates specified."); : ChunkStore.toChunk(coordinates.toBlockVector3());
}
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());
} else { } else {
// use player loc // use player loc
min2D = ChunkStore.toChunk(player.getBlockIn().toVector().toBlockPoint()); min2D = ChunkStore.toChunk(player.getBlockIn().toVector().toBlockPoint());
@ -273,29 +243,21 @@ public class SelectionCommands {
} }
@Command( @Command(
aliases = { "/wand" }, name = "/wand",
usage = "", desc = "Get the wand object"
desc = "Get the wand object",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.wand") @CommandPermissions("worldedit.wand")
public void wand(Player player) throws WorldEditException { public void wand(Player player) throws WorldEditException {
player.giveItem(new BaseItemStack(ItemTypes.get(we.getConfiguration().wandItem), 1)); player.giveItem(new BaseItemStack(ItemTypes.get(we.getConfiguration().wandItem), 1));
player.print("Left click: select pos #1; Right click: select pos #2"); player.print("Left click: select pos #1; Right click: select pos #2");
} }
@Command( @Command(
aliases = { "toggleeditwand" }, name = "toggleeditwand",
usage = "", desc = "Toggle functionality of the edit wand"
desc = "Toggle functionality of the edit wand",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.wand.toggle") @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()); session.setToolControl(!session.isToolControlEnabled());
if (session.isToolControlEnabled()) { if (session.isToolControlEnabled()) {
@ -306,20 +268,23 @@ public class SelectionCommands {
} }
@Command( @Command(
aliases = { "/expand" }, name = "/expand",
usage = "<amount> [reverse-amount] <direction>", desc = "Expand the selection area"
desc = "Expand the selection area",
min = 1,
max = 3
) )
@Logging(REGION) @Logging(REGION)
@CommandPermissions("worldedit.selection.expand") @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<BlockVector3> direction) throws WorldEditException {
// Special syntax (//expand vert) to expand the selection between // Special syntax (//expand vert) to expand the selection between
// sky and bedrock. // sky and bedrock.
if (args.getString(0).equalsIgnoreCase("vert") if (amount.isVert()) {
|| args.getString(0).equalsIgnoreCase("vertical")) {
Region region = session.getSelection(player.getWorld()); Region region = session.getSelection(player.getWorld());
try { try {
int oldSize = region.getArea(); int oldSize = region.getArea();
@ -338,57 +303,16 @@ public class SelectionCommands {
return; return;
} }
List<BlockVector3> 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()); Region region = session.getSelection(player.getWorld());
int oldSize = region.getArea(); int oldSize = region.getArea();
if (reverseChange == 0) { if (reverseAmount == 0) {
for (BlockVector3 dir : dirs) { for (BlockVector3 dir : direction) {
region.expand(dir.multiply(change)); region.expand(dir.multiply(amount.getAmount()));
} }
} else { } else {
for (BlockVector3 dir : dirs) { for (BlockVector3 dir : direction) {
region.expand(dir.multiply(change), dir.multiply(-reverseChange)); region.expand(dir.multiply(amount.getAmount()), dir.multiply(-reverseAmount));
} }
} }
@ -397,70 +321,33 @@ public class SelectionCommands {
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
player.print("Region expanded " + (newSize - oldSize) + " blocks."); player.print("Region expanded " + (newSize - oldSize) + " block(s).");
} }
@Command( @Command(
aliases = { "/contract" }, name = "/contract",
usage = "<amount> [reverse-amount] [direction]", desc = "Contract the selection area"
desc = "Contract the selection area",
min = 1,
max = 3
) )
@Logging(REGION) @Logging(REGION)
@CommandPermissions("worldedit.selection.contract") @CommandPermissions("worldedit.selection.contract")
public void contract(Player player, LocalSession session, CommandContext args) throws WorldEditException { public void contract(Player player, LocalSession session,
@Arg(desc = "Amount to contract the selection by")
List<BlockVector3> dirs = new ArrayList<>(); int amount,
int change = args.getInteger(0); @Arg(desc = "Amount to contract the selection by in the other direction", def = "0")
int reverseChange = 0; int reverseAmount,
@Arg(desc = "Direction to contract", def = Direction.AIM)
switch (args.argsLength()) { @MultiDirection
case 2: List<BlockVector3> direction) throws WorldEditException {
// 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;
}
try { try {
Region region = session.getSelection(player.getWorld()); Region region = session.getSelection(player.getWorld());
int oldSize = region.getArea(); int oldSize = region.getArea();
if (reverseChange == 0) { if (reverseAmount == 0) {
for (BlockVector3 dir : dirs) { for (BlockVector3 dir : direction) {
region.contract(dir.multiply(change)); region.contract(dir.multiply(amount));
} }
} else { } else {
for (BlockVector3 dir : dirs) { for (BlockVector3 dir : direction) {
region.contract(dir.multiply(change), dir.multiply(-reverseChange)); region.contract(dir.multiply(amount), dir.multiply(-reverseAmount));
} }
} }
session.getRegionSelector(player.getWorld()).learnChanges(); session.getRegionSelector(player.getWorld()).learnChanges();
@ -476,35 +363,22 @@ public class SelectionCommands {
} }
@Command( @Command(
aliases = { "/shift" }, name = "/shift",
usage = "<amount> [direction]", desc = "Shift the selection area"
desc = "Shift the selection area",
min = 1,
max = 2
) )
@Logging(REGION) @Logging(REGION)
@CommandPermissions("worldedit.selection.shift") @CommandPermissions("worldedit.selection.shift")
public void shift(Player player, LocalSession session, CommandContext args) throws WorldEditException { public void shift(Player player, LocalSession session,
@Arg(desc = "Amount to shift the selection by")
List<BlockVector3> dirs = new ArrayList<>(); int amount,
int change = args.getInteger(0); @Arg(desc = "Direction to contract", def = Direction.AIM)
if (args.argsLength() == 2) { @MultiDirection
if (args.getString(1).contains(",")) { List<BlockVector3> direction) throws WorldEditException {
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"));
}
try { try {
Region region = session.getSelection(player.getWorld()); Region region = session.getSelection(player.getWorld());
for (BlockVector3 dir : dirs) { for (BlockVector3 dir : direction) {
region.shift(dir.multiply(change)); region.shift(dir.multiply(amount));
} }
session.getRegionSelector(player.getWorld()).learnChanges(); session.getRegionSelector(player.getWorld()).learnChanges();
@ -518,107 +392,92 @@ public class SelectionCommands {
} }
@Command( @Command(
aliases = { "/outset" }, name = "/outset",
usage = "<amount>", desc = "Outset the selection area"
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
) )
@Logging(REGION) @Logging(REGION)
@CommandPermissions("worldedit.selection.outset") @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 region = session.getSelection(player.getWorld());
region.expand(getChangesForEachDir(args)); region.expand(getChangesForEachDir(amount, onlyHorizontal, onlyVertical));
session.getRegionSelector(player.getWorld()).learnChanges(); session.getRegionSelector(player.getWorld()).learnChanges();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
player.print("Region outset."); player.print("Region outset.");
} }
@Command( @Command(
aliases = { "/inset" }, name = "/inset",
usage = "<amount>", desc = "Inset the selection area"
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
) )
@Logging(REGION) @Logging(REGION)
@CommandPermissions("worldedit.selection.inset") @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 region = session.getSelection(player.getWorld());
region.contract(getChangesForEachDir(args)); region.contract(getChangesForEachDir(amount, onlyHorizontal, onlyVertical));
session.getRegionSelector(player.getWorld()).learnChanges(); session.getRegionSelector(player.getWorld()).learnChanges();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
player.print("Region inset."); player.print("Region inset.");
} }
private BlockVector3[] getChangesForEachDir(CommandContext args) { private BlockVector3[] getChangesForEachDir(int amount, boolean onlyHorizontal, boolean onlyVertical) {
List<BlockVector3> changes = new ArrayList<>(6); Stream.Builder<BlockVector3> changes = Stream.builder();
int change = args.getInteger(0);
if (!args.hasFlag('h')) { if (!onlyHorizontal) {
changes.add((BlockVector3.UNIT_Y).multiply(change)); changes.add(BlockVector3.UNIT_Y);
changes.add((BlockVector3.UNIT_MINUS_Y).multiply(change)); changes.add(BlockVector3.UNIT_MINUS_Y);
} }
if (!args.hasFlag('v')) { if (!onlyVertical) {
changes.add((BlockVector3.UNIT_X).multiply(change)); changes.add(BlockVector3.UNIT_X);
changes.add((BlockVector3.UNIT_MINUS_X).multiply(change)); changes.add(BlockVector3.UNIT_MINUS_X);
changes.add((BlockVector3.UNIT_Z).multiply(change)); changes.add(BlockVector3.UNIT_Z);
changes.add((BlockVector3.UNIT_MINUS_Z).multiply(change)); changes.add(BlockVector3.UNIT_MINUS_Z);
} }
return changes.toArray(new BlockVector3[0]); return changes.build().map(v -> v.multiply(amount)).toArray(BlockVector3[]::new);
} }
@Command( @Command(
aliases = { "/size" }, name = "/size",
flags = "c", desc = "Get information about the selection"
usage = "",
desc = "Get information about the selection",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.selection.size") @CommandPermissions("worldedit.selection.size")
public void size(Player player, LocalSession session, CommandContext args) throws WorldEditException { public void size(Player player, LocalSession session,
if (args.hasFlag('c')) { @Switch(name = 'c', desc = "Get clipboard info instead")
boolean clipboardInfo) throws WorldEditException {
Region region;
if (clipboardInfo) {
ClipboardHolder holder = session.getClipboard(); ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard(); Clipboard clipboard = holder.getClipboard();
Region region = clipboard.getRegion(); region = clipboard.getRegion();
BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint());
BlockVector3 origin = clipboard.getOrigin(); BlockVector3 origin = clipboard.getOrigin();
player.print("Cuboid dimensions (max - min): " + size);
player.print("Offset: " + origin); player.print("Offset: " + origin);
player.print("Cuboid distance: " + size.distance(BlockVector3.ONE)); } else {
player.print("# of blocks: " + (int) (size.getX() * size.getY() * size.getZ())); region = session.getSelection(player.getWorld());
return;
}
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() BlockVector3 size = region.getMaximumPoint()
.subtract(region.getMinimumPoint()) .subtract(region.getMinimumPoint())
.add(1, 1, 1); .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("Size: " + size);
player.print("Cuboid distance: " + region.getMaximumPoint().distance(region.getMinimumPoint())); player.print("Cuboid distance: " + region.getMaximumPoint().distance(region.getMinimumPoint()));
player.print("# of blocks: " + region.getArea()); player.print("# of blocks: " + region.getArea());
@ -626,48 +485,41 @@ public class SelectionCommands {
@Command( @Command(
aliases = { "/count" }, name = "/count",
usage = "<block>", desc = "Counts the number of a certain type of block"
flags = "f",
desc = "Counts the number of a certain type of block",
min = 1,
max = 1
) )
@CommandPermissions("worldedit.analysis.count") @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(); ParserContext context = new ParserContext();
context.setActor(player); context.setActor(player);
context.setExtent(player.getExtent()); context.setExtent(player.getExtent());
context.setWorld(player.getWorld()); context.setWorld(player.getWorld());
context.setSession(session); context.setSession(session);
context.setRestricted(false); context.setRestricted(false);
context.setPreferringWildcard(args.hasFlag('f')); context.setPreferringWildcard(fuzzy);
Set<BaseBlock> searchBlocks = we.getBlockFactory().parseFromListInput(args.getString(0), context); Set<BaseBlock> searchBlocks = we.getBlockFactory().parseFromListInput(blocks, context);
int count = editSession.countBlocks(session.getSelection(player.getWorld()), searchBlocks); int count = editSession.countBlocks(session.getSelection(player.getWorld()), searchBlocks);
player.print("Counted: " + count); player.print("Counted: " + count);
} }
@Command( @Command(
aliases = { "/distr" }, name = "/distr",
usage = "", desc = "Get the distribution of blocks in the selection"
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
) )
@CommandPermissions("worldedit.analysis.distr") @CommandPermissions("worldedit.analysis.distr")
public void distr(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException, CommandException { public void distr(Player player, LocalSession session, EditSession editSession,
@Switch(name = 'c', desc = "Get the distribution of the clipboard instead")
boolean separateStates = args.hasFlag('d'); boolean clipboardDistr,
@Switch(name = 'd', desc = "Separate blocks by state")
boolean separateStates) throws WorldEditException {
List<Countable<BlockState>> distribution; List<Countable<BlockState>> distribution;
if (args.hasFlag('c')) { if (clipboardDistr) {
Clipboard clipboard = session.getClipboard().getClipboard(); // throws if missing Clipboard clipboard = session.getClipboard().getClipboard(); // throws if missing
BlockDistributionCounter count = new BlockDistributionCounter(clipboard, separateStates); BlockDistributionCounter count = new BlockDistributionCounter(clipboard, separateStates);
RegionVisitor visitor = new RegionVisitor(clipboard.getRegion(), count); RegionVisitor visitor = new RegionVisitor(clipboard.getRegion(), count);
@ -707,72 +559,86 @@ public class SelectionCommands {
} }
@Command( @Command(
aliases = { "/sel", ";", "/desel", "/deselect" }, name = "/sel",
flags = "d", aliases = { ";", "/desel", "/deselect" },
usage = "[cuboid|extend|poly|ellipsoid|sphere|cyl|convex]", desc = "Choose a region selector"
desc = "Choose a region selector",
min = 0,
max = 1
) )
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(); final World world = player.getWorld();
if (args.argsLength() == 0) { if (selector == null) {
session.getRegionSelector(world).clear(); session.getRegionSelector(world).clear();
session.dispatchCUISelection(player); session.dispatchCUISelection(player);
player.print("Selection cleared."); player.print("Selection cleared.");
return; return;
} }
final String typeName = args.getString(0);
final RegionSelector oldSelector = session.getRegionSelector(world); final RegionSelector oldSelector = session.getRegionSelector(world);
final RegionSelector selector; final RegionSelector newSelector;
if (typeName.equalsIgnoreCase("cuboid")) { switch (selector) {
selector = new CuboidRegionSelector(oldSelector); case CUBOID:
player.print("Cuboid: left click for point 1, right click for point 2"); newSelector = new CuboidRegionSelector(oldSelector);
} else if (typeName.equalsIgnoreCase("extend")) { player.print("Cuboid: left click for point 1, right click for point 2");
selector = new ExtendingCuboidRegionSelector(oldSelector); break;
player.print("Cuboid: left click for a starting point, right click to extend"); case EXTEND:
} else if (typeName.equalsIgnoreCase("poly")) { newSelector = new ExtendingCuboidRegionSelector(oldSelector);
selector = new Polygonal2DRegionSelector(oldSelector); player.print("Cuboid: left click for a starting point, right click to extend");
player.print("2D polygon selector: Left/right click to add a point."); break;
Optional<Integer> limit = ActorSelectorLimits.forActor(player).getPolygonVertexLimit(); case POLY: {
limit.ifPresent(integer -> player.print(integer + " points maximum.")); newSelector = new Polygonal2DRegionSelector(oldSelector);
} else if (typeName.equalsIgnoreCase("ellipsoid")) { player.print("2D polygon selector: Left/right click to add a point.");
selector = new EllipsoidRegionSelector(oldSelector); Optional<Integer> limit = ActorSelectorLimits.forActor(player).getPolygonVertexLimit();
player.print("Ellipsoid selector: left click=center, right click to extend"); limit.ifPresent(integer -> player.print(integer + " points maximum."));
} else if (typeName.equalsIgnoreCase("sphere")) { break;
selector = new SphereRegionSelector(oldSelector); }
player.print("Sphere selector: left click=center, right click to set radius"); case ELLIPSOID:
} else if (typeName.equalsIgnoreCase("cyl")) { newSelector = new EllipsoidRegionSelector(oldSelector);
selector = new CylinderRegionSelector(oldSelector); player.print("Ellipsoid selector: left click=center, right click to extend");
player.print("Cylindrical selector: Left click=center, right click to extend."); break;
} else if (typeName.equalsIgnoreCase("convex") || typeName.equalsIgnoreCase("hull") || typeName.equalsIgnoreCase("polyhedron")) { case SPHERE:
selector = new ConvexPolyhedralRegionSelector(oldSelector); newSelector = new SphereRegionSelector(oldSelector);
player.print("Convex polyhedral selector: Left click=First vertex, right click to add more."); player.print("Sphere selector: left click=center, right click to set radius");
Optional<Integer> limit = ActorSelectorLimits.forActor(player).getPolyhedronVertexLimit(); break;
limit.ifPresent(integer -> player.print(integer + " points maximum.")); case CYL:
} else { newSelector = new CylinderRegionSelector(oldSelector);
CommandListBox box = new CommandListBox("Selection modes"); player.print("Cylindrical selector: Left click=center, right click to extend.");
TextComponentProducer contents = box.getContents(); break;
contents.append(SubtleFormat.wrap("Select one of the modes below:")).newline(); 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<Integer> 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("cuboid", "Select two corners of a cuboid", "//sel cuboid");
box.appendCommand("extend", "Fast cuboid selection mode", "//sel extend"); box.appendCommand("extend", "Fast cuboid selection mode", "//sel extend");
box.appendCommand("poly", "Select a 2D polygon with height", "//sel poly"); box.appendCommand("poly", "Select a 2D polygon with height", "//sel poly");
box.appendCommand("ellipsoid", "Select an ellipsoid", "//sel ellipsoid"); box.appendCommand("ellipsoid", "Select an ellipsoid", "//sel ellipsoid");
box.appendCommand("sphere", "Select a sphere", "//sel sphere"); box.appendCommand("sphere", "Select a sphere", "//sel sphere");
box.appendCommand("cyl", "Select a cylinder", "//sel cyl"); box.appendCommand("cyl", "Select a cylinder", "//sel cyl");
box.appendCommand("convex", "Select a convex polyhedral", "//sel convex"); box.appendCommand("convex", "Select a convex polyhedral", "//sel convex");
player.print(box.create()); player.print(box.create(1));
return; return;
} }
if (args.hasFlag('d')) { if (setDefaultSelector) {
RegionSelectorType found = null; RegionSelectorType found = null;
for (RegionSelectorType type : RegionSelectorType.values()) { for (RegionSelectorType type : RegionSelectorType.values()) {
if (type.getSelectorClass() == selector.getClass()) { if (type.getSelectorClass() == newSelector.getClass()) {
found = type; found = type;
break; break;
} }
@ -786,7 +652,7 @@ public class SelectionCommands {
} }
} }
session.setRegionSelector(world, selector); session.setRegionSelector(world, newSelector);
session.dispatchCUISelection(player); session.dispatchCUISelection(player);
} }

View File

@ -21,32 +21,34 @@
package com.sk89q.worldedit.command; 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.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; 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.entity.Player;
import com.sk89q.worldedit.world.snapshot.InvalidSnapshotException; import com.sk89q.worldedit.world.snapshot.InvalidSnapshotException;
import com.sk89q.worldedit.world.snapshot.Snapshot; import com.sk89q.worldedit.world.snapshot.Snapshot;
import com.sk89q.worldedit.world.storage.MissingWorldException; 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.File;
import java.io.IOException; import java.io.IOException;
import java.text.DateFormat; import java.time.ZonedDateTime;
import java.text.SimpleDateFormat; import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.List; import java.util.List;
/** /**
* Snapshot commands. * Snapshot commands.
*/ */
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class SnapshotCommands { 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; private final WorldEdit we;
public SnapshotCommands(WorldEdit we) { public SnapshotCommands(WorldEdit we) {
@ -54,14 +56,13 @@ public class SnapshotCommands {
} }
@Command( @Command(
aliases = { "list" }, name = "list",
usage = "[num]", desc = "List snapshots"
desc = "List snapshots",
min = 0,
max = 1
) )
@CommandPermissions("worldedit.snapshots.list") @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(); LocalConfiguration config = we.getConfiguration();
@ -75,7 +76,7 @@ public class SnapshotCommands {
if (!snapshots.isEmpty()) { 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() + "'"); player.print("Snapshots for world: '" + player.getWorld().getName() + "'");
for (byte i = 0; i < Math.min(num, snapshots.size()); i++) { for (byte i = 0; i < Math.min(num, snapshots.size()); i++) {
@ -104,14 +105,13 @@ public class SnapshotCommands {
} }
@Command( @Command(
aliases = { "use" }, name = "use",
usage = "<snapshot>", desc = "Choose a snapshot to use"
desc = "Choose a snapshot to use",
min = 1,
max = 1
) )
@CommandPermissions("worldedit.snapshots.restore") @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(); LocalConfiguration config = we.getConfiguration();
@ -120,8 +120,6 @@ public class SnapshotCommands {
return; return;
} }
String name = args.getString(0);
// Want the latest snapshot? // Want the latest snapshot?
if (name.equalsIgnoreCase("latest")) { if (name.equalsIgnoreCase("latest")) {
try { try {
@ -147,14 +145,13 @@ public class SnapshotCommands {
} }
@Command( @Command(
aliases = { "sel" }, name = "sel",
usage = "<index>", desc = "Choose the snapshot based on the list id"
desc = "Choose the snapshot based on the list id",
min = 1,
max = 1
) )
@CommandPermissions("worldedit.snapshots.restore") @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(); LocalConfiguration config = we.getConfiguration();
if (config.snapshotRepo == null) { if (config.snapshotRepo == null) {
@ -162,14 +159,6 @@ public class SnapshotCommands {
return; 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) { if (index < 1) {
player.printError("Invalid index, must be equal or higher then 1."); player.printError("Invalid index, must be equal or higher then 1.");
return; return;
@ -194,14 +183,13 @@ public class SnapshotCommands {
} }
@Command( @Command(
aliases = { "before" }, name = "before",
usage = "<date>", desc = "Choose the nearest snapshot before a date"
desc = "Choose the nearest snapshot before a date",
min = 1,
max = -1
) )
@CommandPermissions("worldedit.snapshots.restore") @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(); LocalConfiguration config = we.getConfiguration();
@ -210,37 +198,29 @@ public class SnapshotCommands {
return; return;
} }
Calendar date = session.detectDate(args.getJoinedStrings(0)); try {
Snapshot snapshot = config.snapshotRepo.getSnapshotBefore(date, player.getWorld().getName());
if (date == null) { if (snapshot == null) {
player.printError("Could not detect the date inputted."); player.printError("Couldn't find a snapshot before "
} else { + dateFormat.withZone(session.getTimeZone()).format(date) + ".");
try { } else {
Snapshot snapshot = config.snapshotRepo.getSnapshotBefore(date, player.getWorld().getName()); session.setSnapshot(snapshot);
player.print("Snapshot set to: " + snapshot.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.");
} }
} catch (MissingWorldException ex) {
player.printError("No snapshots were found for this world.");
} }
} }
@Command( @Command(
aliases = { "after" }, name = "after",
usage = "<date>", desc = "Choose the nearest snapshot after a date"
desc = "Choose the nearest snapshot after a date",
min = 1,
max = -1
) )
@CommandPermissions("worldedit.snapshots.restore") @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(); LocalConfiguration config = we.getConfiguration();
@ -249,24 +229,17 @@ public class SnapshotCommands {
return; return;
} }
Calendar date = session.detectDate(args.getJoinedStrings(0)); try {
Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date, player.getWorld().getName());
if (date == null) { if (snapshot == null) {
player.printError("Could not detect the date inputted."); player.printError("Couldn't find a snapshot after "
} else { + dateFormat.withZone(session.getTimeZone()).format(date) + ".");
try { } else {
Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date, player.getWorld().getName()); session.setSnapshot(snapshot);
if (snapshot == null) { player.print("Snapshot set to: " + snapshot.getName());
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.");
} }
} catch (MissingWorldException ex) {
player.printError("No snapshots were found for this world.");
} }
} }

View File

@ -19,15 +19,14 @@
package com.sk89q.worldedit.command; 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.EditSession;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; 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.entity.Player;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.DataException; 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.snapshot.SnapshotRestore;
import com.sk89q.worldedit.world.storage.ChunkStore; import com.sk89q.worldedit.world.storage.ChunkStore;
import com.sk89q.worldedit.world.storage.MissingWorldException; 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.File;
import java.io.IOException; 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 { public class SnapshotUtilCommands {
private final WorldEdit we; private final WorldEdit we;
@ -51,15 +54,15 @@ public class SnapshotUtilCommands {
} }
@Command( @Command(
aliases = { "restore", "/restore" }, name = "restore",
usage = "[snapshot]", aliases = { "/restore" },
desc = "Restore the selection from a snapshot", desc = "Restore the selection from a snapshot"
min = 0,
max = 1
) )
@Logging(REGION) @Logging(REGION)
@CommandPermissions("worldedit.snapshots.restore") @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(); LocalConfiguration config = we.getConfiguration();
@ -71,9 +74,9 @@ public class SnapshotUtilCommands {
Region region = session.getSelection(player.getWorld()); Region region = session.getSelection(player.getWorld());
Snapshot snapshot; Snapshot snapshot;
if (args.argsLength() > 0) { if (snapshotName != null) {
try { try {
snapshot = config.snapshotRepo.getSnapshot(args.getString(0)); snapshot = config.snapshotRepo.getSnapshot(snapshotName);
} catch (InvalidSnapshotException e) { } catch (InvalidSnapshotException e) {
player.printError("That snapshot does not exist or is not available."); player.printError("That snapshot does not exist or is not available.");
return; return;
@ -110,7 +113,7 @@ public class SnapshotUtilCommands {
} }
} }
ChunkStore chunkStore = null; ChunkStore chunkStore;
// Load chunk store // Load chunk store
try { try {

View File

@ -19,9 +19,6 @@
package com.sk89q.worldedit.command; 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.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; 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.AreaPickaxe;
import com.sk89q.worldedit.command.tool.RecursivePickaxe; import com.sk89q.worldedit.command.tool.RecursivePickaxe;
import com.sk89q.worldedit.command.tool.SinglePickaxe; 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 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 { public class SuperPickaxeCommands {
private final WorldEdit we; private final WorldEdit we;
@ -39,32 +42,26 @@ public class SuperPickaxeCommands {
} }
@Command( @Command(
aliases = { "single" }, name = "single",
usage = "", desc = "Enable the single block super pickaxe mode"
desc = "Enable the single block super pickaxe mode",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.superpickaxe") @CommandPermissions("worldedit.superpickaxe")
public void single(Player player, LocalSession session) throws WorldEditException { public void single(Player player, LocalSession session) throws WorldEditException {
session.setSuperPickaxe(new SinglePickaxe()); session.setSuperPickaxe(new SinglePickaxe());
session.enableSuperPickAxe(); session.enableSuperPickAxe();
player.print("Mode changed. Left click with a pickaxe. // to disable."); player.print("Mode changed. Left click with a pickaxe. // to disable.");
} }
@Command( @Command(
aliases = { "area" }, name = "area",
usage = "<radius>", desc = "Enable the area super pickaxe pickaxe mode"
desc = "Enable the area super pickaxe pickaxe mode",
min = 1,
max = 1
) )
@CommandPermissions("worldedit.superpickaxe.area") @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(); LocalConfiguration config = we.getConfiguration();
int range = args.getInteger(0);
if (range > config.maxSuperPickaxeSize) { if (range > config.maxSuperPickaxeSize) {
player.printError("Maximum range: " + config.maxSuperPickaxeSize); player.printError("Maximum range: " + config.maxSuperPickaxeSize);
@ -77,17 +74,16 @@ public class SuperPickaxeCommands {
} }
@Command( @Command(
aliases = { "recur", "recursive" }, name = "recursive",
usage = "<radius>", aliases = { "recur" },
desc = "Enable the recursive super pickaxe pickaxe mode", desc = "Enable the recursive super pickaxe pickaxe mode"
min = 1,
max = 1
) )
@CommandPermissions("worldedit.superpickaxe.recursive") @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(); LocalConfiguration config = we.getConfiguration();
double range = args.getDouble(0);
if (range > config.maxSuperPickaxeSize) { if (range > config.maxSuperPickaxeSize) {
player.printError("Maximum range: " + config.maxSuperPickaxeSize); player.printError("Maximum range: " + config.maxSuperPickaxeSize);

View File

@ -19,9 +19,6 @@
package com.sk89q.worldedit.command; 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.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; 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.LongRangeBuildTool;
import com.sk89q.worldedit.command.tool.QueryTool; import com.sk89q.worldedit.command.tool.QueryTool;
import com.sk89q.worldedit.command.tool.TreePlanter; 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.entity.Player;
import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.TreeGenerator; 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 { public class ToolCommands {
private final WorldEdit we; private final WorldEdit we;
@ -49,11 +52,8 @@ public class ToolCommands {
} }
@Command( @Command(
aliases = { "none" }, name = "none",
usage = "", desc = "Unbind a bound tool from your current item"
desc = "Unbind a bound tool from your current item",
min = 0,
max = 0
) )
public void none(Player player, LocalSession session) throws WorldEditException { public void none(Player player, LocalSession session) throws WorldEditException {
@ -62,11 +62,8 @@ public class ToolCommands {
} }
@Command( @Command(
aliases = { "info" }, name = "info",
usage = "", desc = "Block information tool"
desc = "Block information tool",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.tool.info") @CommandPermissions("worldedit.tool.info")
public void info(Player player, LocalSession session) throws WorldEditException { public void info(Player player, LocalSession session) throws WorldEditException {
@ -78,49 +75,34 @@ public class ToolCommands {
} }
@Command( @Command(
aliases = { "tree" }, name = "tree",
usage = "[type]", desc = "Tree generator tool"
desc = "Tree generator tool",
min = 0,
max = 1
) )
@CommandPermissions("worldedit.tool.tree") @CommandPermissions("worldedit.tool.tree")
public void tree(Player player, LocalSession session, CommandContext args) throws WorldEditException { public void tree(Player player, LocalSession session,
@Arg(desc = "Type of tree to generate", def = "tree")
TreeGenerator.TreeType type = args.argsLength() > 0 TreeGenerator.TreeType type) throws WorldEditException {
? TreeGenerator.lookup(args.getString(0))
: TreeGenerator.TreeType.TREE;
if (type == null) {
player.printError("Tree type '" + args.getString(0) + "' is unknown.");
return;
}
BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND); BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(itemStack.getType(), new TreePlanter(type)); session.setTool(itemStack.getType(), new TreePlanter(type));
player.print("Tree tool bound to " + itemStack.getType().getName() + "."); player.print("Tree tool bound to " + itemStack.getType().getName() + ".");
} }
@Command( @Command(
aliases = { "repl" }, name = "repl",
usage = "<block>", desc = "Block replacer tool"
desc = "Block replacer tool",
min = 1,
max = 1
) )
@CommandPermissions("worldedit.tool.replacer") @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); BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(itemStack.getType(), new BlockReplacer(pattern)); session.setTool(itemStack.getType(), new BlockReplacer(pattern));
player.print("Block replacer tool bound to " + itemStack.getType().getName() + "."); player.print("Block replacer tool bound to " + itemStack.getType().getName() + ".");
} }
@Command( @Command(
aliases = { "cycler" }, name = "cycler",
usage = "", desc = "Block data cycler tool"
desc = "Block data cycler tool",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.tool.data-cycler") @CommandPermissions("worldedit.tool.data-cycler")
public void cycler(Player player, LocalSession session) throws WorldEditException { public void cycler(Player player, LocalSession session) throws WorldEditException {
@ -131,14 +113,16 @@ public class ToolCommands {
} }
@Command( @Command(
aliases = { "floodfill", "flood" }, name = "floodfill",
usage = "<pattern> <range>", aliases = { "flood" },
desc = "Flood fill tool", desc = "Flood fill tool"
min = 2,
max = 2
) )
@CommandPermissions("worldedit.tool.flood-fill") @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(); LocalConfiguration config = we.getConfiguration();
@ -153,11 +137,8 @@ public class ToolCommands {
} }
@Command( @Command(
aliases = { "deltree" }, name = "deltree",
usage = "", desc = "Floating tree remover tool"
desc = "Floating tree remover tool",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.tool.deltree") @CommandPermissions("worldedit.tool.deltree")
public void deltree(Player player, LocalSession session) throws WorldEditException { public void deltree(Player player, LocalSession session) throws WorldEditException {
@ -169,11 +150,8 @@ public class ToolCommands {
} }
@Command( @Command(
aliases = { "farwand" }, name = "farwand",
usage = "", desc = "Wand at a distance tool"
desc = "Wand at a distance tool",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.tool.farwand") @CommandPermissions("worldedit.tool.farwand")
public void farwand(Player player, LocalSession session) throws WorldEditException { public void farwand(Player player, LocalSession session) throws WorldEditException {
@ -184,14 +162,16 @@ public class ToolCommands {
} }
@Command( @Command(
aliases = { "lrbuild", "/lrbuild" }, name = "lrbuild",
usage = "<leftclick block> <rightclick block>", aliases = { "/lrbuild" },
desc = "Long-range building tool", desc = "Long-range building tool"
min = 2,
max = 2
) )
@CommandPermissions("worldedit.tool.lrbuild") @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); BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(itemStack.getType(), new LongRangeBuildTool(primary, secondary)); session.setTool(itemStack.getType(), new LongRangeBuildTool(primary, secondary));

View File

@ -19,21 +19,23 @@
package com.sk89q.worldedit.command; 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.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; 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.entity.Player;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.util.HandSide; 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. * Tool commands.
*/ */
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ToolUtilCommands { public class ToolUtilCommands {
private final WorldEdit we; private final WorldEdit we;
@ -42,44 +44,37 @@ public class ToolUtilCommands {
} }
@Command( @Command(
aliases = { "/", "," }, name = "/",
usage = "[on|off]", aliases = { "," },
desc = "Toggle the super pickaxe function", desc = "Toggle the super pickaxe function"
min = 0,
max = 1
) )
@CommandPermissions("worldedit.superpickaxe") @CommandPermissions("worldedit.superpickaxe")
public void togglePickaxe(Player player, LocalSession session, CommandContext args) throws WorldEditException { public void togglePickaxe(Player player, LocalSession session,
@Arg(desc = "The new super pickaxe state", def = "")
String newState = args.getString(0, null); Boolean superPickaxe) throws WorldEditException {
if (session.hasSuperPickAxe()) { boolean hasSuperPickAxe = session.hasSuperPickAxe();
if ("on".equals(newState)) { if (superPickaxe != null && superPickaxe == hasSuperPickAxe) {
player.printError("Super pick axe already enabled."); player.printError("Super pickaxe already " + (superPickaxe ? "enabled" : "disabled") + ".");
return; return;
} }
if (hasSuperPickAxe) {
session.disableSuperPickAxe(); session.disableSuperPickAxe();
player.print("Super pick axe disabled."); player.print("Super pickaxe disabled.");
} else { } else {
if ("off".equals(newState)) {
player.printError("Super pick axe already disabled.");
return;
}
session.enableSuperPickAxe(); session.enableSuperPickAxe();
player.print("Super pick axe enabled."); player.print("Super pickaxe enabled.");
} }
} }
@Command( @Command(
aliases = { "mask" }, name = "mask",
usage = "[mask]", desc = "Set the brush mask"
desc = "Set the brush mask",
min = 0,
max = -1
) )
@CommandPermissions("worldedit.brush.options.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) { if (mask == null) {
session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setMask(null); session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setMask(null);
player.print("Brush mask disabled."); player.print("Brush mask disabled.");
@ -90,46 +85,41 @@ public class ToolUtilCommands {
} }
@Command( @Command(
aliases = { "mat", "material" }, name = "material",
usage = "[pattern]", aliases = { "/material" },
desc = "Set the brush material", desc = "Set the brush material"
min = 1,
max = 1
) )
@CommandPermissions("worldedit.brush.options.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); session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setFill(pattern);
player.print("Brush material set."); player.print("Brush material set.");
} }
@Command( @Command(
aliases = { "range" }, name = "range",
usage = "[pattern]", desc = "Set the brush range"
desc = "Set the brush range", )
min = 1,
max = 1
)
@CommandPermissions("worldedit.brush.options.range") @CommandPermissions("worldedit.brush.options.range")
public void range(Player player, LocalSession session, CommandContext args) throws WorldEditException { public void range(Player player, LocalSession session,
int range = args.getInteger(0); @Arg(desc = "The range of the brush")
int range) throws WorldEditException {
session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setRange(range); session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setRange(range);
player.print("Brush range set."); player.print("Brush range set.");
} }
@Command( @Command(
aliases = { "size" }, name = "size",
usage = "[pattern]", desc = "Set the brush size"
desc = "Set the brush size",
min = 1,
max = 1
) )
@CommandPermissions("worldedit.brush.options.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); session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setSize(size);
we.checkMaxBrushRadius(radius);
session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setSize(radius);
player.print("Brush size set."); player.print("Brush size set.");
} }
} }

View File

@ -19,30 +19,31 @@
package com.sk89q.worldedit.command; 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.EditSession;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; 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.CreatureButcher;
import com.sk89q.worldedit.command.util.EntityRemover; 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.Entity;
import com.sk89q.worldedit.entity.Player; 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.Actor;
import com.sk89q.worldedit.extension.platform.Capability; 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.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.operation.Operations;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.EntityVisitor; import com.sk89q.worldedit.function.visitor.EntityVisitor;
import com.sk89q.worldedit.internal.expression.Expression; 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.CuboidRegion;
import com.sk89q.worldedit.regions.CylinderRegion; import com.sk89q.worldedit.regions.CylinderRegion;
import com.sk89q.worldedit.regions.Region; 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.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.TextComponent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockTypes; 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.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Locale;
import java.util.function.Supplier;
/** /**
* Utility commands. * Utility commands.
*/ */
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class UtilityCommands { public class UtilityCommands {
private final WorldEdit we; private final WorldEdit we;
@ -87,357 +83,365 @@ public class UtilityCommands {
} }
@Command( @Command(
aliases = { "/fill" }, name = "/fill",
usage = "<block> <radius> [depth]", desc = "Fill a hole"
desc = "Fill a hole",
min = 2,
max = 3
) )
@CommandPermissions("worldedit.fill") @CommandPermissions("worldedit.fill")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void fill(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { public int fill(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The blocks to fill with")
ParserContext context = new ParserContext(); Pattern pattern,
context.setActor(player); @Arg(desc = "The radius to fill in")
context.setWorld(player.getWorld()); double radius,
context.setSession(session); @Arg(desc = "The depth to fill", def = "1")
Pattern pattern = we.getPatternFactory().parseFromInput(args.getString(0), context); int depth) throws WorldEditException {
radius = Math.max(1, radius);
double radius = Math.max(1, args.getDouble(1));
we.checkMaxRadius(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); BlockVector3 pos = session.getPlacementPosition(player);
int affected = editSession.fillXZ(pos, pattern, radius, depth, false); int affected = editSession.fillXZ(pos, pattern, radius, depth, false);
player.print(affected + " block(s) have been created."); player.print(affected + " block(s) have been created.");
return affected;
} }
@Command( @Command(
aliases = { "/fillr" }, name = "/fillr",
usage = "<block> <radius> [depth]", desc = "Fill a hole recursively"
desc = "Fill a hole recursively",
min = 2,
max = 3
) )
@CommandPermissions("worldedit.fill.recursive") @CommandPermissions("worldedit.fill.recursive")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void fillr(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { public int fillr(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The blocks to fill with")
ParserContext context = new ParserContext(); Pattern pattern,
context.setActor(player); @Arg(desc = "The radius to fill in")
context.setWorld(player.getWorld()); double radius,
context.setSession(session); @Arg(desc = "The depth to fill", def = "")
Pattern pattern = we.getPatternFactory().parseFromInput(args.getString(0), context); Integer depth) throws WorldEditException {
radius = Math.max(1, radius);
double radius = Math.max(1, args.getDouble(1)); we.checkMaxRadius(radius);
depth = depth == null ? Integer.MAX_VALUE : Math.max(1, depth);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
int depth = args.argsLength() > 2 ? Math.max(1, args.getInteger(2)) : Integer.MAX_VALUE;
BlockVector3 pos = session.getPlacementPosition(player); BlockVector3 pos = session.getPlacementPosition(player);
int affected = 0; int affected = editSession.fillXZ(pos, pattern, radius, depth, true);
if (pattern instanceof BlockPattern) {
affected = editSession.fillXZ(pos, ((BlockPattern) pattern).getBlock(), radius, depth, true);
} else {
affected = editSession.fillXZ(pos, pattern, radius, depth, true);
}
player.print(affected + " block(s) have been created."); player.print(affected + " block(s) have been created.");
return affected;
} }
@Command( @Command(
aliases = { "/drain" }, name = "/drain",
usage = "<radius>", desc = "Drain a pool"
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
) )
@CommandPermissions("worldedit.drain") @CommandPermissions("worldedit.drain")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void drain(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { public int drain(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius to drain")
double radius = Math.max(0, args.getDouble(0)); double radius,
boolean waterlogged = args.hasFlag('w'); @Switch(name = 'w', desc = "Also un-waterlog blocks")
boolean waterlogged) throws WorldEditException {
radius = Math.max(0, radius);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
int affected = editSession.drainArea( int affected = editSession.drainArea(
session.getPlacementPosition(player), radius, waterlogged); session.getPlacementPosition(player), radius, waterlogged);
player.print(affected + " block(s) have been changed."); player.print(affected + " block(s) have been changed.");
return affected;
} }
@Command( @Command(
aliases = { "/fixlava", "fixlava" }, name = "fixlava",
usage = "<radius>", aliases = { "/fixlava" },
desc = "Fix lava to be stationary", desc = "Fix lava to be stationary"
min = 1,
max = 1
) )
@CommandPermissions("worldedit.fixlava") @CommandPermissions("worldedit.fixlava")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void fixLava(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { public int fixLava(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius to fix in")
double radius = Math.max(0, args.getDouble(0)); double radius) throws WorldEditException {
radius = Math.max(0, radius);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
int affected = editSession.fixLiquid(session.getPlacementPosition(player), radius, BlockTypes.LAVA); int affected = editSession.fixLiquid(session.getPlacementPosition(player), radius, BlockTypes.LAVA);
player.print(affected + " block(s) have been changed."); player.print(affected + " block(s) have been changed.");
return affected;
} }
@Command( @Command(
aliases = { "/fixwater", "fixwater" }, name = "fixwater",
usage = "<radius>", aliases = { "/fixwater" },
desc = "Fix water to be stationary", desc = "Fix water to be stationary"
min = 1,
max = 1
) )
@CommandPermissions("worldedit.fixwater") @CommandPermissions("worldedit.fixwater")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void fixWater(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { public int fixWater(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius to fix in")
double radius = Math.max(0, args.getDouble(0)); double radius) throws WorldEditException {
radius = Math.max(0, radius);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
int affected = editSession.fixLiquid(session.getPlacementPosition(player), radius, BlockTypes.WATER); int affected = editSession.fixLiquid(session.getPlacementPosition(player), radius, BlockTypes.WATER);
player.print(affected + " block(s) have been changed."); player.print(affected + " block(s) have been changed.");
return affected;
} }
@Command( @Command(
aliases = { "/removeabove", "removeabove" }, name = "removeabove",
usage = "[size] [height]", aliases = { "/removeabove" },
desc = "Remove blocks above your head.", desc = "Remove blocks above your head."
min = 0,
max = 2
) )
@CommandPermissions("worldedit.removeabove") @CommandPermissions("worldedit.removeabove")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void removeAbove(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { public int removeAbove(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The apothem of the square to remove from", def = "1")
int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 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); we.checkMaxRadius(size);
World world = player.getWorld(); 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( int affected = editSession.removeAbove(
session.getPlacementPosition(player), size, height); session.getPlacementPosition(player), size, height);
player.print(affected + " block(s) have been removed."); player.print(affected + " block(s) have been removed.");
return affected;
} }
@Command( @Command(
aliases = { "/removebelow", "removebelow" }, name = "removebelow",
usage = "[size] [height]", aliases = { "/removebelow" },
desc = "Remove blocks below you.", desc = "Remove blocks below you."
min = 0,
max = 2
) )
@CommandPermissions("worldedit.removebelow") @CommandPermissions("worldedit.removebelow")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void removeBelow(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { public int removeBelow(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The apothem of the square to remove from", def = "1")
int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 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); we.checkMaxRadius(size);
World world = player.getWorld(); 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); int affected = editSession.removeBelow(session.getPlacementPosition(player), size, height);
player.print(affected + " block(s) have been removed."); player.print(affected + " block(s) have been removed.");
return affected;
} }
@Command( @Command(
aliases = { "/removenear", "removenear" }, name = "removenear",
usage = "<block> [size]", aliases = { "/removenear" },
desc = "Remove blocks near you.", desc = "Remove blocks near you."
min = 1,
max = 2
) )
@CommandPermissions("worldedit.removenear") @CommandPermissions("worldedit.removenear")
@Logging(PLACEMENT) @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(); int affected = editSession.removeNear(session.getPlacementPosition(player), mask, radius);
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);
player.print(affected + " block(s) have been removed."); player.print(affected + " block(s) have been removed.");
return affected;
} }
@Command( @Command(
aliases = { "/replacenear", "replacenear" }, name = "replacenear",
usage = "<size> <from-id> <to-id>", aliases = { "/replacenear" },
desc = "Replace nearby blocks", desc = "Replace nearby blocks"
flags = "f",
min = 3,
max = 3
) )
@CommandPermissions("worldedit.replacenear") @CommandPermissions("worldedit.replacenear")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void replaceNear(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { public int replaceNear(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius of the square to remove in")
int size = Math.max(1, args.getInteger(0)); int radius,
we.checkMaxRadius(size); @Arg(desc = "The mask matching blocks to remove", def = "")
int affected; Mask from,
Set<BaseBlock> from; @Arg(desc = "The pattern of blocks to replace with")
Pattern to; Pattern to) throws WorldEditException {
radius = Math.max(1, radius);
ParserContext context = new ParserContext(); we.checkMaxRadius(radius);
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);
}
BlockVector3 base = session.getPlacementPosition(player); BlockVector3 base = session.getPlacementPosition(player);
BlockVector3 min = base.subtract(size, size, size); BlockVector3 min = base.subtract(radius, radius, radius);
BlockVector3 max = base.add(size, size, size); BlockVector3 max = base.add(radius, radius, radius);
Region region = new CuboidRegion(player.getWorld(), min, max); Region region = new CuboidRegion(player.getWorld(), min, max);
if (to instanceof BlockPattern) { if (from == null) {
affected = editSession.replaceBlocks(region, from, ((BlockPattern) to).getBlock()); from = new ExistingBlockMask(editSession);
} else {
affected = editSession.replaceBlocks(region, from, to);
} }
int affected = editSession.replaceBlocks(region, from, to);
player.print(affected + " block(s) have been replaced."); player.print(affected + " block(s) have been replaced.");
return affected;
} }
@Command( @Command(
aliases = { "/snow", "snow" }, name = "snow",
usage = "[radius]", aliases = { "/snow" },
desc = "Simulates snow", desc = "Simulates snow"
min = 0,
max = 1
) )
@CommandPermissions("worldedit.snow") @CommandPermissions("worldedit.snow")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void snow(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { public int snow(Player player, LocalSession session, EditSession editSession,
double size = args.argsLength() > 0 ? Math.max(1, args.getDouble(0)) : 10; @Arg(desc = "The radius of the circle to snow in", def = "10")
double size) throws WorldEditException {
size = Math.max(1, size);
we.checkMaxRadius(size); we.checkMaxRadius(size);
int affected = editSession.simulateSnow(session.getPlacementPosition(player), 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( @Command(
aliases = {"/thaw", "thaw"}, name = "thaw",
usage = "[radius]", aliases = { "/thaw" },
desc = "Thaws the area", desc = "Thaws the area"
min = 0,
max = 1
) )
@CommandPermissions("worldedit.thaw") @CommandPermissions("worldedit.thaw")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void thaw(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { public int thaw(Player player, LocalSession session, EditSession editSession,
double size = args.argsLength() > 0 ? Math.max(1, args.getDouble(0)) : 10; @Arg(desc = "The radius of the circle to thaw in", def = "10")
double size) throws WorldEditException {
size = Math.max(1, size);
we.checkMaxRadius(size); we.checkMaxRadius(size);
int affected = editSession.thaw(session.getPlacementPosition(player), size); int affected = editSession.thaw(session.getPlacementPosition(player), size);
player.print(affected + " surfaces thawed."); player.print(affected + " surface(s) thawed.");
return affected;
} }
@Command( @Command(
aliases = { "/green", "green" }, name = "green",
usage = "[radius]", aliases = { "/green" },
desc = "Greens the area", desc = "Converts dirt to grass blocks in the area"
help = "Converts dirt to grass blocks. -f also converts coarse dirt.",
flags = "f",
min = 0,
max = 1
) )
@CommandPermissions("worldedit.green") @CommandPermissions("worldedit.green")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void green(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { public int green(Player player, LocalSession session, EditSession editSession,
final double size = args.argsLength() > 0 ? Math.max(1, args.getDouble(0)) : 10; @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); we.checkMaxRadius(size);
final boolean onlyNormalDirt = !args.hasFlag('f'); final boolean onlyNormalDirt = !convertCoarse;
final int affected = editSession.green(session.getPlacementPosition(player), size, onlyNormalDirt); final int affected = editSession.green(session.getPlacementPosition(player), size, onlyNormalDirt);
player.print(affected + " surfaces greened."); player.print(affected + " surface(s) greened.");
return affected;
} }
@Command( @Command(
aliases = { "/ex", "/ext", "/extinguish", "ex", "ext", "extinguish" }, name = "extinguish",
usage = "[radius]", aliases = { "/ex", "/ext", "/extinguish", "ex", "ext" },
desc = "Extinguish nearby fire", desc = "Extinguish nearby fire"
min = 0, )
max = 1
)
@CommandPermissions("worldedit.extinguish") @CommandPermissions("worldedit.extinguish")
@Logging(PLACEMENT) @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(); LocalConfiguration config = we.getConfiguration();
int defaultRadius = config.maxRadius != -1 ? Math.min(40, config.maxRadius) : 40; int defaultRadius = config.maxRadius != -1 ? Math.min(40, config.maxRadius) : 40;
int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) int size = radius != null ? Math.max(1, radius) : defaultRadius;
: defaultRadius;
we.checkMaxRadius(size); 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."); player.print(affected + " block(s) have been removed.");
} }
@Command( @Command(
aliases = { "butcher" }, name = "butcher",
usage = "[radius]", desc = "Kill all or nearby mobs"
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
) )
@CommandPermissions("worldedit.butcher") @CommandPermissions("worldedit.butcher")
@Logging(PLACEMENT) @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(); LocalConfiguration config = we.getConfiguration();
Player player = actor instanceof Player ? (Player) actor : null; Player player = actor instanceof Player ? (Player) actor : null;
// technically the default can be larger than the max, but that's not my problem if (radius == null) {
int radius = config.butcherDefaultRadius; radius = config.butcherDefaultRadius;
} else if (radius < -1) {
// there might be a better way to do this but my brain is fried right now actor.printError("Use -1 to remove all mobs in loaded chunks");
if (args.argsLength() > 0) { // user inputted radius, override the default return 0;
radius = args.getInteger(0); } else if (radius == -1) {
if (radius < -1) { if (config.butcherMaxRadius != -1) {
actor.printError("Use -1 to remove all mobs in loaded chunks"); radius = config.butcherMaxRadius;
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 (config.butcherMaxRadius != -1) {
radius = Math.min(radius, config.butcherMaxRadius);
}
CreatureButcher flags = new CreatureButcher(actor); 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<EntityFunction> func) throws IncompleteRegionException, MaxChangedBlocksException {
List<EntityVisitor> visitors = new ArrayList<>(); List<EntityVisitor> visitors = new ArrayList<>();
LocalSession session = null; LocalSession session = null;
EditSession editSession = null; EditSession editSession = null;
@ -453,12 +457,12 @@ public class UtilityCommands {
} else { } else {
entities = editSession.getEntities(); entities = editSession.getEntities();
} }
visitors.add(new EntityVisitor(entities.iterator(), flags.createFunction())); visitors.add(new EntityVisitor(entities.iterator(), func.get()));
} else { } else {
Platform platform = we.getPlatformManager().queryCapability(Capability.WORLD_EDITING); Platform platform = we.getPlatformManager().queryCapability(Capability.WORLD_EDITING);
for (World world : platform.getWorlds()) { for (World world : platform.getWorlds()) {
List<? extends Entity> entities = world.getEntities(); 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(); killed += visitor.getAffected();
} }
actor.print("Killed " + killed + (killed != 1 ? " mobs" : " mob") + (radius < 0 ? "" : " in a radius of " + radius) + ".");
if (editSession != null) { if (editSession != null) {
session.remember(editSession); session.remember(editSession);
editSession.flushSession(); 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( @Command(
aliases = { "remove", "rem", "rement" }, name = "/calculate",
usage = "<type> <radius>", aliases = { "/calc", "/eval", "/evaluate", "/solve" },
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<EntityVisitor> 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 = "<expression>",
desc = "Evaluate a mathematical expression" desc = "Evaluate a mathematical expression"
) )
@CommandPermissions("worldedit.calc") @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<String> input) {
try { try {
Expression expression = Expression.compile(input); Expression expression = Expression.compile(String.join(" ", input));
if (actor instanceof SessionOwner) { double result = expression.evaluate(
actor.print("= " + expression.evaluate( new double[]{}, WorldEdit.getInstance().getSessionManager().get(actor).getTimeout());
new double[]{}, WorldEdit.getInstance().getSessionManager().get((SessionOwner) actor).getTimeout())); String formatted = formatter.format(result);
} else { actor.print(SubtleFormat.wrap(input + " = ")
actor.print("= " + expression.evaluate()); .append(TextComponent.of(formatted, TextColor.LIGHT_PURPLE)));
}
} catch (EvaluationException e) { } catch (EvaluationException e) {
actor.printError(String.format( 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) { } catch (ExpressionException e) {
actor.printError(String.format( 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( @Command(
aliases = { "/help" }, name = "/help",
usage = "[<command>]", desc = "Displays help for WorldEdit commands"
desc = "Displays help for WorldEdit commands",
min = 0,
max = -1
) )
@CommandPermissions("worldedit.help") @CommandPermissions("worldedit.help")
public void help(Actor actor, CommandContext args) throws WorldEditException { public void help(Actor actor,
help(args, we, actor); @Arg(desc = "The page to retrieve", def = "1")
} int page,
@Arg(desc = "The command to retrieve help for", def = "", variable = true)
private static CommandMapping detectCommand(Dispatcher dispatcher, String command, boolean isRootLevel) { List<String> command) throws WorldEditException {
CommandMapping mapping; PrintCommandHelp.help(command, page, we, actor);
// 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<String> 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<CommandMapping> 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<CommandMapping> list = aliases.subList(offset, Math.min(offset + perPage, aliases.size()));
tip.append("Type ");
tip.append(CodeFormat.wrap("//help "));
tip.append("<command> [<page>] 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());
}
} }
} }

View File

@ -20,12 +20,12 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import com.google.common.io.Files; 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.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; 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.entity.Player;
import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent; import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent;
import com.sk89q.worldedit.extension.platform.Actor; 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.ConfigReport;
import com.sk89q.worldedit.util.report.ReportList; import com.sk89q.worldedit.util.report.ReportList;
import com.sk89q.worldedit.util.report.SystemInfoReport; 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.File;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.text.DateFormat; import java.time.ZoneId;
import java.text.SimpleDateFormat; import java.time.ZonedDateTime;
import java.util.Calendar; import java.time.format.DateTimeFormatter;
import java.util.TimeZone; 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 { 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; private final WorldEdit we;
public WorldEditCommands(WorldEdit we) { public WorldEditCommands(WorldEdit we) {
this.we = we; this.we = we;
} }
@Command( @Command(
aliases = { "version", "ver" }, name = "version",
usage = "", aliases = { "ver" },
desc = "Get WorldEdit version", desc = "Get WorldEdit version"
min = 0,
max = 0
) )
public void version(Actor actor) throws WorldEditException { public void version(Actor actor) throws WorldEditException {
actor.print("WorldEdit version " + WorldEdit.getVersion()); actor.print("WorldEdit version " + WorldEdit.getVersion());
actor.print("https://github.com/sk89q/worldedit/"); actor.print("https://github.com/EngineHub/worldedit/");
PlatformManager pm = we.getPlatformManager(); PlatformManager pm = we.getPlatformManager();
@ -80,11 +86,8 @@ public class WorldEditCommands {
} }
@Command( @Command(
aliases = { "reload" }, name = "reload",
usage = "", desc = "Reload configuration"
desc = "Reload configuration",
min = 0,
max = 0
) )
@CommandPermissions("worldedit.reload") @CommandPermissions("worldedit.reload")
public void reload(Actor actor) throws WorldEditException { public void reload(Actor actor) throws WorldEditException {
@ -93,9 +96,14 @@ public class WorldEditCommands {
actor.print("Configuration reloaded!"); 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"}) @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"); ReportList report = new ReportList("Report");
report.add(new SystemInfoReport()); report.add(new SystemInfoReport());
report.add(new ConfigReport()); report.add(new ConfigReport());
@ -109,21 +117,18 @@ public class WorldEditCommands {
actor.printError("Failed to write report: " + e.getMessage()); actor.printError("Failed to write report: " + e.getMessage());
} }
if (args.hasFlag('p')) { if (pastebin) {
actor.checkPermission("worldedit.report.pastebin"); actor.checkPermission("worldedit.report.pastebin");
ActorCallbackPaste.pastebin( ActorCallbackPaste.pastebin(
we.getSupervisor(), actor, result, "WorldEdit report: %s.report", we.getSupervisor(), actor, result, "WorldEdit report: %s.report",
WorldEdit.getInstance().getPlatformManager().getCommandManager().getExceptionConverter() WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getExceptionConverter()
); );
} }
} }
@Command( @Command(
aliases = { "cui" }, name = "cui",
usage = "", desc = "Complete CUI handshake (internal usage)"
desc = "Complete CUI handshake (internal usage)",
min = 0,
max = 0
) )
public void cui(Player player, LocalSession session) throws WorldEditException { public void cui(Player player, LocalSession session) throws WorldEditException {
session.setCUISupport(true); session.setCUISupport(true);
@ -131,29 +136,34 @@ public class WorldEditCommands {
} }
@Command( @Command(
aliases = { "tz" }, name = "tz",
usage = "[timezone]", desc = "Set your timezone for snapshots"
desc = "Set your timezone for snapshots",
min = 1,
max = 1
) )
public void tz(Player player, LocalSession session, CommandContext args) throws WorldEditException { public void tz(Player player, LocalSession session,
TimeZone tz = TimeZone.getTimeZone(args.getString(0)); @Arg(desc = "The timezone to set")
session.setTimezone(tz); String timezone) throws WorldEditException {
player.print("Timezone set for this session to: " + tz.getDisplayName()); try {
player.print("The current time in that timezone is: " ZoneId tz = ZoneId.of(timezone);
+ dateFormat.format(Calendar.getInstance(tz).getTime())); 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( @Command(
aliases = { "help" }, name = "help",
usage = "[<command>]", desc = "Displays help for WorldEdit commands"
desc = "Displays help for WorldEdit commands",
min = 0,
max = -1
) )
@CommandPermissions("worldedit.help") @CommandPermissions("worldedit.help")
public void help(Actor actor, CommandContext args) throws WorldEditException { public void help(Actor actor,
UtilityCommands.help(args, we, actor); @Arg(desc = "The page to retrieve", def = "1")
int page,
@Arg(desc = "The command to retrieve help for", def = "", variable = true)
List<String> command) throws WorldEditException {
PrintCommandHelp.help(command, page, we, actor);
} }
} }

View File

@ -17,13 +17,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
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();
} }

View File

@ -17,29 +17,29 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
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; public class BooleanConverter {
import java.util.List;
public final class ArgumentUtils { public static void register(CommandManager commandManager) {
commandManager.registerConverter(Key.of(Boolean.class),
private ArgumentUtils() { MultiKeyConverter.builder(
ImmutableSetMultimap.<Boolean, String>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<String> getMatchingSuggestions(Collection<String> items, String s) { private BooleanConverter() {
if (s.isEmpty()) {
return Lists.newArrayList(items);
}
List<String> suggestions = Lists.newArrayList();
for (String item : items) {
if (item.toLowerCase().startsWith(s)) {
suggestions.add(item);
}
}
return suggestions;
} }
} }

View File

@ -1,63 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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<Boolean> {
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<String> 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;
}
}

View File

@ -0,0 +1,91 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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<T> implements ArgumentConverter<T> {
public static <T> CommaSeparatedValuesConverter<T> wrap(ArgumentConverter<T> delegate) {
return wrapAndLimit(delegate, -1);
}
public static <T> CommaSeparatedValuesConverter<T> wrapAndLimit(ArgumentConverter<T> delegate, int maximum) {
return new CommaSeparatedValuesConverter<>(delegate, maximum);
}
private static final Splitter COMMA = Splitter.on(',');
private final ArgumentConverter<T> delegate;
private final int maximum;
private CommaSeparatedValuesConverter(ArgumentConverter<T> 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<String> getSuggestions(String input) {
String lastInput = Iterables.getLast(COMMA.split(input), "");
return delegate.getSuggestions(lastInput);
}
@Override
public ConversionResult<T> convert(String argument, InjectedValueAccess context) {
ImmutableList.Builder<T> result = ImmutableList.builder();
for (String input : COMMA.split(argument)) {
ConversionResult<T> temp = delegate.convert(input, context);
if (!temp.isSuccessful()) {
return temp;
}
result.addAll(temp.get());
}
return SuccessfulConversion.from(result.build());
}
}

View File

@ -0,0 +1,119 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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<BlockVector3> {
@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<String> NON_DIAGONALS = ImmutableSet.of(
"north", "south", "east", "west", "up", "down"
);
private static final ImmutableSet<String> RELATIVE = ImmutableSet.of(
"me", "forward", "back", "left", "right"
);
private static final ImmutableSet<String> DIAGONALS = ImmutableSet.of(
"northeast", "northwest", "southeast", "southwest"
);
private final WorldEdit worldEdit;
private final boolean includeDiagonals;
private final ImmutableList<String> suggestions;
private DirectionConverter(WorldEdit worldEdit, boolean includeDiagonals) {
this.worldEdit = worldEdit;
this.includeDiagonals = includeDiagonals;
suggestions = ImmutableList.<String>builder()
.addAll(NON_DIAGONALS)
.addAll(RELATIVE)
.addAll(includeDiagonals ? DIAGONALS : ImmutableList.of())
.build();
}
@Override
public ConversionResult<BlockVector3> 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<String> getSuggestions(String input) {
return limitByPrefix(suggestions.stream(), input);
}
}

View File

@ -0,0 +1,87 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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);
}
}
}

View File

@ -0,0 +1,57 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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<EntityRemover> {
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<EntityRemover> convert(String argument, InjectedValueAccess context) {
try {
return SuccessfulConversion.fromSingle(EntityRemover.fromString(argument));
} catch (Exception e) {
return FailedConversion.from(e);
}
}
}

View File

@ -0,0 +1,71 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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 <E extends Enum<E>> ArgumentConverter<E> basic(Class<E> enumClass) {
return full(enumClass, e -> ImmutableSet.of(e.name()), null);
}
private static <E extends Enum<E>> ArgumentConverter<E> basic(Class<E> enumClass, E unknownValue) {
return full(enumClass, e -> ImmutableSet.of(e.name()), unknownValue);
}
private static <E extends Enum<E>> ArgumentConverter<E> full(Class<E> enumClass,
Function<E, Set<String>> lookupKeys,
@Nullable E unknownValue) {
return MultiKeyConverter.from(
EnumSet.allOf(enumClass),
lookupKeys,
unknownValue
);
}
private EnumConverter() {
}
}

View File

@ -17,27 +17,35 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.util.command.parametric; package com.sk89q.worldedit.command.argument;
/** import javax.annotation.Nullable;
* Thrown if there is an error with a parameter.
*/
public class ParameterException extends Exception {
public ParameterException() { import static com.google.common.base.Preconditions.checkNotNull;
super();
public final class ExpandAmount {
public static ExpandAmount vert() {
return new ExpandAmount(null);
} }
public ParameterException(String message) { public static ExpandAmount from(int amount) {
super(message); return new ExpandAmount(amount);
} }
public ParameterException(Throwable cause) { @Nullable
super(cause); private final Integer amount;
private ExpandAmount(@Nullable Integer amount) {
this.amount = amount;
} }
public ParameterException(String message, Throwable cause) { public boolean isVert() {
super(message, cause); return amount == null;
}
public int getAmount() {
return checkNotNull(amount, "This amount is vertical, i.e. undefined");
} }
} }

View File

@ -0,0 +1,70 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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<ExpandAmount> {
public static void register(CommandManager commandManager) {
commandManager.registerConverter(Key.of(ExpandAmount.class), new ExpandAmountConverter());
}
private final ArgumentConverter<Integer> integerConverter =
ArgumentConverters.get(TypeToken.of(int.class));
private ExpandAmountConverter() {
}
@Override
public Component describeAcceptableArguments() {
return TextComponent.of("`vert` or " + integerConverter.describeAcceptableArguments());
}
@Override
public List<String> getSuggestions(String input) {
return limitByPrefix(Stream.concat(
Stream.of("vert"), integerConverter.getSuggestions(input).stream()
), input);
}
@Override
public ConversionResult<ExpandAmount> 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);
}
}

View File

@ -0,0 +1,98 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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<T> implements ArgumentConverter<T> {
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<WorldEdit, AbstractFactory<T>> factoryExtractor;
private final String description;
private FactoryConverter(WorldEdit worldEdit,
Function<WorldEdit, AbstractFactory<T>> factoryExtractor,
String description) {
this.worldEdit = worldEdit;
this.factoryExtractor = factoryExtractor;
this.description = description;
}
@Override
public ConversionResult<T> 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);
}
}

View File

@ -1,82 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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<BaseItem> {
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;
}
}

View File

@ -1,90 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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<Contextual<RegionFunction>> {
private final ItemParser itemParser = addParameter(new ItemParser("item", "minecraft:bone_meal"));
@Override
public Contextual<RegionFunction> 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<RegionFunction> {
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);
}
}
}

View File

@ -1,83 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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<Number> {
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<String> 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;
}
}

View File

@ -1,78 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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<Pattern> {
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;
}
}

View File

@ -0,0 +1,49 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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.<RegionFactory, String>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() {
}
}

View File

@ -1,81 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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<RegionFactory> {
@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<String> 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;
}
}

View File

@ -0,0 +1,110 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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<V> implements ArgumentConverter<V> {
@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<Object>) c)
.forEach(registryType ->
commandManager.registerConverter(Key.of(registryType), from(registryType))
);
}
@SuppressWarnings("unchecked")
private static <V> RegistryConverter<V> from(Class<V> registryType) {
try {
Field registryField = registryType.getDeclaredField("REGISTRY");
Registry<V> registry = (Registry<V>) registryField.get(null);
return new RegistryConverter<>(registryType, registry);
} catch (NoSuchFieldException e) {
throw new IllegalArgumentException("Not a registry-backed type: " + registryType.getName());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Registry field inaccessible on " + registryType.getName());
}
}
private final Registry<V> registry;
private final TextComponent choices;
private RegistryConverter(Class<V> clazz, Registry<V> registry) {
this.registry = registry;
this.choices = TextComponent.of("any " + registry.getName());
}
@Override
public Component describeAcceptableArguments() {
return this.choices;
}
@Override
public ConversionResult<V> convert(String argument, InjectedValueAccess injectedValueAccess) {
V result = registry.get(argument);
return result == null
? FailedConversion.from(new IllegalArgumentException(
"Not a valid " + registry.getName() + ": " + argument))
: SuccessfulConversion.fromSingle(result);
}
@Override
public List<String> getSuggestions(String input) {
return limitByPrefix(registry.keySet().stream(), input);
}
}

View File

@ -1,76 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.extent.NullExtent;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.EditContext;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.block.BlockReplace;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.util.command.argument.CommandArgs;
import com.sk89q.worldedit.util.command.composition.SimpleCommand;
public class ReplaceParser extends SimpleCommand<Contextual<? extends RegionFunction>> {
private final PatternParser fillArg = addParameter(new PatternParser("fillPattern"));
@Override
public Contextual<RegionFunction> call(CommandArgs args, CommandLocals locals) throws CommandException {
Pattern fill = fillArg.call(args, locals);
return new ReplaceFactory(fill);
}
@Override
public String getDescription() {
return "Replaces blocks";
}
@Override
protected boolean testPermission0(CommandLocals locals) {
return true;
}
private static class ReplaceFactory implements Contextual<RegionFunction> {
private final Pattern fill;
private ReplaceFactory(Pattern fill) {
this.fill = fill;
}
@Override
public RegionFunction createFromContext(EditContext context) {
return new BlockReplace(
firstNonNull(context.getDestination(), new NullExtent()),
firstNonNull(context.getFill(), fill));
}
@Override
public String toString() {
return "replace blocks";
}
}
}

View File

@ -17,23 +17,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.util.command.argument; package com.sk89q.worldedit.command.argument;
public class ArgumentParseException extends ArgumentException {
public ArgumentParseException() {
}
public ArgumentParseException(String message) {
super(message);
}
public ArgumentParseException(String message, Throwable cause) {
super(message, cause);
}
public ArgumentParseException(Throwable cause) {
super(cause);
}
public enum SelectorChoice {
CUBOID,
EXTEND,
POLY,
ELLIPSOID,
SPHERE,
CYL,
CONVEX,
HULL,
POLYHEDRON,
UNKNOWN
} }

View File

@ -1,78 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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 StringParser implements CommandExecutor<String> {
private final String name;
private final String description;
private final String defaultSuggestion;
public StringParser(String name, String description) {
this(name, description, null);
}
public StringParser(String name, String description, String defaultSuggestion) {
this.name = name;
this.description = description;
this.defaultSuggestion = defaultSuggestion;
}
@Override
public String call(CommandArgs args, CommandLocals locals) throws CommandException {
try {
return args.next();
} catch (MissingArgumentException e) {
throw new CommandException("Missing value for <" + name + ">.");
}
}
@Override
public List<String> 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;
}
}

View File

@ -1,106 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.EditContext;
import com.sk89q.worldedit.function.generator.ForestGenerator;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.TreeGenerator.TreeType;
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.Arrays;
import java.util.List;
public class TreeGeneratorParser implements CommandExecutor<Contextual<ForestGenerator>> {
private final String name;
public TreeGeneratorParser(String name) {
this.name = name;
}
private String getOptionsList() {
return Joiner.on(" | ").join(Arrays.asList(TreeType.values()));
}
@Override
public Contextual<ForestGenerator> call(CommandArgs args, CommandLocals locals) throws CommandException {
try {
String input = args.next();
TreeType type = TreeGenerator.lookup(input);
if (type != null) {
return new GeneratorFactory(type);
} else {
throw new CommandException("Unknown value for <" + name + "> (try one of " + getOptionsList() + ").");
}
} catch (MissingArgumentException e) {
throw new CommandException("Missing value for <" + name + "> (try one of " + getOptionsList() + ").");
}
}
@Override
public List<String> getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException {
String s = args.next();
return s.isEmpty() ? Lists.newArrayList(TreeType.getPrimaryAliases()) : ArgumentUtils.getMatchingSuggestions(TreeType.getAliases(), s);
}
@Override
public String getUsage() {
return "<" + name + ">";
}
@Override
public String getDescription() {
return "Choose a tree generator";
}
@Override
public boolean testPermission(CommandLocals locals) {
return true;
}
private static final class GeneratorFactory implements Contextual<ForestGenerator> {
private final TreeType type;
private GeneratorFactory(TreeType type) {
this.type = type;
}
@Override
public ForestGenerator createFromContext(EditContext input) {
return new ForestGenerator((EditSession) input.getDestination(), type);
}
@Override
public String toString() {
return "tree of type " + type;
}
}
}

View File

@ -0,0 +1,110 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import com.google.common.collect.ImmutableList;
import com.google.common.reflect.TypeToken;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector2;
import com.sk89q.worldedit.math.Vector3;
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.FailedConversion;
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.function.Function;
public class VectorConverter<C, T> implements ArgumentConverter<T> {
public static void register(CommandManager commandManager) {
CommaSeparatedValuesConverter<Integer> intConverter = CommaSeparatedValuesConverter.wrap(ArgumentConverters.get(TypeToken.of(int.class)));
CommaSeparatedValuesConverter<Double> doubleConverter = CommaSeparatedValuesConverter.wrap(ArgumentConverters.get(TypeToken.of(double.class)));
commandManager.registerConverter(Key.of(BlockVector2.class),
new VectorConverter<>(
intConverter,
2,
cmps -> BlockVector2.at(cmps.get(0), cmps.get(1)),
"block vector with x and z"
));
commandManager.registerConverter(Key.of(Vector2.class),
new VectorConverter<>(
doubleConverter,
2,
cmps -> Vector2.at(cmps.get(0), cmps.get(1)),
"vector with x and z"
));
commandManager.registerConverter(Key.of(BlockVector3.class),
new VectorConverter<>(
intConverter,
3,
cmps -> BlockVector3.at(cmps.get(0), cmps.get(1), cmps.get(2)),
"block vector with x, y, and z"
));
commandManager.registerConverter(Key.of(Vector3.class),
new VectorConverter<>(
doubleConverter,
3,
cmps -> Vector3.at(cmps.get(0), cmps.get(1), cmps.get(2)),
"vector with x, y, and z"
));
}
private final ArgumentConverter<C> componentConverter;
private final int componentCount;
private final Function<List<C>, T> vectorConstructor;
private final String acceptableArguments;
private VectorConverter(ArgumentConverter<C> componentConverter,
int componentCount,
Function<List<C>, T> vectorConstructor,
String acceptableArguments) {
this.componentConverter = componentConverter;
this.componentCount = componentCount;
this.vectorConstructor = vectorConstructor;
this.acceptableArguments = acceptableArguments;
}
@Override
public Component describeAcceptableArguments() {
return TextComponent.of("any " + acceptableArguments);
}
@Override
public ConversionResult<T> convert(String argument, InjectedValueAccess context) {
ConversionResult<C> components = componentConverter.convert(argument, context);
if (!components.isSuccessful()) {
return components.failureAsAny();
}
if (components.get().size() != componentCount) {
return FailedConversion.from(new IllegalArgumentException(
"Must have exactly " + componentCount + " vector components"));
}
T vector = vectorConstructor.apply(ImmutableList.copyOf(components.get()));
return SuccessfulConversion.fromSingle(vector);
}
}

View File

@ -0,0 +1,61 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import com.sk89q.worldedit.LocalSession;
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.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Calendar;
public class ZonedDateTimeConverter implements ArgumentConverter<ZonedDateTime> {
public static void register(CommandManager commandManager) {
commandManager.registerConverter(Key.of(ZonedDateTime.class), new ZonedDateTimeConverter());
}
private ZonedDateTimeConverter() {
}
@Override
public Component describeAcceptableArguments() {
return TextComponent.of("any date");
}
@Override
public ConversionResult<ZonedDateTime> convert(String argument, InjectedValueAccess context) {
LocalSession session = context.injectedValue(Key.of(LocalSession.class))
.orElseThrow(() -> new IllegalStateException("Need a local session"));
Calendar date = session.detectDate(argument);
if (date == null) {
return FailedConversion.from(new IllegalArgumentException("Not a date: " + argument));
}
return SuccessfulConversion.fromSingle(date.toInstant().atZone(ZoneOffset.UTC));
}
}

View File

@ -0,0 +1,21 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
@org.enginehub.piston.util.NonnullByDefault
package com.sk89q.worldedit.command.argument;

View File

@ -1,68 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.composition;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.command.argument.RegionFunctionParser;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.factory.Apply;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.util.command.argument.CommandArgs;
import com.sk89q.worldedit.util.command.composition.CommandExecutor;
import com.sk89q.worldedit.util.command.composition.SimpleCommand;
public class ApplyCommand extends SimpleCommand<Contextual<? extends Operation>> {
private final CommandExecutor<Contextual<? extends RegionFunction>> functionParser;
private final String description;
public ApplyCommand() {
this(new RegionFunctionParser(), "Applies a function to every block");
}
public ApplyCommand(CommandExecutor<Contextual<? extends RegionFunction>> functionParser, String description) {
checkNotNull(functionParser, "functionParser");
checkNotNull(description, "description");
this.functionParser = functionParser;
this.description = description;
addParameter(functionParser);
}
@Override
public Apply call(CommandArgs args, CommandLocals locals) throws CommandException {
Contextual<? extends RegionFunction> function = functionParser.call(args, locals);
return new Apply(function);
}
@Override
public String getDescription() {
return description;
}
@Override
protected boolean testPermission0(CommandLocals locals) {
return true;
}
}

View File

@ -1,84 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.composition;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.minecraft.util.commands.WrappedCommandException;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.argument.BooleanFlag;
import com.sk89q.worldedit.command.argument.StringParser;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.factory.Deform;
import com.sk89q.worldedit.function.factory.Deform.Mode;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.util.command.argument.CommandArgs;
import com.sk89q.worldedit.util.command.composition.FlagParser.Flag;
import com.sk89q.worldedit.util.command.composition.FlagParser.FlagData;
import com.sk89q.worldedit.util.command.composition.SimpleCommand;
public class DeformCommand extends SimpleCommand<Contextual<? extends Operation>> {
private final Flag<Boolean> rawCoordsFlag = addFlag('r', new BooleanFlag("Raw coords mode"));
private final Flag<Boolean> offsetFlag = addFlag('o', new BooleanFlag("Offset mode"));
private final StringParser expressionParser = addParameter(new StringParser("expression", "Expression to apply", "y-=0.2"));
@Override
public Deform call(CommandArgs args, CommandLocals locals) throws CommandException {
FlagData flagData = getFlagParser().call(args, locals);
String expression = expressionParser.call(args, locals);
boolean rawCoords = rawCoordsFlag.get(flagData, false);
boolean offset = offsetFlag.get(flagData, false);
Deform deform = new Deform(expression);
if (rawCoords) {
deform.setMode(Mode.RAW_COORD);
} else if (offset) {
deform.setMode(Mode.OFFSET);
Player player = (Player) locals.get(Actor.class);
LocalSession session = WorldEdit.getInstance().getSessionManager().get(locals.get(Actor.class));
try {
deform.setOffset(session.getPlacementPosition(player).toVector3());
} catch (IncompleteRegionException e) {
throw new WrappedCommandException(e);
}
} else {
deform.setMode(Mode.UNIT_CUBE);
}
return deform;
}
@Override
public String getDescription() {
return "Apply math expression to area";
}
@Override
protected boolean testPermission0(CommandLocals locals) {
return true;
}
}

View File

@ -1,64 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.composition;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.command.argument.NumberParser;
import com.sk89q.worldedit.command.argument.RegionFunctionParser;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.factory.Paint;
import com.sk89q.worldedit.util.command.argument.CommandArgs;
import com.sk89q.worldedit.util.command.composition.CommandExecutor;
import com.sk89q.worldedit.util.command.composition.SimpleCommand;
public class PaintCommand extends SimpleCommand<Paint> {
private final NumberParser densityCommand = addParameter(new NumberParser("density", "0-100", "20"));
private final CommandExecutor<? extends Contextual<? extends RegionFunction>> functionParser;
public PaintCommand() {
this(new RegionFunctionParser());
}
public PaintCommand(CommandExecutor<? extends Contextual<? extends RegionFunction>> functionParser) {
this.functionParser = functionParser;
addParameter(functionParser);
}
@Override
public Paint call(CommandArgs args, CommandLocals locals) throws CommandException {
double density = densityCommand.call(args, locals).doubleValue() / 100.0;
Contextual<? extends RegionFunction> function = functionParser.call(args, locals);
return new Paint(function, density);
}
@Override
public String getDescription() {
return "Applies a function to surfaces";
}
@Override
protected boolean testPermission0(CommandLocals locals) {
return true;
}
}

View File

@ -1,115 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.composition;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.EditContext;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.command.argument.CommandArgs;
import com.sk89q.worldedit.util.command.composition.CommandExecutor;
import com.sk89q.worldedit.util.command.composition.SimpleCommand;
import java.util.List;
public class SelectionCommand extends SimpleCommand<Operation> {
private final CommandExecutor<Contextual<? extends Operation>> delegate;
private final String permission;
public SelectionCommand(CommandExecutor<Contextual<? extends Operation>> delegate, String permission) {
checkNotNull(delegate, "delegate");
checkNotNull(permission, "permission");
this.delegate = delegate;
this.permission = permission;
addParameter(delegate);
}
@Override
public Operation call(CommandArgs args, CommandLocals locals) throws CommandException {
if (!testPermission(locals)) {
throw new CommandPermissionsException();
}
Contextual<? extends Operation> operationFactory = delegate.call(args, locals);
Actor actor = locals.get(Actor.class);
if (actor instanceof Player) {
try {
Player player = (Player) actor;
LocalSession session = WorldEdit.getInstance().getSessionManager().get(player);
Region selection = session.getSelection(player.getWorld());
EditSession editSession = session.createEditSession(player);
editSession.enableStandardMode();
locals.put(EditSession.class, editSession);
session.tellVersion(player);
EditContext editContext = new EditContext();
editContext.setDestination(locals.get(EditSession.class));
editContext.setRegion(selection);
editContext.setSession(session);
Operation operation = operationFactory.createFromContext(editContext);
Operations.completeBlindly(operation);
List<String> messages = Lists.newArrayList();
operation.addStatusMessages(messages);
if (messages.isEmpty()) {
actor.print("Operation completed.");
} else {
actor.print("Operation completed (" + Joiner.on(", ").join(messages) + ").");
}
return operation;
} catch (IncompleteRegionException e) {
WorldEdit.getInstance().getPlatformManager().getCommandManager().getExceptionConverter().convert(e);
return null;
}
} else {
throw new CommandException("This command can only be used by players.");
}
}
@Override
public String getDescription() {
return delegate.getDescription();
}
@Override
protected boolean testPermission0(CommandLocals locals) {
return locals.get(Actor.class).hasPermission(permission);
}
}

View File

@ -1,103 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.composition;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.MaxBrushRadiusException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.argument.NumberParser;
import com.sk89q.worldedit.command.argument.RegionFactoryParser;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.InvalidToolBindException;
import com.sk89q.worldedit.command.tool.brush.OperationFactoryBrush;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.regions.factory.RegionFactory;
import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.command.argument.CommandArgs;
import com.sk89q.worldedit.util.command.composition.CommandExecutor;
import com.sk89q.worldedit.util.command.composition.SimpleCommand;
public class ShapedBrushCommand extends SimpleCommand<Object> {
private final CommandExecutor<? extends Contextual<? extends Operation>> delegate;
private final String permission;
private final RegionFactoryParser regionFactoryParser = addParameter(new RegionFactoryParser());
private final NumberParser radiusCommand = addParameter(new NumberParser("size", "The size of the brush", "5"));
public ShapedBrushCommand(CommandExecutor<? extends Contextual<? extends Operation>> delegate, String permission) {
checkNotNull(delegate, "delegate");
this.permission = permission;
this.delegate = delegate;
addParameter(delegate);
}
@Override
public Object call(CommandArgs args, CommandLocals locals) throws CommandException {
if (!testPermission(locals)) {
throw new CommandPermissionsException();
}
RegionFactory regionFactory = regionFactoryParser.call(args, locals);
int radius = radiusCommand.call(args, locals).intValue();
Contextual<? extends Operation> factory = delegate.call(args, locals);
Player player = (Player) locals.get(Actor.class);
LocalSession session = WorldEdit.getInstance().getSessionManager().get(player);
try {
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, regionFactory, session), permission);
} catch (MaxBrushRadiusException | InvalidToolBindException e) {
WorldEdit.getInstance().getPlatformManager().getCommandManager().getExceptionConverter().convert(e);
}
player.print("Set brush to " + factory);
return true;
}
@Override
public String getDescription() {
return delegate.getDescription();
}
@Override
public boolean testPermission0(CommandLocals locals) {
Actor sender = locals.get(Actor.class);
if (sender == null) {
throw new RuntimeException("Uh oh! No 'Actor' specified so that we can check permissions");
} else {
return sender.hasPermission(permission);
}
}
}

View File

@ -0,0 +1,47 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.factory;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.function.ItemUseFunction;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.EditContext;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.world.World;
public final class ItemUseFactory implements Contextual<RegionFunction> {
private final BaseItem item;
public 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();
}
}

View File

@ -0,0 +1,49 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.factory;
import com.sk89q.worldedit.extent.NullExtent;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.EditContext;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.block.BlockReplace;
import com.sk89q.worldedit.function.pattern.Pattern;
import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull;
public class ReplaceFactory implements Contextual<RegionFunction> {
private final Pattern fill;
public ReplaceFactory(Pattern fill) {
this.fill = fill;
}
@Override
public RegionFunction createFromContext(EditContext context) {
return new BlockReplace(
firstNonNull(context.getDestination(), new NullExtent()),
firstNonNull(context.getFill(), fill));
}
@Override
public String toString() {
return "replace blocks";
}
}

View File

@ -17,22 +17,28 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.util.command; package com.sk89q.worldedit.command.factory;
import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.worldedit.EditSession;
import com.sk89q.minecraft.util.commands.CommandLocals; import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.EditContext;
import com.sk89q.worldedit.function.generator.ForestGenerator;
import com.sk89q.worldedit.util.TreeGenerator;
import java.util.Collections; public final class TreeGeneratorFactory implements Contextual<ForestGenerator> {
import java.util.List; private final TreeGenerator.TreeType type;
/** public TreeGeneratorFactory(TreeGenerator.TreeType type) {
* Always returns an empty list of suggestions. this.type = type;
*/
public class NullCompleter implements CommandCompleter {
@Override
public List<String> getSuggestions(String arguments, CommandLocals locals) throws CommandException {
return Collections.emptyList();
} }
@Override
public ForestGenerator createFromContext(EditContext input) {
return new ForestGenerator((EditSession) input.getDestination(), type);
}
@Override
public String toString() {
return "tree of type " + type;
}
} }

View File

@ -24,12 +24,13 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; import com.sk89q.worldedit.internal.command.exception.ExceptionConverter;
import com.sk89q.worldedit.util.task.FutureForwardingTask; import com.sk89q.worldedit.util.task.FutureForwardingTask;
import com.sk89q.worldedit.util.task.Supervisor; import com.sk89q.worldedit.util.task.Supervisor;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.concurrent.ForkJoinPool;
public class AsyncCommandHelper { public class AsyncCommandHelper {
@ -85,7 +86,8 @@ public class AsyncCommandHelper {
.exceptionConverter(exceptionConverter) .exceptionConverter(exceptionConverter)
.onSuccess(format(success)) .onSuccess(format(success))
.onFailure(format(failure)) .onFailure(format(failure))
.build()); .build(),
ForkJoinPool.commonPool());
return this; return this;
} }
@ -96,7 +98,8 @@ public class AsyncCommandHelper {
new MessageFutureCallback.Builder(sender) new MessageFutureCallback.Builder(sender)
.exceptionConverter(exceptionConverter) .exceptionConverter(exceptionConverter)
.onFailure(format(failure)) .onFailure(format(failure))
.build()); .build(),
ForkJoinPool.commonPool());
return this; return this;
} }

View File

@ -17,28 +17,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.util.command.binding; package com.sk89q.worldedit.command.util;
import org.enginehub.piston.annotation.CommandCondition;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Indicates a command flag, such as {@code /command -f}.
*
* <p>If used on a boolean type, then the flag will be a non-value flag. If
* used on any other type, then the flag will be a value flag.</p>
*/
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER) @CommandCondition(CommandPermissionsConditionGenerator.class)
public @interface Switch { public @interface CommandPermissions {
/** /**
* The flag character. * A list of permissions. Only one permission has to be met
* * for the command to be permitted.
* @return the flag character (A-Z a-z 0-9 is acceptable) *
* @return a list of permissions strings
*/ */
char value(); String[] value();
} }

View File

@ -0,0 +1,47 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.util;
import com.google.common.collect.ImmutableSet;
import org.enginehub.piston.Command;
import org.enginehub.piston.gen.CommandConditionGenerator;
import org.enginehub.piston.gen.CommandRegistration;
import org.enginehub.piston.util.NonnullByDefault;
import java.lang.reflect.Method;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
@NonnullByDefault
public final class CommandPermissionsConditionGenerator implements CommandConditionGenerator {
public interface Registration {
Registration commandPermissionsConditionGenerator(CommandPermissionsConditionGenerator generator);
}
@Override
public Command.Condition generateCondition(Method commandMethod) {
CommandPermissions annotation = commandMethod.getAnnotation(CommandPermissions.class);
checkNotNull(annotation, "Annotation is missing from commandMethod");
Set<String> permissions = ImmutableSet.copyOf(annotation.value());
return new PermissionCondition(permissions);
}
}

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.command.util; package com.sk89q.worldedit.command.util;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.worldedit.entity.metadata.EntityProperties; import com.sk89q.worldedit.entity.metadata.EntityProperties;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.function.EntityFunction; import com.sk89q.worldedit.function.EntityFunction;
@ -29,7 +28,7 @@ import com.sk89q.worldedit.function.EntityFunction;
*/ */
public class CreatureButcher { public class CreatureButcher {
final class Flags { public final class Flags {
@SuppressWarnings("PointlessBitwiseExpression") @SuppressWarnings("PointlessBitwiseExpression")
public static final int PETS = 1 << 0; public static final int PETS = 1 << 0;
public static final int NPCS = 1 << 1; public static final int NPCS = 1 << 1;
@ -39,7 +38,6 @@ public class CreatureButcher {
public static final int TAGGED = 1 << 5; public static final int TAGGED = 1 << 5;
public static final int FRIENDLY = PETS | NPCS | ANIMALS | GOLEMS | AMBIENT | TAGGED; public static final int FRIENDLY = PETS | NPCS | ANIMALS | GOLEMS | AMBIENT | TAGGED;
public static final int ARMOR_STAND = 1 << 6; public static final int ARMOR_STAND = 1 << 6;
public static final int WITH_LIGHTNING = 1 << 20;
private Flags() { private Flags() {
} }
@ -64,19 +62,6 @@ public class CreatureButcher {
} }
} }
public void fromCommand(CommandContext args) {
or(Flags.FRIENDLY , args.hasFlag('f')); // No permission check here. Flags will instead be filtered by the subsequent calls.
or(Flags.PETS , args.hasFlag('p'), "worldedit.butcher.pets");
or(Flags.NPCS , args.hasFlag('n'), "worldedit.butcher.npcs");
or(Flags.GOLEMS , args.hasFlag('g'), "worldedit.butcher.golems");
or(Flags.ANIMALS , args.hasFlag('a'), "worldedit.butcher.animals");
or(Flags.AMBIENT , args.hasFlag('b'), "worldedit.butcher.ambient");
or(Flags.TAGGED , args.hasFlag('t'), "worldedit.butcher.tagged");
or(Flags.ARMOR_STAND , args.hasFlag('r'), "worldedit.butcher.armorstands");
or(Flags.WITH_LIGHTNING, args.hasFlag('l'), "worldedit.butcher.lightning");
}
public EntityFunction createFunction() { public EntityFunction createFunction() {
return entity -> { return entity -> {
boolean killPets = (flags & Flags.PETS) != 0; boolean killPets = (flags & Flags.PETS) != 0;

View File

@ -19,15 +19,13 @@
package com.sk89q.worldedit.command.util; package com.sk89q.worldedit.command.util;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.worldedit.entity.metadata.EntityProperties; import com.sk89q.worldedit.entity.metadata.EntityProperties;
import com.sk89q.worldedit.function.EntityFunction; import com.sk89q.worldedit.function.EntityFunction;
import javax.annotation.Nullable;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* The implementation of /remove. * The implementation of /remove.
@ -125,17 +123,21 @@ public class EntityRemover {
} }
} }
private Type type; public static EntityRemover fromString(String str) {
public void fromString(String str) throws CommandException {
Type type = Type.findByPattern(str); Type type = Type.findByPattern(str);
if (type != null) { if (type != null) {
this.type = type; return new EntityRemover(type);
} else { } else {
throw new CommandException("Acceptable types: projectiles, items, paintings, itemframes, boats, minecarts, tnt, xp, or all"); throw new IllegalArgumentException("Acceptable types: projectiles, items, paintings, itemframes, boats, minecarts, tnt, xp, or all");
} }
} }
private final Type type;
private EntityRemover(Type type) {
this.type = type;
}
public EntityFunction createFunction() { public EntityFunction createFunction() {
final Type type = this.type; final Type type = this.type;
checkNotNull(type, "type can't be null"); checkNotNull(type, "type can't be null");

View File

@ -20,7 +20,7 @@
//$Id$ //$Id$
package com.sk89q.minecraft.util.commands; package com.sk89q.worldedit.command.util;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;

View File

@ -22,9 +22,9 @@ package com.sk89q.worldedit.command.util;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; import com.sk89q.worldedit.internal.command.exception.ExceptionConverter;
import org.enginehub.piston.exception.CommandException;
import javax.annotation.Nullable; import javax.annotation.Nullable;

View File

@ -0,0 +1,49 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.util;
import com.sk89q.worldedit.extension.platform.Actor;
import org.enginehub.piston.Command;
import org.enginehub.piston.CommandParameters;
import org.enginehub.piston.inject.Key;
import java.util.Set;
public final class PermissionCondition implements Command.Condition {
private static final Key<Actor> ACTOR_KEY = Key.of(Actor.class);
private final Set<String> permissions;
public PermissionCondition(Set<String> permissions) {
this.permissions = permissions;
}
public Set<String> getPermissions() {
return permissions;
}
@Override
public boolean satisfied(CommandParameters parameters) {
return parameters.injectedValue(ACTOR_KEY)
.map(actor -> permissions.stream().anyMatch(actor::hasPermission))
.orElse(false);
}
}

View File

@ -0,0 +1,155 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.util;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.formatting.component.CommandListBox;
import com.sk89q.worldedit.util.formatting.component.CommandUsageBox;
import com.sk89q.worldedit.util.formatting.component.InvalidComponentException;
import org.enginehub.piston.Command;
import org.enginehub.piston.CommandManager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.sk89q.worldedit.internal.command.CommandUtil.byCleanName;
import static com.sk89q.worldedit.internal.command.CommandUtil.getSubCommands;
import static java.util.stream.Collectors.toList;
/**
* Implementation of the //help command.
*/
// Stored in a separate class to prevent import conflicts, and because it's aliased via /we help.
public class PrintCommandHelp {
private static Command detectCommand(CommandManager manager, String command) {
Optional<Command> mapping;
// First try the command as entered
mapping = manager.getCommand(command);
if (mapping.isPresent()) {
return mapping.get();
}
// If tried with slashes, try dropping a slash
if (command.startsWith("/")) {
mapping = manager.getCommand(command.substring(1));
return mapping.orElse(null);
}
// Otherwise, check /command, since that's common
mapping = manager.getCommand("/" + command);
return mapping.orElse(null);
}
public static void help(List<String> commandPath, int page, WorldEdit we, Actor actor) throws InvalidComponentException {
CommandManager manager = we.getPlatformManager().getPlatformCommandManager().getCommandManager();
if (commandPath.isEmpty()) {
printCommands(page, manager.getAllCommands(), actor, ImmutableList.of());
return;
}
List<Command> visited = new ArrayList<>();
Command currentCommand = detectCommand(manager, commandPath.get(0));
if (currentCommand == null) {
actor.printError(String.format("The command '%s' could not be found.", commandPath.get(0)));
return;
}
visited.add(currentCommand);
// Drill down to the command
for (int i = 1; i < commandPath.size(); i++) {
String subCommand = commandPath.get(i);
Map<String, Command> subCommands = getSubCommands(currentCommand);
if (subCommands.isEmpty()) {
actor.printError(String.format("'%s' has no sub-commands. (Maybe '%s' is for a parameter?)",
Joiner.on(" ").join(visited.stream().map(Command::getName).iterator()), subCommand));
// full help for single command
CommandUsageBox box = new CommandUsageBox(visited, visited.stream()
.map(Command::getName).collect(Collectors.joining(" ")));
actor.print(box.create());
return;
}
if (subCommands.containsKey(subCommand)) {
currentCommand = subCommands.get(subCommand);
visited.add(currentCommand);
} else {
actor.printError(String.format("The sub-command '%s' under '%s' could not be found.",
subCommand, Joiner.on(" ").join(visited.stream().map(Command::getName).iterator())));
// list subcommands for currentCommand
CommandUsageBox box = new CommandUsageBox(visited, visited.stream()
.map(Command::getName).collect(Collectors.joining(" ")));
actor.print(box.create());
return;
}
}
Map<String, Command> subCommands = getSubCommands(currentCommand);
if (subCommands.isEmpty()) {
// Create the message
CommandUsageBox box = new CommandUsageBox(visited, visited.stream()
.map(Command::getName).collect(Collectors.joining(" ")));
actor.print(box.create());
} else {
printCommands(page, subCommands.values().stream(), actor, visited);
}
}
private static void printCommands(int page, Stream<Command> commandStream, Actor actor,
List<Command> commandList) throws InvalidComponentException {
// Get a list of aliases
List<Command> commands = commandStream
.sorted(byCleanName())
.collect(toList());
String used = commandList.isEmpty() ? null
: Joiner.on(" ").join(commandList.stream().map(Command::getName).iterator());
CommandListBox box = new CommandListBox(
(used == null ? "Help" : "Subcommands: " + used),
"//help %page%" + (used == null ? "" : " " + used));
if (!actor.isPlayer()) {
box.formatForConsole();
}
for (Command mapping : commands) {
String alias = (commandList.isEmpty() ? "/" : "") + mapping.getName();
String command = Stream.concat(commandList.stream(), Stream.of(mapping))
.map(Command::getName)
.collect(Collectors.joining(" ", "/", ""));
box.appendCommand(alias, mapping.getDescription(), command);
}
actor.print(box.create(page));
}
private PrintCommandHelp() {
}
}

View File

@ -23,7 +23,7 @@ import com.sk89q.worldedit.internal.cui.CUIEvent;
import com.sk89q.worldedit.session.SessionOwner; import com.sk89q.worldedit.session.SessionOwner;
import com.sk89q.worldedit.util.Identifiable; import com.sk89q.worldedit.util.Identifiable;
import com.sk89q.worldedit.util.auth.Subject; import com.sk89q.worldedit.util.auth.Subject;
import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.Component;
import java.io.File; import java.io.File;
@ -77,11 +77,11 @@ public interface Actor extends Identifiable, SessionOwner, Subject {
void printError(String msg); void printError(String msg);
/** /**
* Print a {@link TextComponent}. * Print a {@link Component}.
* *
* @param component The component to print * @param component The component to print
*/ */
void print(TextComponent component); void print(Component component);
/** /**
* Returns true if the actor can destroy bedrock. * Returns true if the actor can destroy bedrock.

View File

@ -17,20 +17,22 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.util.command.parametric; package com.sk89q.worldedit.extension.platform;
import com.sk89q.worldedit.util.command.SimpleDescription; import com.google.auto.value.AutoAnnotation;
import com.sk89q.worldedit.internal.annotation.Radii;
import java.lang.reflect.Method;
/** /**
* An abstract listener. * Holder for generated annotation classes.
*/ */
public abstract class AbstractInvokeListener implements InvokeListener { class Annotations {
@Override @AutoAnnotation
public void updateDescription(Object object, Method method, static Radii radii(int value) {
ParameterData[] parameters, SimpleDescription description) { return new AutoAnnotation_Annotations_radii(value);
}
private Annotations() {
} }
} }

View File

@ -50,12 +50,12 @@ public enum Capability {
USER_COMMANDS { USER_COMMANDS {
@Override @Override
void initialize(PlatformManager platformManager, Platform platform) { void initialize(PlatformManager platformManager, Platform platform) {
platformManager.getCommandManager().register(platform); platformManager.getPlatformCommandManager().registerCommandsWith(platform);
} }
@Override @Override
void unload(PlatformManager platformManager, Platform platform) { void unload(PlatformManager platformManager, Platform platform) {
platformManager.getCommandManager().unregister(); platformManager.getPlatformCommandManager().removeCommands();
} }
}, },

View File

@ -1,378 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extension.platform;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.util.command.composition.LegacyCommandAdapter.adapt;
import com.google.common.base.Joiner;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
import com.sk89q.minecraft.util.commands.WrappedCommandException;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.BiomeCommands;
import com.sk89q.worldedit.command.BrushCommands;
import com.sk89q.worldedit.command.ChunkCommands;
import com.sk89q.worldedit.command.ClipboardCommands;
import com.sk89q.worldedit.command.GeneralCommands;
import com.sk89q.worldedit.command.GenerationCommands;
import com.sk89q.worldedit.command.HistoryCommands;
import com.sk89q.worldedit.command.NavigationCommands;
import com.sk89q.worldedit.command.RegionCommands;
import com.sk89q.worldedit.command.SchematicCommands;
import com.sk89q.worldedit.command.ScriptingCommands;
import com.sk89q.worldedit.command.SelectionCommands;
import com.sk89q.worldedit.command.SnapshotCommands;
import com.sk89q.worldedit.command.SnapshotUtilCommands;
import com.sk89q.worldedit.command.SuperPickaxeCommands;
import com.sk89q.worldedit.command.ToolCommands;
import com.sk89q.worldedit.command.ToolUtilCommands;
import com.sk89q.worldedit.command.UtilityCommands;
import com.sk89q.worldedit.command.WorldEditCommands;
import com.sk89q.worldedit.command.argument.ReplaceParser;
import com.sk89q.worldedit.command.argument.TreeGeneratorParser;
import com.sk89q.worldedit.command.composition.ApplyCommand;
import com.sk89q.worldedit.command.composition.DeformCommand;
import com.sk89q.worldedit.command.composition.PaintCommand;
import com.sk89q.worldedit.command.composition.SelectionCommand;
import com.sk89q.worldedit.command.composition.ShapedBrushCommand;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.factory.Deform;
import com.sk89q.worldedit.function.factory.Deform.Mode;
import com.sk89q.worldedit.internal.command.ActorAuthorizer;
import com.sk89q.worldedit.internal.command.CommandLoggingHandler;
import com.sk89q.worldedit.internal.command.UserCommandCompleter;
import com.sk89q.worldedit.internal.command.WorldEditBinding;
import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.command.Dispatcher;
import com.sk89q.worldedit.util.command.InvalidUsageException;
import com.sk89q.worldedit.util.command.composition.ProvidedValue;
import com.sk89q.worldedit.util.command.fluent.CommandGraph;
import com.sk89q.worldedit.util.command.parametric.ExceptionConverter;
import com.sk89q.worldedit.util.command.parametric.LegacyCommandsHandler;
import com.sk89q.worldedit.util.command.parametric.ParametricBuilder;
import com.sk89q.worldedit.util.eventbus.Subscribe;
import com.sk89q.worldedit.util.formatting.component.CommandUsageBox;
import com.sk89q.worldedit.util.logging.DynamicStreamHandler;
import com.sk89q.worldedit.util.logging.LogFormat;
import com.sk89q.worldedit.world.World;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.regex.Pattern;
/**
* Handles the registration and invocation of commands.
*
* <p>This class is primarily for internal usage.</p>
*/
public final class CommandManager {
public static final Pattern COMMAND_CLEAN_PATTERN = Pattern.compile("^[/]+");
private static final Logger log = LoggerFactory.getLogger(CommandManager.class);
private static final java.util.logging.Logger commandLog =
java.util.logging.Logger.getLogger(CommandManager.class.getCanonicalName() + ".CommandLog");
private static final Pattern numberFormatExceptionPattern = Pattern.compile("^For input string: \"(.*)\"$");
private final WorldEdit worldEdit;
private final PlatformManager platformManager;
private final Dispatcher dispatcher;
private final DynamicStreamHandler dynamicHandler = new DynamicStreamHandler();
private final ExceptionConverter exceptionConverter;
/**
* Create a new instance.
*
* @param worldEdit the WorldEdit instance
*/
CommandManager(final WorldEdit worldEdit, PlatformManager platformManager) {
checkNotNull(worldEdit);
checkNotNull(platformManager);
this.worldEdit = worldEdit;
this.platformManager = platformManager;
this.exceptionConverter = new WorldEditExceptionConverter(worldEdit);
// Register this instance for command events
worldEdit.getEventBus().register(this);
// Setup the logger
commandLog.addHandler(dynamicHandler);
// Set up the commands manager
ParametricBuilder builder = new ParametricBuilder();
builder.setAuthorizer(new ActorAuthorizer());
builder.setDefaultCompleter(new UserCommandCompleter(platformManager));
builder.addBinding(new WorldEditBinding(worldEdit));
builder.addInvokeListener(new LegacyCommandsHandler());
builder.addInvokeListener(new CommandLoggingHandler(worldEdit, commandLog));
dispatcher = new CommandGraph()
.builder(builder)
.commands()
.registerMethods(new BiomeCommands(worldEdit))
.registerMethods(new ChunkCommands(worldEdit))
.registerMethods(new ClipboardCommands(worldEdit))
.registerMethods(new GeneralCommands(worldEdit))
.registerMethods(new GenerationCommands(worldEdit))
.registerMethods(new HistoryCommands(worldEdit))
.registerMethods(new NavigationCommands(worldEdit))
.registerMethods(new RegionCommands(worldEdit))
.registerMethods(new ScriptingCommands(worldEdit))
.registerMethods(new SelectionCommands(worldEdit))
.registerMethods(new SnapshotUtilCommands(worldEdit))
.registerMethods(new ToolUtilCommands(worldEdit))
.registerMethods(new ToolCommands(worldEdit))
.registerMethods(new UtilityCommands(worldEdit))
.register(adapt(new SelectionCommand(new ApplyCommand(new ReplaceParser(), "Set all blocks within selection"), "worldedit.region.set")), "/set")
.group("worldedit", "we")
.describeAs("WorldEdit commands")
.registerMethods(new WorldEditCommands(worldEdit))
.parent()
.group("schematic", "schem", "/schematic", "/schem")
.describeAs("Schematic commands for saving/loading areas")
.registerMethods(new SchematicCommands(worldEdit))
.parent()
.group("snapshot", "snap")
.describeAs("Schematic commands for saving/loading areas")
.registerMethods(new SnapshotCommands(worldEdit))
.parent()
.group("brush", "br")
.describeAs("Brushing commands")
.registerMethods(new BrushCommands(worldEdit))
.register(adapt(new ShapedBrushCommand(new DeformCommand(), "worldedit.brush.deform")), "deform")
.register(adapt(new ShapedBrushCommand(new ApplyCommand(new ReplaceParser(), "Set all blocks within region"), "worldedit.brush.set")), "set")
.register(adapt(new ShapedBrushCommand(new PaintCommand(), "worldedit.brush.paint")), "paint")
.register(adapt(new ShapedBrushCommand(new ApplyCommand(), "worldedit.brush.apply")), "apply")
.register(adapt(new ShapedBrushCommand(new PaintCommand(new TreeGeneratorParser("treeType")), "worldedit.brush.forest")), "forest")
.register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y-=1", Mode.RAW_COORD), "Raise one block"), "worldedit.brush.raise")), "raise")
.register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y+=1", Mode.RAW_COORD), "Lower one block"), "worldedit.brush.lower")), "lower")
.parent()
.group("superpickaxe", "pickaxe", "sp")
.describeAs("Super-pickaxe commands")
.registerMethods(new SuperPickaxeCommands(worldEdit))
.parent()
.group("tool")
.describeAs("Bind functions to held items")
.registerMethods(new ToolCommands(worldEdit))
.parent()
.graph()
.getDispatcher();
}
public ExceptionConverter getExceptionConverter() {
return exceptionConverter;
}
void register(Platform platform) {
log.info("Registering commands with " + platform.getClass().getCanonicalName());
LocalConfiguration config = platform.getConfiguration();
boolean logging = config.logCommands;
String path = config.logFile;
// Register log
if (!logging || path.isEmpty()) {
dynamicHandler.setHandler(null);
commandLog.setLevel(Level.OFF);
} else {
File file = new File(config.getWorkingDirectory(), path);
commandLog.setLevel(Level.ALL);
log.info("Logging WorldEdit commands to " + file.getAbsolutePath());
try {
dynamicHandler.setHandler(new FileHandler(file.getAbsolutePath(), true));
} catch (IOException e) {
log.warn("Could not use command log file " + path + ": " + e.getMessage());
}
dynamicHandler.setFormatter(new LogFormat(config.logFormat));
}
platform.registerCommands(dispatcher);
}
void unregister() {
dynamicHandler.setHandler(null);
}
public String[] commandDetection(String[] split) {
// Quick script shortcut
if (split[0].matches("^[^/].*\\.js$")) {
String[] newSplit = new String[split.length + 1];
System.arraycopy(split, 0, newSplit, 1, split.length);
newSplit[0] = "cs";
newSplit[1] = newSplit[1];
split = newSplit;
}
String searchCmd = split[0].toLowerCase();
// Try to detect the command
if (!dispatcher.contains(searchCmd)) {
if (worldEdit.getConfiguration().noDoubleSlash && dispatcher.contains("/" + searchCmd)) {
split[0] = "/" + split[0];
} else if (searchCmd.length() >= 2 && searchCmd.charAt(0) == '/' && dispatcher.contains(searchCmd.substring(1))) {
split[0] = split[0].substring(1);
}
}
return split;
}
@Subscribe
public void handleCommand(CommandEvent event) {
Request.reset();
Actor actor = platformManager.createProxyActor(event.getActor());
String[] split = commandDetection(event.getArguments().split(" "));
// No command found!
if (!dispatcher.contains(split[0])) {
return;
}
LocalSession session = worldEdit.getSessionManager().get(actor);
Request.request().setSession(session);
if (actor instanceof Entity) {
Extent extent = ((Entity) actor).getExtent();
if (extent instanceof World) {
Request.request().setWorld(((World) extent));
}
}
LocalConfiguration config = worldEdit.getConfiguration();
CommandLocals locals = new CommandLocals();
locals.put(Actor.class, actor);
locals.put("arguments", event.getArguments());
long start = System.currentTimeMillis();
try {
// This is a bit of a hack, since the call method can only throw CommandExceptions
// everything needs to be wrapped at least once. Which means to handle all WorldEdit
// exceptions without writing a hook into every dispatcher, we need to unwrap these
// exceptions and rethrow their converted form, if their is one.
try {
dispatcher.call(Joiner.on(" ").join(split), locals, new String[0]);
} catch (Throwable t) {
// Use the exception converter to convert the exception if any of its causes
// can be converted, otherwise throw the original exception
Throwable next = t;
do {
exceptionConverter.convert(next);
next = next.getCause();
} while (next != null);
throw t;
}
} catch (CommandPermissionsException e) {
actor.printError("You are not permitted to do that. Are you in the right mode?");
} catch (InvalidUsageException e) {
if (e.isFullHelpSuggested()) {
actor.print(new CommandUsageBox(e.getCommand(), e.getCommandUsed("/", ""), locals).create());
String message = e.getMessage();
if (message != null) {
actor.printError(message);
}
} else {
String message = e.getMessage();
actor.printError(message != null ? message : "The command was not used properly (no more help available).");
actor.printError("Usage: " + e.getSimpleUsageString("/"));
}
} catch (WrappedCommandException e) {
Throwable t = e.getCause();
actor.printError("Please report this error: [See console]");
actor.printRaw(t.getClass().getName() + ": " + t.getMessage());
log.error("An unexpected error while handling a WorldEdit command", t);
} catch (CommandException e) {
String message = e.getMessage();
if (message != null) {
actor.printError(e.getMessage());
} else {
actor.printError("An unknown error has occurred! Please see console.");
log.error("An unknown error occurred", e);
}
} finally {
EditSession editSession = locals.get(EditSession.class);
if (editSession != null) {
session.remember(editSession);
editSession.flushSession();
if (config.profile) {
long time = System.currentTimeMillis() - start;
int changed = editSession.getBlockChangeCount();
if (time > 0) {
double throughput = changed / (time / 1000.0);
actor.printDebug((time / 1000.0) + "s elapsed (history: "
+ changed + " changed; "
+ Math.round(throughput) + " blocks/sec).");
} else {
actor.printDebug((time / 1000.0) + "s elapsed.");
}
}
worldEdit.flushBlockBag(actor, editSession);
}
Request.reset();
}
event.setCancelled(true);
}
@Subscribe
public void handleCommandSuggestion(CommandSuggestionEvent event) {
try {
CommandLocals locals = new CommandLocals();
locals.put(Actor.class, event.getActor());
locals.put("arguments", event.getArguments());
event.setSuggestions(dispatcher.getSuggestions(event.getArguments(), locals));
} catch (CommandException e) {
event.getActor().printError(e.getMessage());
}
}
/**
* Get the command dispatcher instance.
*
* @return the command dispatcher
*/
public Dispatcher getDispatcher() {
return dispatcher;
}
public static java.util.logging.Logger getLogger() {
return commandLog;
}
}

View File

@ -21,14 +21,13 @@ package com.sk89q.worldedit.extension.platform;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.util.command.Dispatcher;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.registry.Registries; import com.sk89q.worldedit.world.registry.Registries;
import org.enginehub.piston.CommandManager;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;
/** /**
* Represents a platform that WorldEdit has been implemented for. * Represents a platform that WorldEdit has been implemented for.
@ -104,11 +103,11 @@ public interface Platform {
@Nullable World matchWorld(World world); @Nullable World matchWorld(World world);
/** /**
* Register the commands contained within the given command dispatcher. * Register the commands contained within the given command manager.
* *
* @param dispatcher the dispatcher * @param commandManager the command manager
*/ */
void registerCommands(Dispatcher dispatcher); void registerCommands(CommandManager commandManager);
/** /**
* Register game hooks. * Register game hooks.

View File

@ -0,0 +1,591 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extension.platform;
import com.google.common.collect.ImmutableList;
import com.google.common.reflect.TypeToken;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.ApplyBrushCommands;
import com.sk89q.worldedit.command.BiomeCommands;
import com.sk89q.worldedit.command.BiomeCommandsRegistration;
import com.sk89q.worldedit.command.BrushCommands;
import com.sk89q.worldedit.command.BrushCommandsRegistration;
import com.sk89q.worldedit.command.ChunkCommands;
import com.sk89q.worldedit.command.ChunkCommandsRegistration;
import com.sk89q.worldedit.command.ClipboardCommands;
import com.sk89q.worldedit.command.ClipboardCommandsRegistration;
import com.sk89q.worldedit.command.GeneralCommands;
import com.sk89q.worldedit.command.GeneralCommandsRegistration;
import com.sk89q.worldedit.command.GenerationCommands;
import com.sk89q.worldedit.command.GenerationCommandsRegistration;
import com.sk89q.worldedit.command.HistoryCommands;
import com.sk89q.worldedit.command.HistoryCommandsRegistration;
import com.sk89q.worldedit.command.NavigationCommands;
import com.sk89q.worldedit.command.NavigationCommandsRegistration;
import com.sk89q.worldedit.command.PaintBrushCommands;
import com.sk89q.worldedit.command.RegionCommands;
import com.sk89q.worldedit.command.RegionCommandsRegistration;
import com.sk89q.worldedit.command.SchematicCommands;
import com.sk89q.worldedit.command.SchematicCommandsRegistration;
import com.sk89q.worldedit.command.ScriptingCommands;
import com.sk89q.worldedit.command.ScriptingCommandsRegistration;
import com.sk89q.worldedit.command.SelectionCommands;
import com.sk89q.worldedit.command.SelectionCommandsRegistration;
import com.sk89q.worldedit.command.SnapshotCommands;
import com.sk89q.worldedit.command.SnapshotCommandsRegistration;
import com.sk89q.worldedit.command.SnapshotUtilCommands;
import com.sk89q.worldedit.command.SnapshotUtilCommandsRegistration;
import com.sk89q.worldedit.command.SuperPickaxeCommands;
import com.sk89q.worldedit.command.SuperPickaxeCommandsRegistration;
import com.sk89q.worldedit.command.ToolCommands;
import com.sk89q.worldedit.command.ToolCommandsRegistration;
import com.sk89q.worldedit.command.ToolUtilCommands;
import com.sk89q.worldedit.command.ToolUtilCommandsRegistration;
import com.sk89q.worldedit.command.UtilityCommands;
import com.sk89q.worldedit.command.UtilityCommandsRegistration;
import com.sk89q.worldedit.command.WorldEditCommands;
import com.sk89q.worldedit.command.WorldEditCommandsRegistration;
import com.sk89q.worldedit.command.argument.Arguments;
import com.sk89q.worldedit.command.argument.BooleanConverter;
import com.sk89q.worldedit.command.argument.CommaSeparatedValuesConverter;
import com.sk89q.worldedit.command.argument.DirectionConverter;
import com.sk89q.worldedit.command.argument.EntityRemoverConverter;
import com.sk89q.worldedit.command.argument.EnumConverter;
import com.sk89q.worldedit.command.argument.ExpandAmountConverter;
import com.sk89q.worldedit.command.argument.FactoryConverter;
import com.sk89q.worldedit.command.argument.RegionFactoryConverter;
import com.sk89q.worldedit.command.argument.RegistryConverter;
import com.sk89q.worldedit.command.argument.VectorConverter;
import com.sk89q.worldedit.command.argument.ZonedDateTimeConverter;
import com.sk89q.worldedit.command.util.PermissionCondition;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.annotation.Selection;
import com.sk89q.worldedit.internal.command.CommandLoggingHandler;
import com.sk89q.worldedit.internal.command.exception.WorldEditExceptionConverter;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.internal.command.CommandArgParser;
import com.sk89q.worldedit.internal.command.CommandRegistrationHandler;
import com.sk89q.worldedit.internal.command.exception.ExceptionConverter;
import com.sk89q.worldedit.util.eventbus.Subscribe;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.logging.DynamicStreamHandler;
import com.sk89q.worldedit.util.logging.LogFormat;
import com.sk89q.worldedit.world.World;
import org.enginehub.piston.ColorConfig;
import org.enginehub.piston.Command;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.DefaultCommandManagerService;
import org.enginehub.piston.converter.ArgumentConverters;
import org.enginehub.piston.exception.CommandException;
import org.enginehub.piston.exception.CommandExecutionException;
import org.enginehub.piston.exception.ConditionFailedException;
import org.enginehub.piston.exception.UsageException;
import org.enginehub.piston.gen.CommandRegistration;
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.enginehub.piston.inject.MergedValueAccess;
import org.enginehub.piston.part.SubCommandPart;
import org.enginehub.piston.util.HelpGenerator;
import org.enginehub.piston.util.ValueProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Handles the registration and invocation of commands.
*
* <p>This class is primarily for internal usage.</p>
*/
public final class PlatformCommandManager {
public static final Pattern COMMAND_CLEAN_PATTERN = Pattern.compile("^[/]+");
private static final Logger log = LoggerFactory.getLogger(PlatformCommandManager.class);
private static final java.util.logging.Logger COMMAND_LOG =
java.util.logging.Logger.getLogger("com.sk89q.worldedit.CommandLog");
private final WorldEdit worldEdit;
private final PlatformManager platformManager;
private final CommandManager commandManager;
private final InjectedValueStore globalInjectedValues;
private final DynamicStreamHandler dynamicHandler = new DynamicStreamHandler();
private final WorldEditExceptionConverter exceptionConverter;
private final CommandRegistrationHandler registration;
/**
* Create a new instance.
*
* @param worldEdit the WorldEdit instance
*/
PlatformCommandManager(final WorldEdit worldEdit, PlatformManager platformManager) {
checkNotNull(worldEdit);
checkNotNull(platformManager);
this.worldEdit = worldEdit;
this.platformManager = platformManager;
this.exceptionConverter = new WorldEditExceptionConverter(worldEdit);
this.commandManager = DefaultCommandManagerService.getInstance()
.newCommandManager();
this.globalInjectedValues = MapBackedValueStore.create();
this.registration = new CommandRegistrationHandler(
ImmutableList.of(
new CommandLoggingHandler(worldEdit, COMMAND_LOG)
));
// setup separate from main constructor
// ensures that everything is definitely assigned
initialize();
}
private void initialize() {
// Register this instance for command events
worldEdit.getEventBus().register(this);
// Setup the logger
COMMAND_LOG.addHandler(dynamicHandler);
// Set up the commands manager
registerAlwaysInjectedValues();
registerArgumentConverters();
registerAllCommands();
}
private void registerArgumentConverters() {
DirectionConverter.register(worldEdit, commandManager);
FactoryConverter.register(worldEdit, commandManager);
for (int count = 2; count <= 3; count++) {
commandManager.registerConverter(Key.of(double.class, Annotations.radii(count)),
CommaSeparatedValuesConverter.wrapAndLimit(ArgumentConverters.get(
TypeToken.of(double.class)
), count)
);
}
VectorConverter.register(commandManager);
EnumConverter.register(commandManager);
RegistryConverter.register(commandManager);
ExpandAmountConverter.register(commandManager);
ZonedDateTimeConverter.register(commandManager);
BooleanConverter.register(commandManager);
EntityRemoverConverter.register(commandManager);
RegionFactoryConverter.register(commandManager);
}
private void registerAlwaysInjectedValues() {
globalInjectedValues.injectValue(Key.of(Region.class, Selection.class),
context -> {
LocalSession localSession = context.injectedValue(Key.of(LocalSession.class))
.orElseThrow(() -> new IllegalStateException("No LocalSession"));
return context.injectedValue(Key.of(Player.class))
.map(player -> {
try {
return localSession.getSelection(player.getWorld());
} catch (IncompleteRegionException e) {
exceptionConverter.convert(e);
throw new AssertionError("Should have thrown a new exception.");
}
});
});
globalInjectedValues.injectValue(Key.of(EditSession.class),
context -> {
LocalSession localSession = context.injectedValue(Key.of(LocalSession.class))
.orElseThrow(() -> new IllegalStateException("No LocalSession"));
return context.injectedValue(Key.of(Player.class))
.map(player -> {
EditSession editSession = localSession.createEditSession(player);
editSession.enableStandardMode();
return editSession;
});
});
}
private <CI> void registerSubCommands(String name, List<String> aliases, String desc,
CommandRegistration<CI> registration, CI instance) {
registerSubCommands(name, aliases, desc, registration, instance, m -> {});
}
private <CI> void registerSubCommands(String name, List<String> aliases, String desc,
CommandRegistration<CI> registration, CI instance,
Consumer<CommandManager> additionalConfig) {
commandManager.register(name, cmd -> {
cmd.aliases(aliases);
cmd.description(TextComponent.of(desc));
cmd.action(Command.Action.NULL_ACTION);
CommandManager manager = DefaultCommandManagerService.getInstance()
.newCommandManager();
this.registration.register(
manager,
registration,
instance
);
additionalConfig.accept(manager);
cmd.addPart(SubCommandPart.builder(TranslatableComponent.of("worldedit.argument.action"),
TextComponent.of("Sub-command to run."))
.withCommands(manager.getAllCommands().collect(Collectors.toList()))
.required()
.build());
});
}
private void registerAllCommands() {
registerSubCommands(
"schematic",
ImmutableList.of("schem", "/schematic", "/schem"),
"Schematic commands for saving/loading areas",
SchematicCommandsRegistration.builder(),
new SchematicCommands(worldEdit)
);
registerSubCommands(
"snapshot",
ImmutableList.of("snap"),
"Snapshot commands for saving/loading snapshots",
SnapshotCommandsRegistration.builder(),
new SnapshotCommands(worldEdit)
);
registerSubCommands(
"superpickaxe",
ImmutableList.of("pickaxe", "sp"),
"Super-pickaxe commands",
SuperPickaxeCommandsRegistration.builder(),
new SuperPickaxeCommands(worldEdit)
);
registerSubCommands(
"brush",
ImmutableList.of("br"),
"Brushing commands",
BrushCommandsRegistration.builder(),
new BrushCommands(worldEdit),
manager -> {
PaintBrushCommands.register(manager, registration);
ApplyBrushCommands.register(manager, registration);
}
);
registerSubCommands(
"worldedit",
ImmutableList.of("we"),
"WorldEdit commands",
WorldEditCommandsRegistration.builder(),
new WorldEditCommands(worldEdit)
);
this.registration.register(
commandManager,
BiomeCommandsRegistration.builder(),
new BiomeCommands()
);
this.registration.register(
commandManager,
ChunkCommandsRegistration.builder(),
new ChunkCommands(worldEdit)
);
this.registration.register(
commandManager,
ClipboardCommandsRegistration.builder(),
new ClipboardCommands()
);
this.registration.register(
commandManager,
GeneralCommandsRegistration.builder(),
new GeneralCommands(worldEdit)
);
this.registration.register(
commandManager,
GenerationCommandsRegistration.builder(),
new GenerationCommands(worldEdit)
);
this.registration.register(
commandManager,
HistoryCommandsRegistration.builder(),
new HistoryCommands(worldEdit)
);
this.registration.register(
commandManager,
NavigationCommandsRegistration.builder(),
new NavigationCommands(worldEdit)
);
this.registration.register(
commandManager,
RegionCommandsRegistration.builder(),
new RegionCommands()
);
this.registration.register(
commandManager,
ScriptingCommandsRegistration.builder(),
new ScriptingCommands(worldEdit)
);
this.registration.register(
commandManager,
SelectionCommandsRegistration.builder(),
new SelectionCommands(worldEdit)
);
this.registration.register(
commandManager,
SnapshotUtilCommandsRegistration.builder(),
new SnapshotUtilCommands(worldEdit)
);
this.registration.register(
commandManager,
ToolCommandsRegistration.builder(),
new ToolCommands(worldEdit)
);
this.registration.register(
commandManager,
ToolUtilCommandsRegistration.builder(),
new ToolUtilCommands(worldEdit)
);
this.registration.register(
commandManager,
UtilityCommandsRegistration.builder(),
new UtilityCommands(worldEdit)
);
}
public ExceptionConverter getExceptionConverter() {
return exceptionConverter;
}
void registerCommandsWith(Platform platform) {
log.info("Registering commands with " + platform.getClass().getCanonicalName());
LocalConfiguration config = platform.getConfiguration();
boolean logging = config.logCommands;
String path = config.logFile;
// Register log
if (!logging || path.isEmpty()) {
dynamicHandler.setHandler(null);
COMMAND_LOG.setLevel(Level.OFF);
} else {
File file = new File(config.getWorkingDirectory(), path);
COMMAND_LOG.setLevel(Level.ALL);
log.info("Logging WorldEdit commands to " + file.getAbsolutePath());
try {
dynamicHandler.setHandler(new FileHandler(file.getAbsolutePath(), true));
} catch (IOException e) {
log.warn("Could not use command log file " + path + ": " + e.getMessage());
}
dynamicHandler.setFormatter(new LogFormat(config.logFormat));
}
platform.registerCommands(commandManager);
}
void removeCommands() {
dynamicHandler.setHandler(null);
}
public String[] commandDetection(String[] split) {
// Quick script shortcut
if (split[0].matches("^[^/].*\\.js$")) {
String[] newSplit = new String[split.length + 1];
System.arraycopy(split, 0, newSplit, 1, split.length);
newSplit[0] = "cs";
newSplit[1] = newSplit[1];
split = newSplit;
}
String searchCmd = split[0].toLowerCase();
// Try to detect the command
if (!commandManager.containsCommand(searchCmd)) {
if (worldEdit.getConfiguration().noDoubleSlash && commandManager.containsCommand("/" + searchCmd)) {
split[0] = "/" + split[0];
} else if (searchCmd.length() >= 2 && searchCmd.charAt(0) == '/' && commandManager.containsCommand(searchCmd.substring(1))) {
split[0] = split[0].substring(1);
}
}
return split;
}
private String[] parseArgs(String input) {
return new CommandArgParser(input).parseArgs().toArray(String[]::new);
}
@Subscribe
public void handleCommand(CommandEvent event) {
Request.reset();
Actor actor = platformManager.createProxyActor(event.getActor());
String[] split = commandDetection(parseArgs(event.getArguments().substring(1)));
// No command found!
if (!commandManager.containsCommand(split[0])) {
return;
}
LocalSession session = worldEdit.getSessionManager().get(actor);
Request.request().setSession(session);
if (actor instanceof Entity) {
Extent extent = ((Entity) actor).getExtent();
if (extent instanceof World) {
Request.request().setWorld(((World) extent));
}
}
LocalConfiguration config = worldEdit.getConfiguration();
InjectedValueStore store = MapBackedValueStore.create();
store.injectValue(Key.of(Actor.class), ValueProvider.constant(actor));
if (actor instanceof Player) {
store.injectValue(Key.of(Player.class), ValueProvider.constant((Player) actor));
} else {
store.injectValue(Key.of(Player.class), context -> {
throw new CommandException(TextComponent.of("This command must be used with a player."), ImmutableList.of());
});
}
store.injectValue(Key.of(Arguments.class), ValueProvider.constant(event::getArguments));
store.injectValue(Key.of(LocalSession.class),
context -> {
LocalSession localSession = worldEdit.getSessionManager().get(actor);
localSession.tellVersion(actor);
return Optional.of(localSession);
});
MemoizingValueAccess context = MemoizingValueAccess.wrap(
MergedValueAccess.of(store, globalInjectedValues)
);
long start = System.currentTimeMillis();
try {
// This is a bit of a hack, since the call method can only throw CommandExceptions
// everything needs to be wrapped at least once. Which means to handle all WorldEdit
// exceptions without writing a hook into every dispatcher, we need to unwrap these
// exceptions and rethrow their converted form, if their is one.
try {
commandManager.execute(context, ImmutableList.copyOf(split));
} catch (Throwable t) {
// Use the exception converter to convert the exception if any of its causes
// can be converted, otherwise throw the original exception
Throwable next = t;
do {
exceptionConverter.convert(next);
next = next.getCause();
} while (next != null);
throw t;
}
} catch (ConditionFailedException e) {
if (e.getCondition() instanceof PermissionCondition) {
actor.printError("You are not permitted to do that. Are you in the right mode?");
}
} catch (UsageException e) {
actor.print(TextComponent.builder("")
.color(TextColor.RED)
.append(e.getRichMessage())
.build());
ImmutableList<Command> cmd = e.getCommands();
if (!cmd.isEmpty()) {
actor.print(TextComponent.builder("Usage: ")
.color(TextColor.RED)
.append(TextComponent.of("/", ColorConfig.getMainText()))
.append(HelpGenerator.create(e.getCommandParseResult()).getUsage())
.build());
}
} catch (CommandExecutionException e) {
handleUnknownException(actor, e.getCause());
} catch (CommandException e) {
actor.print(TextComponent.builder("")
.color(TextColor.RED)
.append(e.getRichMessage())
.build());
} catch (Throwable t) {
handleUnknownException(actor, t);
} finally {
Optional<EditSession> editSessionOpt =
context.snapshotMemory().injectedValue(Key.of(EditSession.class));
if (editSessionOpt.isPresent()) {
EditSession editSession = editSessionOpt.get();
session.remember(editSession);
editSession.flushSession();
if (config.profile) {
long time = System.currentTimeMillis() - start;
int changed = editSession.getBlockChangeCount();
if (time > 0) {
double throughput = changed / (time / 1000.0);
actor.printDebug((time / 1000.0) + "s elapsed (history: "
+ changed + " changed; "
+ Math.round(throughput) + " blocks/sec).");
} else {
actor.printDebug((time / 1000.0) + "s elapsed.");
}
}
worldEdit.flushBlockBag(actor, editSession);
}
Request.reset();
}
event.setCancelled(true);
}
private void handleUnknownException(Actor actor, Throwable t) {
actor.printError("Please report this error: [See console]");
actor.printRaw(t.getClass().getName() + ": " + t.getMessage());
log.error("An unexpected error while handling a WorldEdit command", t);
}
@Subscribe
public void handleCommandSuggestion(CommandSuggestionEvent event) {
try {
globalInjectedValues.injectValue(Key.of(Actor.class), ValueProvider.constant(event.getActor()));
globalInjectedValues.injectValue(Key.of(Arguments.class), ValueProvider.constant(event::getArguments));
// TODO suggestions
} catch (CommandException e) {
event.getActor().printError(e.getMessage());
}
}
/**
* Get the command manager instance.
*
* @return the command manager
*/
public CommandManager getCommandManager() {
return commandManager;
}
}

View File

@ -68,7 +68,7 @@ public class PlatformManager {
private static final Logger logger = LoggerFactory.getLogger(PlatformManager.class); private static final Logger logger = LoggerFactory.getLogger(PlatformManager.class);
private final WorldEdit worldEdit; private final WorldEdit worldEdit;
private final CommandManager commandManager; private final PlatformCommandManager platformCommandManager;
private final List<Platform> platforms = new ArrayList<>(); private final List<Platform> platforms = new ArrayList<>();
private final Map<Capability, Platform> preferences = new EnumMap<>(Capability.class); private final Map<Capability, Platform> preferences = new EnumMap<>(Capability.class);
private @Nullable String firstSeenVersion; private @Nullable String firstSeenVersion;
@ -83,7 +83,7 @@ public class PlatformManager {
public PlatformManager(WorldEdit worldEdit) { public PlatformManager(WorldEdit worldEdit) {
checkNotNull(worldEdit); checkNotNull(worldEdit);
this.worldEdit = worldEdit; this.worldEdit = worldEdit;
this.commandManager = new CommandManager(worldEdit, this); this.platformCommandManager = new PlatformCommandManager(worldEdit, this);
// Register this instance for events // Register this instance for events
worldEdit.getEventBus().register(this); worldEdit.getEventBus().register(this);
@ -277,8 +277,8 @@ public class PlatformManager {
* *
* @return the command manager * @return the command manager
*/ */
public CommandManager getCommandManager() { public PlatformCommandManager getPlatformCommandManager() {
return commandManager; return platformCommandManager;
} }
/** /**

View File

@ -31,10 +31,10 @@ import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.session.SessionKey;
import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import java.util.UUID; import java.util.UUID;
@ -134,7 +134,7 @@ class PlayerProxy extends AbstractPlayerActor {
} }
@Override @Override
public void print(TextComponent component) { public void print(Component component) {
basePlayer.print(component); basePlayer.print(component);
} }

View File

@ -102,10 +102,11 @@ public class SpongeSchematicReader extends NBTSchematicReader {
return readVersion1(schematicTag); return readVersion1(schematicTag);
} else if (version == 2) { } else if (version == 2) {
int dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue(); int dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue();
if (dataVersion > WorldEdit.getInstance().getPlatformManager() int liveDataVersion = WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.WORLD_EDITING).getDataVersion()) { .queryCapability(Capability.WORLD_EDITING).getDataVersion();
// maybe should just warn? simple schematics may be compatible still. if (dataVersion > liveDataVersion) {
throw new IOException("Schematic was made in a newer Minecraft version. Data may be incompatible."); log.warn("Schematic was made in a newer Minecraft version ({} > {}). Data may be incompatible.",
dataVersion, liveDataVersion);
} }
BlockArrayClipboard clip = readVersion1(schematicTag); BlockArrayClipboard clip = readVersion1(schematicTag);
return readVersion2(clip, schematicTag); return readVersion2(clip, schematicTag);

View File

@ -17,24 +17,26 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.command.argument; package com.sk89q.worldedit.function;
import com.sk89q.worldedit.function.Contextual; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.util.command.composition.BranchingCommand; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.World;
public class RegionFunctionParser extends BranchingCommand<Contextual<? extends RegionFunction>> { public final class ItemUseFunction implements RegionFunction {
private final World world;
private final BaseItem item;
public RegionFunctionParser() { public ItemUseFunction(World world, BaseItem item) {
super("functionTpe"); this.world = world;
putOption(new TreeGeneratorParser("treeType"), "forest"); this.item = item;
putOption(new ItemUseParser(), "item");
putOption(new ReplaceParser(), "set");
} }
@Override @Override
public String getDescription() { public boolean apply(BlockVector3 position) throws WorldEditException {
return "Choose a block function"; return world.useItem(position, item, Direction.UP);
} }
} }

View File

@ -19,7 +19,8 @@
package com.sk89q.worldedit.internal.annotation; package com.sk89q.worldedit.internal.annotation;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.BlockVector3;
import org.enginehub.piston.inject.InjectAnnotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -27,12 +28,13 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* Annotates a {@link Vector3} parameter to inject a direction. * Annotates a {@link BlockVector3} parameter to inject a direction.
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER) @Target(ElementType.PARAMETER)
@InjectAnnotation
public @interface Direction { public @interface Direction {
String AIM = "me"; String AIM = "me";
boolean includeDiagonals() default false; boolean includeDiagonals() default false;

View File

@ -17,7 +17,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.util.command.parametric; package com.sk89q.worldedit.internal.annotation;
import org.enginehub.piston.inject.InjectAnnotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -25,17 +27,11 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* Indicates an optional parameter. * Annotates a {@code List<BlockVector3>} parameter to inject multiple direction.
*/ */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Optional { @Target(ElementType.PARAMETER)
@InjectAnnotation
/** public @interface MultiDirection {
* The default value to use if no value is set. boolean includeDiagonals() default false;
*
* @return a string value, or an empty list
*/
String[] value() default {};
} }

View File

@ -17,29 +17,24 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.util.command.binding; package com.sk89q.worldedit.internal.annotation;
import org.enginehub.piston.inject.InjectAnnotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.util.regex.Pattern;
/** /**
* Used to validate a string. * Annotates a {@code double} parameter to inject multiple radii values.
*
* @see PrimitiveBindings where this validation is used
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER) @Target(ElementType.PARAMETER)
public @interface Validate { @InjectAnnotation
public @interface Radii {
/** /**
* An optional regular expression that must match the string. * Number of radii values to inject at maximum. May inject less.
*
* @see Pattern regular expression class
* @return the pattern
*/ */
String regex() default ""; int value();
} }

Some files were not shown because too many files have changed in this diff Show More