Various command (use es6 if java9 + nashorn)

This commit is contained in:
Jesse Boyd
2018-08-22 03:22:37 +10:00
parent 43531a0da0
commit c55353e5b1
59 changed files with 1799 additions and 612 deletions

View File

@ -12,62 +12,10 @@ import com.boydti.fawe.util.chat.ChatManager;
import com.boydti.fawe.util.chat.PlainChatManager;
import com.boydti.fawe.util.cui.CUI;
import com.boydti.fawe.util.metrics.BStats;
import com.boydti.fawe.wrappers.FakePlayer;
import com.sk89q.jnbt.*;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.command.*;
import com.sk89q.worldedit.command.composition.SelectionCommand;
import com.sk89q.worldedit.command.tool.*;
import com.sk89q.worldedit.command.tool.brush.GravityBrush;
import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.extension.factory.DefaultMaskParser;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.factory.DefaultTransformParser;
import com.sk89q.worldedit.extension.factory.HashTagPatternParser;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.CommandManager;
import com.sk89q.worldedit.extension.platform.PlatformManager;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.MaskingExtent;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.SchematicReader;
import com.sk89q.worldedit.extent.inventory.BlockBagExtent;
import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
import com.sk89q.worldedit.function.CombinedRegionFunction;
import com.sk89q.worldedit.function.block.BlockReplace;
import com.sk89q.worldedit.function.block.ExtentBlockCopy;
import com.sk89q.worldedit.function.entity.ExtentEntityCopy;
import com.sk89q.worldedit.function.mask.*;
import com.sk89q.worldedit.function.operation.ChangeSetExecutor;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.*;
import com.sk89q.worldedit.function.visitor.*;
import com.sk89q.worldedit.internal.command.WorldEditBinding;
import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.runtime.*;
import com.sk89q.worldedit.math.convolution.HeightMap;
import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.CylinderRegion;
import com.sk89q.worldedit.regions.EllipsoidRegion;
import com.sk89q.worldedit.regions.selector.*;
import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.session.PasteBuilder;
import com.sk89q.worldedit.session.SessionManager;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.command.SimpleCommandMapping;
import com.sk89q.worldedit.util.command.SimpleDispatcher;
import com.sk89q.worldedit.util.command.fluent.DispatcherNode;
import com.sk89q.worldedit.util.command.parametric.*;
import com.sk89q.worldedit.util.formatting.Fragment;
import com.sk89q.worldedit.util.formatting.component.CommandListBox;
import com.sk89q.worldedit.util.formatting.component.CommandUsageBox;
import com.sk89q.worldedit.util.formatting.component.MessageBox;
import com.sk89q.worldedit.world.biome.BaseBiome;
import javax.annotation.Nullable;
import javax.management.InstanceAlreadyExistsException;
@ -418,6 +366,8 @@ public class Fawe {
MainUtil.copyFile(MainUtil.getJarFile(), "tr/message.yml", null);
MainUtil.copyFile(MainUtil.getJarFile(), "es/message.yml", null);
MainUtil.copyFile(MainUtil.getJarFile(), "es/commands.yml", null);
MainUtil.copyFile(MainUtil.getJarFile(), "nl/message.yml", null);
MainUtil.copyFile(MainUtil.getJarFile(), "fr/message.yml", null);
// Setting up config.yml
File file = new File(this.IMP.getDirectory(), "config.yml");
Settings.IMP.PLATFORM = IMP.getPlatform().replace("\"", "");

View File

@ -135,18 +135,18 @@ public class AnvilCommands {
}
}
// @Command(
// aliases = {"replaceall", "rea", "repall"},
// usage = "<folder> [from-block] <to-block>",
// desc = "Replace all blocks in the selection with another",
// help = "Replace all blocks in the selection with another\n" +
// "The -d flag disabled wildcard data matching\n",
// flags = "df",
// min = 2,
// max = 4
// )
// @CommandPermissions("worldedit.anvil.replaceall")
// public void replaceAll(Player player, String folder, @Optional String from, String to, @Switch('d') boolean useData) throws WorldEditException {
@Command(
aliases = {"replaceall", "rea", "repall"},
usage = "<folder> [from-block] <to-block>",
desc = "Replace all blocks in the selection with another",
help = "Replace all blocks in the selection with another\n" +
"The -d flag disabled wildcard data matching\n",
flags = "df",
min = 2,
max = 4
)
@CommandPermissions("worldedit.anvil.replaceall")
public void replaceAll(Player player, String folder, @Optional String from, String to, @Switch('d') boolean useData) throws WorldEditException {
// final FaweBlockMatcher matchFrom;
// if (from == null) {
// matchFrom = FaweBlockMatcher.NOT_AIR;
@ -160,7 +160,7 @@ public class AnvilCommands {
// ReplaceSimpleFilter filter = new ReplaceSimpleFilter(matchFrom, matchTo);
// ReplaceSimpleFilter result = runWithWorld(player, folder, filter, true);
// if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
// }
}
@Command(
aliases = {"remapall"},
@ -333,16 +333,16 @@ public class AnvilCommands {
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
}
// @Command(
// aliases = {"replaceallpattern", "reap", "repallpat"},
// usage = "<folder> [from-block] <to-pattern>",
// desc = "Replace all blocks in the selection with another",
// flags = "dm",
// min = 2,
// max = 4
// )
// @CommandPermissions("worldedit.anvil.replaceall")
// public void replaceAllPattern(Player player, String folder, @Optional String from, final Pattern to, @Switch('d') boolean useData, @Switch('m') boolean useMap) throws WorldEditException {
@Command(
aliases = {"replaceallpattern", "reap", "repallpat"},
usage = "<folder> [from-block] <to-pattern>",
desc = "Replace all blocks in the selection with another",
flags = "dm",
min = 2,
max = 4
)
@CommandPermissions("worldedit.anvil.replaceall")
public void replaceAllPattern(Player player, String folder, @Optional String from, final Pattern to, @Switch('d') boolean useData, @Switch('m') boolean useMap) throws WorldEditException {
// MCAFilterCounter filter;
// if (useMap) {
// if (to instanceof RandomPattern) {
@ -363,18 +363,18 @@ public class AnvilCommands {
// }
// MCAFilterCounter result = runWithWorld(player, folder, filter, true);
// if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
// }
}
//
// @Command(
// aliases = {"countall"},
// usage = "<folder> [hasSky] <id>",
// desc = "Count all blocks in a world",
// flags = "d",
// min = 2,
// max = 3
// )
// @CommandPermissions("worldedit.anvil.countall")
// public void countAll(Player player, EditSession editSession, String folder, String arg, @Switch('d') boolean useData) throws WorldEditException {
@Command(
aliases = {"countall"},
usage = "<folder> [hasSky] <id>",
desc = "Count all blocks in a world",
flags = "d",
min = 2,
max = 3
)
@CommandPermissions("worldedit.anvil.countall")
public void countAll(Player player, EditSession editSession, String folder, String arg, @Switch('d') boolean useData) throws WorldEditException {
// Set<BaseBlock> searchBlocks = worldEdit.getBlocks(player, arg, true);
// MCAFilterCounter filter;
// if (useData || arg.contains(":")) { // Optimize for both cases
@ -388,7 +388,7 @@ public class AnvilCommands {
// }
// MCAFilterCounter result = runWithWorld(player, folder, filter, true);
// if (result != null) player.print(BBC.getPrefix() + BBC.SELECTION_COUNT.format(result.getTotal()));
// }
}
@Command(
aliases = {"clear", "unset"},
@ -440,16 +440,16 @@ public class AnvilCommands {
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
}
// @Command(
// aliases = {"count"},
// usage = "<ids>",
// desc = "Count blocks in a selection",
// flags = "d",
// min = 1,
// max = 2
// )
// @CommandPermissions("worldedit.anvil.count")
// public void count(Player player, EditSession editSession, @Selection Region selection, String arg, @Switch('d') boolean useData) throws WorldEditException {
@Command(
aliases = {"count"},
usage = "<ids>",
desc = "Count blocks in a selection",
flags = "d",
min = 1,
max = 2
)
@CommandPermissions("worldedit.anvil.count")
public void count(Player player, EditSession editSession, @Selection Region selection, String arg, @Switch('d') boolean useData) throws WorldEditException {
// Set<BaseBlock> searchBlocks = worldEdit.getBlocks(player, arg, true);
// MCAFilterCounter filter;
// if (useData || arg.contains(":")) { // Optimize for both cases
@ -463,14 +463,14 @@ public class AnvilCommands {
// }
// MCAFilterCounter result = runWithSelection(player, editSession, selection, filter);
// if (result != null) player.print(BBC.getPrefix() + BBC.SELECTION_COUNT.format(result.getTotal()));
// }
}
//
// @Command(
// aliases = {"distr"},
// desc = "Replace all blocks in the selection with another"
// )
// @CommandPermissions("worldedit.anvil.distr")
// public void distr(Player player, EditSession editSession, @Selection Region selection, @Switch('d') boolean useData) throws WorldEditException {
@Command(
aliases = {"distr"},
desc = "Replace all blocks in the selection with another"
)
@CommandPermissions("worldedit.anvil.distr")
public void distr(Player player, EditSession editSession, @Selection Region selection, @Switch('d') boolean useData) throws WorldEditException {
// long total = 0;
// long[] count;
// MCAFilter<long[]> counts;
@ -540,15 +540,15 @@ public class AnvilCommands {
// player.print(BBC.getPrefix() + str);
// }
// }
// }
}
//
// @Command(
// aliases = {"replace", "r"},
// usage = "[from-block] <to-block>",
// desc = "Replace all blocks in the selection with another"
// )
// @CommandPermissions("worldedit.anvil.replace")
// public void replace(Player player, EditSession editSession, @Selection Region selection, @Optional String from, String to, @Switch('d') boolean useData) throws WorldEditException {
@Command(
aliases = {"replace", "r"},
usage = "[from-block] <to-block>",
desc = "Replace all blocks in the selection with another"
)
@CommandPermissions("worldedit.anvil.replace")
public void replace(Player player, EditSession editSession, @Selection Region selection, @Optional String from, String to, @Switch('d') boolean useData) throws WorldEditException {
// final FaweBlockMatcher matchFrom;
// if (from == null) {
// matchFrom = FaweBlockMatcher.NOT_AIR;
@ -561,16 +561,16 @@ public class AnvilCommands {
// if (result != null) {
// player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
// }
// }
}
//
// @Command(
// aliases = {"replacepattern", "preplace", "rp"},
// usage = "[from-mask] <to-pattern>",
// desc = "Replace all blocks in the selection with a pattern"
// )
// @CommandPermissions("worldedit.anvil.replace")
// // Player player, String folder, @Optional String from, final Pattern to, @Switch('d') boolean useData, @Switch('m') boolean useMap
// public void replacePattern(Player player, EditSession editSession, @Selection Region selection, @Optional String from, final Pattern to, @Switch('d') boolean useData, @Switch('m') boolean useMap) throws WorldEditException {
@Command(
aliases = {"replacepattern", "preplace", "rp"},
usage = "[from-mask] <to-pattern>",
desc = "Replace all blocks in the selection with a pattern"
)
@CommandPermissions("worldedit.anvil.replace")
// Player player, String folder, @Optional String from, final Pattern to, @Switch('d') boolean useData, @Switch('m') boolean useMap
public void replacePattern(Player player, EditSession editSession, @Selection Region selection, @Optional String from, final Pattern to, @Switch('d') boolean useData, @Switch('m') boolean useMap) throws WorldEditException {
// MCAFilterCounter filter;
// if (useMap) {
// if (to instanceof RandomPattern) {
@ -593,7 +593,7 @@ public class AnvilCommands {
// if (result != null) {
// player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
// }
// }
}
@Command(
aliases = {"set"},
@ -651,17 +651,17 @@ public class AnvilCommands {
BBC.COMMAND_COPY.send(player, selection.getArea());
}
// @Command(
// aliases = {"paste"},
// desc = "Paste chunks from your anvil clipboard",
// help =
// "Paste the chunks from your anvil clipboard.\n" +
// "The -c flag will align the paste to the chunks.",
// flags = "c"
//
// )
// @CommandPermissions("worldedit.anvil.pastechunks")
// public void paste(Player player, LocalSession session, EditSession editSession, @Switch('c') boolean alignChunk) throws WorldEditException, IOException {
@Command(
aliases = {"paste"},
desc = "Paste chunks from your anvil clipboard",
help =
"Paste the chunks from your anvil clipboard.\n" +
"The -c flag will align the paste to the chunks.",
flags = "c"
)
@CommandPermissions("worldedit.anvil.pastechunks")
public void paste(Player player, LocalSession session, EditSession editSession, @Switch('c') boolean alignChunk) throws WorldEditException, IOException {
// FawePlayer fp = FawePlayer.wrap(player);
// MCAClipboard clipboard = fp.getMeta(FawePlayer.METADATA_KEYS.ANVIL_CLIPBOARD);
// if (clipboard == null) {
@ -689,5 +689,5 @@ public class AnvilCommands {
// } catch (IOException e) { throw new RuntimeException(e); }
// });
// BBC.COMMAND_PASTE.send(player, player.getPosition().toBlockVector());
// }
}
}

View File

@ -25,21 +25,21 @@ public abstract class FaweParser<T> extends InputParser<T> {
public abstract Dispatcher getDispatcher();
public List<String> suggestRemaining(String input, String... expected) throws InputParseException {
List<String> remainder = StringMan.split(input, ':');
int len = remainder.size();
if (len != expected.length - 1) {
if (len <= expected.length - 1 && len != 0) {
if (remainder.get(len - 1).endsWith(":")) {
throw new SuggestInputParseException(null, StringMan.join(expected, ":"));
}
throw new SuggestInputParseException(null, expected[0] + ":" + input + ":" + StringMan.join(Arrays.copyOfRange(expected, len + 1, 3), ":"));
} else {
throw new SuggestInputParseException(null, StringMan.join(expected, ":"));
}
}
return remainder;
}
// public List<String> suggestRemaining(String input, String... expected) throws InputParseException {
// List<String> remainder = StringMan.split(input, ':');
// int len = remainder.size();
// if (len != expected.length - 1) {
// if (len <= expected.length - 1 && len != 0) {
// if (remainder.get(len - 1).endsWith(":")) {
// throw new SuggestInputParseException(null, StringMan.join(expected, ":"));
// }
// throw new SuggestInputParseException(null, expected[0] + ":" + input + ":" + StringMan.join(Arrays.copyOfRange(expected, len + 1, 3), ":"));
// } else {
// throw new SuggestInputParseException(null, StringMan.join(expected, ":"));
// }
// }
// return remainder;
// }
protected static class ParseEntry {
public boolean and;
@ -58,7 +58,7 @@ public abstract class FaweParser<T> extends InputParser<T> {
}
}
public List<Map.Entry<ParseEntry, List<String>>> parse(String toParse) throws InputParseException {
public static List<Map.Entry<ParseEntry, List<String>>> parse(String toParse) throws InputParseException {
List<Map.Entry<ParseEntry, List<String>>> keys = new ArrayList<>();
List<String> inputs = new ArrayList<>();
List<Boolean> and = new ArrayList<>();
@ -83,8 +83,11 @@ public abstract class FaweParser<T> extends InputParser<T> {
int next = StringMan.findMatchingBracket(toParse, i);
if (next != -1) {
i = next;
continue outer;
} else {
toParse += "]";
i = toParse.length();
}
continue outer;
}
}
}
@ -93,7 +96,7 @@ public abstract class FaweParser<T> extends InputParser<T> {
String full = inputs.get(i);
String command = full;
List<String> args = new ArrayList<>();
while (command.charAt(command.length() - 1) == ']') {
while (!command.isEmpty() && command.charAt(command.length() - 1) == ']') {
int startPos = StringMan.findMatchingBracket(command, command.length() - 1);
if (startPos == -1) break;
String arg = command.substring(startPos + 1, command.length() - 1);

View File

@ -1,9 +1,16 @@
package com.boydti.fawe.command;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.factory.DefaultMaskParser;
import com.sk89q.worldedit.util.command.parametric.ParameterData;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class MaskBinding extends FaweBinding {
private final WorldEdit worldEdit;
@ -15,25 +22,9 @@ public class MaskBinding extends FaweBinding {
@Override
public List<String> getSuggestions(ParameterData parameter, String prefix) {
// int index = prefix.lastIndexOf(",");
// String start = index != -1 ? prefix.substring(0, index) : "";
// String current = index != -1 ? prefix.substring(index) : prefix;
// if (current.isEmpty()) {
// return MainUtil.prepend(start, Arrays.asList(DefaultMaskParser.ALL_MASKS));
// }
// if (current.startsWith("#") || current.startsWith("=")) {
// return new ArrayList<>();
// }
// if (StringMan.isAlphanumeric(current.charAt(0) + "")) {
// String[] split2 = current.split(":");
// if (split2.length == 2 || current.endsWith(":")) {
// start = (start.isEmpty() ? split2[0] : start + " " + split2[0]) + ":";
// current = split2.length == 2 ? split2[1] : "";
// return MainUtil.prepend(start, MainUtil.filter(current, BundledBlockData.getInstance().getBlockStates(split2[0])));
// }
// List<String> blocks = BundledBlockData.getInstance().getBlockNames(split2[0]);
// return MainUtil.prepend(start, blocks);
// }
if (prefix.isEmpty()) {
return Stream.concat(Stream.of("#"), BlockTypes.getNameSpaces().stream().map(n -> n + ":")).collect(Collectors.toList());
}
return super.getSuggestions(parameter, prefix);
}
}

View File

@ -2,9 +2,13 @@ package com.boydti.fawe.command;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.util.command.parametric.ParameterData;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class PatternBinding extends FaweBinding {
private final WorldEdit worldEdit;
@ -16,32 +20,9 @@ public class PatternBinding extends FaweBinding {
@Override
public List<String> getSuggestions(ParameterData parameter, String prefix) {
if (prefix.isEmpty()) {
return Stream.concat(Stream.of("#"), BlockTypes.getNameSpaces().stream()).collect(Collectors.toList());
}
return super.getSuggestions(parameter, prefix);
// int index = prefix.lastIndexOf(",|%");
// String start = index != -1 ? prefix.substring(0, index) : "";
// String current = index != -1 ? prefix.substring(index) : prefix;
// if (current.isEmpty()) {
// return MainUtil.prepend(start, Arrays.asList(HashTagPatternParser.ALL_PATTERNS));
// }
// if (current.startsWith("#") || current.startsWith("=")) {
// return new ArrayList<>();
// }
// if ("hand".startsWith(prefix)) {
// return MainUtil.prepend(start, Arrays.asList("hand"));
// }
// if ("pos1".startsWith(prefix)) {
// return MainUtil.prepend(start, Arrays.asList("pos1"));
// }
// if (current.contains("|")) {
// return new ArrayList<>();
// }
// String[] split2 = current.split(":");
// if (split2.length == 2 || current.endsWith(":")) {
// start = (start.isEmpty() ? split2[0] : start + " " + split2[0]) + ":";
// current = split2.length == 2 ? split2[1] : "";
// return MainUtil.prepend(start, MainUtil.filter(current, BundledBlockData.getInstance().getBlockStates(split2[0])));
// }
// List<String> blocks = BundledBlockData.getInstance().getBlockNames(split2[0]);
// return MainUtil.prepend(start, blocks);
}
}

View File

@ -2,87 +2,73 @@ package com.boydti.fawe.command;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.StringMan;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extension.input.InputParseException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.Supplier;
import static com.google.common.base.Preconditions.checkNotNull;
public class SuggestInputParseException extends InputParseException {
private final String message;
private final InputParseException cause;
private final Supplier<List<String>> getSuggestions;
private String prefix;
private ArrayList<String> suggestions = new ArrayList<>();
public SuggestInputParseException(String input, Collection<String> inputs) {
super("");
this.message = "Suggested input: " + StringMan.join(suggestions = getSuggestions(input, inputs), ", ");
this.prefix = "";
public SuggestInputParseException(String msg, String prefix, Supplier<List<String>> getSuggestions) {
this(new InputParseException(msg), prefix, getSuggestions);
}
public SuggestInputParseException(String input, String... inputs) {
super("");
this.message = "Suggested input: " + StringMan.join(suggestions = getSuggestions(input, inputs), ", ");
this.prefix = "";
public static SuggestInputParseException of(Throwable other, String prefix, Supplier<List<String>> getSuggestions) {
if (other instanceof InputParseException) return of((InputParseException) other, prefix, getSuggestions);
return of(new InputParseException(other.getMessage()), prefix, getSuggestions);
}
public static SuggestInputParseException of(InputParseException other, String prefix, Supplier<List<String>> getSuggestions) {
if (other instanceof SuggestInputParseException) return (SuggestInputParseException) other;
return new SuggestInputParseException(other, prefix, getSuggestions);
}
public SuggestInputParseException(InputParseException other, String prefix, Supplier<List<String>> getSuggestions) {
super(other.getMessage());
checkNotNull(getSuggestions);
checkNotNull(other);
this.cause = other;
this.getSuggestions = getSuggestions;
this.prefix = prefix;
}
public static SuggestInputParseException get(InvocationTargetException e) {
Throwable t = e;
while (t.getCause() != null) {
t = t.getCause();
if (t instanceof SuggestInputParseException) return (SuggestInputParseException) t;
}
return null;
}
@Override
public synchronized Throwable getCause() {
return cause.getCause();
}
@Override
public String getMessage() {
return message;
return cause.getMessage();
}
public List<String> getSuggestions() {
return MainUtil.prepend(prefix, suggestions);
return getSuggestions.get();
}
public SuggestInputParseException prepend(String input) {
this.prefix = input + prefix;
return this;
}
public static SuggestInputParseException get(Throwable e) {
if (e instanceof SuggestInputParseException) {
return (SuggestInputParseException) e;
}
Throwable cause = e.getCause();
if (cause == null) {
return null;
}
return get(cause);
}
private static ArrayList<String> getSuggestions(String input, Collection<String> inputs) {
ArrayList<String> suggestions = new ArrayList<>();
if (input != null) {
String tmp = input.toLowerCase();
for (String s : inputs) {
if (s.startsWith(tmp)) {
suggestions.add(s);
}
}
}
if (suggestions.isEmpty()) {
suggestions.addAll(inputs);
}
return suggestions;
}
private static ArrayList<String> getSuggestions(String input, String... inputs) {
ArrayList<String> suggestions = new ArrayList<>();
if (input != null) {
String tmp = input.toLowerCase();
for (String s : inputs) {
if (s.startsWith(tmp)) {
suggestions.add(s);
}
}
}
if (suggestions.isEmpty()) {
for (String s : inputs) {
suggestions.add(s);
}
}
return suggestions;
}
}

View File

@ -30,7 +30,8 @@ public class Commands {
}
}
public static Command fromArgs(String[] aliases, String usage, String desc, int min, int max, String flags, String help) {
public static Command fromArgs(String[] aliases, String usage, String desc, int min, Integer max, String flags, String help) {
int finalMax = max == null ? -1 : max;
return new Command() {
@Override
public Class<? extends Annotation> annotationType() {
@ -54,7 +55,7 @@ public class Commands {
}
@Override
public int max() {
return max;
return finalMax;
}
@Override
public String flags() {

View File

@ -76,8 +76,6 @@ public class Settings extends Config {
@Comment({
"Put any minecraft or mod jars for FAWE to be aware of block textures",
})
public String PATTERNS = "patterns";
public String MASKS = "masks";
public String TEXTURES = "textures";
public String HEIGHTMAP = "heightmap";
public String HISTORY = "history";
@ -88,6 +86,7 @@ public class Settings extends Config {
public String CLIPBOARD = "clipboard";
@Comment("Each player has their own sub directory for schematics")
public boolean PER_PLAYER_SCHEMATICS = true;
public String COMMANDS = "commands";
}
@Comment("Region restriction settings")

View File

@ -1,6 +1,8 @@
package com.boydti.fawe.object;
public abstract class RunnableVal2<T, U> implements Runnable {
import java.util.function.BiConsumer;
public abstract class RunnableVal2<T, U> implements Runnable, BiConsumer<T, U> {
public T value1;
public U value2;
@ -23,4 +25,9 @@ public abstract class RunnableVal2<T, U> implements Runnable {
run(value1, value2);
return this;
}
@Override
public void accept(T t, U u) {
run(t, u);
}
}

View File

@ -1,12 +1,9 @@
package com.boydti.fawe.object.clipboard;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import jdk.nashorn.internal.ir.Block;
public class OffsetFaweClipboard extends AbstractDelegateFaweClipboard {
private final int ox, oy, oz;

View File

@ -1,15 +1,9 @@
package com.boydti.fawe.object.pattern;
import com.boydti.fawe.FaweCache;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes;
import jdk.nashorn.internal.ir.Block;
import static com.google.common.base.Preconditions.checkNotNull;

View File

@ -56,6 +56,13 @@ public class MutableCharSequence implements CharSequence {
return str.substring(start, start + length);
}
public int indexOf(char c) {
for (int i = 0; i < length; i++) {
if (charAt(i) == c) return i;
}
return -1;
}
@Override
public boolean equals(Object obj) {
CharSequence anotherString = (CharSequence) obj;

View File

@ -31,6 +31,7 @@ import java.util.Map.Entry;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiConsumer;
import java.util.regex.Pattern;
import java.util.zip.*;
import javax.imageio.ImageIO;
@ -151,13 +152,13 @@ public class MainUtil {
new Exception().printStackTrace();
}
public static void traverse(Path path, final RunnableVal2<Path, BasicFileAttributes> onEach) {
public static void traverse(Path path, final BiConsumer<Path, BasicFileAttributes> onEach) {
try {
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult
visitFile(Path file, BasicFileAttributes attrs) {
onEach.run(file, attrs);
onEach.accept(file, attrs);
return FileVisitResult.CONTINUE;
}

View File

@ -10,6 +10,8 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Function;
import java.util.function.IntConsumer;
import java.util.function.IntFunction;
public class StringMan {
public static String replaceFromMap(final String string, final Map<String, String> replacements) {
@ -33,6 +35,13 @@ public class StringMan {
return sb.toString();
}
public static boolean containsAny(CharSequence sequence, String any) {
for (int i = 0; i < sequence.length(); i++) {
if (any.indexOf(sequence.charAt(i)) != -1) return true;
}
return false;
}
public static int findMatchingBracket(CharSequence sequence, int index) {
char startC = sequence.charAt(index);
char lookC = getMatchingBracket(startC);

View File

@ -504,7 +504,7 @@ public class TextureUtil implements TextureHolder{
}
public BiomeColor getNearestBiome(int color) {
int grass = blockColors[2 << 4];
int grass = blockColors[BlockTypes.GRASS_BLOCK.getInternalId()];
if (grass == 0) {
return null;
}

View File

@ -25,12 +25,14 @@ import com.boydti.fawe.util.MainUtil;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.command.ClipboardCommands;
import com.sk89q.worldedit.command.FlattenedClipboardTransform;
import com.sk89q.worldedit.command.SchematicCommands;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.CuboidRegion;
@ -84,7 +86,7 @@ public class CuboidClipboard {
}
}
private final BlockArrayClipboard clipboard;
private BlockArrayClipboard clipboard;
private AffineTransform transform;
public Vector size;
@ -441,7 +443,14 @@ public class CuboidClipboard {
@Deprecated
public void saveSchematic(File path) throws IOException, DataException {
checkNotNull(path);
SchematicFormat.MCEDIT.save(this, path);
if (transform != null && !transform.isIdentity()) {
final FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform);
BlockArrayClipboard target = new BlockArrayClipboard(result.getTransformedRegion(), UUID.randomUUID());
target.setOrigin(clipboard.getOrigin());
Operations.completeLegacy(result.copyTo(target));
this.clipboard = target;
}
new Schematic(clipboard).save(path, ClipboardFormat.SPONGE_SCHEMATIC);
}
/**

View File

@ -1548,7 +1548,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
checkNotNull(region);
checkNotNull(block);
if (canBypassAll(region, false, true) && !block.hasNbtData()) {
return changes = queue.setBlocks((CuboidRegion) region, block.getInternalPropertiesId());
return changes = queue.setBlocks((CuboidRegion) region, block.getInternalId());
}
try {
if (hasExtraExtents()) {
@ -1584,8 +1584,8 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
if (pattern instanceof BlockPattern) {
return setBlocks(region, ((BlockPattern) pattern).getBlock());
}
if (pattern instanceof BaseBlock) {
return setBlocks(region, (BaseBlock) pattern);
if (pattern instanceof BlockStateHolder) {
return setBlocks(region, (BlockStateHolder) pattern);
}
final BlockReplace replace = new BlockReplace(EditSession.this, pattern);
final RegionVisitor visitor = new RegionVisitor(region, replace, queue instanceof MappedFaweQueue ? (MappedFaweQueue) queue : null);

View File

@ -19,19 +19,12 @@
package com.sk89q.worldedit.blocks;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.PlayerDirection;
import com.sk89q.worldedit.registry.state.PropertyGroup;
import com.sk89q.worldedit.registry.state.PropertyKey;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import jdk.nashorn.internal.ir.Block;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Block types.

View File

@ -62,7 +62,7 @@ public class MaskCommands extends MethodCommands {
}
@Command(
aliases = {"false"},
aliases = {"false", "#false"},
desc = "Always false"
)
public Mask falseMask(Extent extent) {
@ -70,7 +70,7 @@ public class MaskCommands extends MethodCommands {
}
@Command(
aliases = {"true"},
aliases = {"true", "#true"},
desc = "Always true"
)
public Mask trueMask(Extent extent) {
@ -262,7 +262,7 @@ public class MaskCommands extends MethodCommands {
}
@Command(
aliases = {"\\", "/", "#angle"},
aliases = {"\\", "/", "#angle", "#\\", "#/"},
desc = "Restrict to specific terrain angle",
help = "Restrict to specific terrain angle\n" +
"The -o flag will only overlay\n" +
@ -289,7 +289,7 @@ public class MaskCommands extends MethodCommands {
}
@Command(
aliases = {"(", ")", "#roc"},
aliases = {"(", ")", "#roc", "#(", "#)"},
desc = "Restrict to near specific terrain slope rate of change",
help = "Restrict to near specific terrain slope rate of change\n" +
"The -o flag will only overlay\n" +
@ -315,7 +315,7 @@ public class MaskCommands extends MethodCommands {
}
@Command(
aliases = {"^", "#extrema"},
aliases = {"^", "#extrema", "#^"},
desc = "Restrict to near specific terrain extrema",
help = "Restrict to near specific terrain extrema\n" +
"The -o flag will only overlay\n" +
@ -342,7 +342,7 @@ public class MaskCommands extends MethodCommands {
}
@Command(
aliases = {"{"},
aliases = {"{", "#{"},
desc = "Restricts blocks to within a specific radius range of the initial block",
usage = "<min> <max>",
min = 2,
@ -353,7 +353,7 @@ public class MaskCommands extends MethodCommands {
}
@Command(
aliases = {"|"},
aliases = {"|", "#|", "#side"},
desc = "sides with a specific number of other blocks",
usage = "<mask> <min> <max>",
min = 3,
@ -364,7 +364,7 @@ public class MaskCommands extends MethodCommands {
}
@Command(
aliases = {"~"},
aliases = {"~", "#~", "#adjacent"},
desc = "Adjacent to a specific number of other blocks",
usage = "<mask> [min=1] [max=8]",
min = 1,
@ -382,7 +382,7 @@ public class MaskCommands extends MethodCommands {
}
@Command(
aliases = {"<"},
aliases = {"<", "#<", "#below"},
desc = "below a specific block",
usage = "<mask>",
min = 1,
@ -394,7 +394,7 @@ public class MaskCommands extends MethodCommands {
}
@Command(
aliases = {">"},
aliases = {">", "#>", "#above"},
desc = "above a specific block",
usage = "<mask>",
min = 1,
@ -406,7 +406,7 @@ public class MaskCommands extends MethodCommands {
}
@Command(
aliases = {"$", "#biome"},
aliases = {"$", "#biome", "#$"},
desc = "in a specific biome",
help = "in a specific biome. For a list of biomes use //biomelist",
usage = "<biome>",
@ -418,7 +418,7 @@ public class MaskCommands extends MethodCommands {
}
@Command(
aliases = {"%"},
aliases = {"%", "#%", "#percent"},
desc = "percentage chance",
usage = "<chance>",
min = 1,
@ -430,7 +430,7 @@ public class MaskCommands extends MethodCommands {
}
@Command(
aliases = {"="},
aliases = {"=", "#=", "#expression"},
desc = "expression mask",
usage = "<expression>",
min = 1,
@ -444,7 +444,7 @@ public class MaskCommands extends MethodCommands {
}
@Command(
aliases = {"!", "#not", "#negate"},
aliases = {"!", "#not", "#negate", "#!"},
desc = "Negate another mask",
usage = "<mask>",
min = 1,

View File

@ -418,7 +418,7 @@ public class PatternCommands extends MethodCommands {
}
@Command(
aliases = {"="},
aliases = {"=", "#=", "#expression"},
desc = "Expression pattern: http://wiki.sk89q.com/wiki/WorldEdit/Expression_syntax",
usage = "<expression>",
min = 1,

View File

@ -382,11 +382,11 @@ public class SchematicCommands extends MethodCommands {
@Command(aliases = {"move", "m"}, usage = "<directory>", desc = "Move your loaded schematic", help = "Move your currently loaded schematics", min = 1, max = 1)
@CommandPermissions({"worldedit.schematic.move", "worldedit.schematic.move.other"})
public void move(final Player player, final LocalSession session, final CommandContext args) throws WorldEditException {
public void move(final Player player, final LocalSession session, String directory) throws WorldEditException {
final LocalConfiguration config = this.worldEdit.getConfiguration();
final File working = this.worldEdit.getWorkingDirectoryFile(config.saveDir);
final File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, player.getUniqueId().toString()) : working;
File destDir = new File(dir, args.getString(0));
File destDir = new File(dir, directory);
if (!MainUtil.isInSubDirectory(working, destDir)) {
player.printError("Directory " + destDir + " does not exist!");
return;

View File

@ -36,10 +36,8 @@ import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extension.platform.PlatformManager;
import com.sk89q.worldedit.extension.platform.*;
import java.io.IOException;
import java.net.URL;
import java.text.DateFormat;
@ -113,6 +111,7 @@ public class WorldEditCommands {
we.getPlatformManager().queryCapability(Capability.CONFIGURATION).reload();
we.getEventBus().post(new ConfigurationLoadEvent(we.getPlatformManager().queryCapability(Capability.CONFIGURATION).getConfiguration()));
Fawe.get().setupConfigs();
CommandManager.getInstance().register(we.getPlatformManager().queryCapability(Capability.USER_COMMANDS));
actor.print(BBC.getPrefix() + "Reloaded WorldEdit " + we.getVersion() + " and FAWE (" + Fawe.get().getVersion() + ")");
}

View File

@ -19,6 +19,7 @@
package com.sk89q.worldedit.extension.factory;
import com.boydti.fawe.command.SuggestInputParseException;
import com.boydti.fawe.jnbt.JSON2NBT;
import com.boydti.fawe.jnbt.NBTException;
import com.boydti.fawe.util.MathMan;
@ -26,6 +27,7 @@ import com.boydti.fawe.util.StringMan;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.blocks.MobSpawnerBlock;
@ -50,6 +52,11 @@ import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.registry.LegacyMapper;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Parses block input strings.
@ -283,8 +290,13 @@ public class DefaultBlockParser extends InputParser<BlockStateHolder> {
break;
}
}
if (!worldEdit.getPlatformManager().queryCapability(Capability.USER_COMMANDS).isValidMobType(mobName)) {
throw new NoMatchException("Unknown mob type '" + mobName + "'");
Platform capability = worldEdit.getPlatformManager().queryCapability(Capability.USER_COMMANDS);
if (!capability.isValidMobType(mobName)) {
final String finalMobName = mobName.toLowerCase();
throw new SuggestInputParseException("Unknown mob type '" + mobName + "'", mobName, () -> Stream.of(MobType.values())
.map(m -> m.getName().toLowerCase())
.filter(s -> s.startsWith(finalMobName))
.collect(Collectors.toList()));
}
return new MobSpawnerBlock(state, mobName);
} else {

View File

@ -1,11 +1,14 @@
package com.sk89q.worldedit.extension.factory;
import com.boydti.fawe.command.FaweParser;
import com.boydti.fawe.command.SuggestInputParseException;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.util.StringMan;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.util.command.*;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.command.MaskCommands;
import com.sk89q.worldedit.extension.input.InputParseException;
@ -17,14 +20,18 @@ import com.sk89q.worldedit.function.mask.*;
import com.sk89q.worldedit.internal.command.ActorAuthorizer;
import com.sk89q.worldedit.internal.command.WorldEditBinding;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.command.Dispatcher;
import com.sk89q.worldedit.util.command.SimpleDispatcher;
import com.sk89q.worldedit.util.command.parametric.ParametricBuilder;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class DefaultMaskParser extends FaweParser<Mask> {
private final Dispatcher dispatcher;
@ -50,11 +57,11 @@ public class DefaultMaskParser extends FaweParser<Mask> {
@Override
public Mask parseFromInput(String input, ParserContext context) throws InputParseException {
if (input.isEmpty()) return null;
if (input.isEmpty()) {
throw new SuggestInputParseException("No input provided", "", () -> Stream.concat(Stream.of("#", ",", "&"), BlockTypes.getNameSpaces().stream().map(n -> n + ":")).collect(Collectors.toList()));
}
Extent extent = Request.request().getExtent();
if (extent == null) extent = context.getExtent();
// List<Mask> intersection = new ArrayList<>();
// List<Mask> union = new ArrayList<>();
List<List<Mask>> masks = new ArrayList<>();
masks.add(new ArrayList<>());
@ -63,12 +70,12 @@ public class DefaultMaskParser extends FaweParser<Mask> {
if (actor != null) {
locals.put(Actor.class, actor);
}
//
try {
List<Map.Entry<ParseEntry, List<String>>> parsed = parse(input);
for (Map.Entry<ParseEntry, List<String>> entry : parsed) {
ParseEntry pe = entry.getKey();
String command = pe.input;
final String command = pe.input;
String full = pe.full;
Mask mask = null;
if (command.isEmpty()) {
mask = parseFromInput(StringMan.join(entry.getValue(), ','), context);
@ -79,76 +86,107 @@ public class DefaultMaskParser extends FaweParser<Mask> {
if (charMask && input.charAt(0) == '=') {
return parseFromInput(char0 + "[" + input.substring(1) + "]", context);
}
if (mask == null) {
// Legacy syntax
if (charMask) {
switch (char0) {
case '\\': //
case '/': //
case '{': //
case '$': //
case '%': {
command = command.substring(1);
String value = command + ((entry.getValue().isEmpty()) ? "" : "[" + StringMan.join(entry.getValue(), "][") + "]");
if (value.contains(":")) {
if (value.charAt(0) == ':') value.replaceFirst(":", "");
value = value.replaceAll(":", "][");
}
mask = parseFromInput(char0 + "[" + value + "]", context);
break;
if (char0 == '#') {
throw new SuggestInputParseException(new NoMatchException("Unkown mask: " + full + ", See: //masks"), full,
() -> {
if (full.length() == 1) return new ArrayList<>(dispatcher.getPrimaryAliases());
return dispatcher.getAliases().stream().filter(
s -> s.startsWith(command.toLowerCase())
).collect(Collectors.toList());
}
case '|':
case '~':
case '<':
case '>':
case '!':
input = input.substring(input.indexOf(char0) + 1);
mask = parseFromInput(char0 + "[" + input + "]", context);
if (actor != null) {
BBC.COMMAND_CLARIFYING_BRACKET.send(actor, char0 + "[" + input + "]");
}
return mask;
);
}
// Legacy syntax
if (charMask) {
switch (char0) {
case '\\': //
case '/': //
case '{': //
case '$': //
case '%': {
String value = command.substring(1) + ((entry.getValue().isEmpty()) ? "" : "[" + StringMan.join(entry.getValue(), "][") + "]");
if (value.contains(":")) {
if (value.charAt(0) == ':') value.replaceFirst(":", "");
value = value.replaceAll(":", "][");
}
mask = parseFromInput("#" + char0 + "[" + value + "]", context);
break;
}
}
if (mask == null) {
if (command.startsWith("[")) {
int end = command.lastIndexOf(']');
mask = parseFromInput(command.substring(1, end == -1 ? command.length() : end), context);
} else {
List<String> entries = entry.getValue();
try {
BlockMaskBuilder builder = new BlockMaskBuilder().addRegex(pe.full);
if (builder.isEmpty()) {
try {
context.setPreferringWildcard(true);
context.setRestricted(false);
BlockStateHolder block = worldEdit.getBlockFactory().parseFromInput(pe.full, context);
builder.add(block);
} catch (NoMatchException e) {
throw new NoMatchException(e.getMessage() + " See: //masks");
}
}
mask = builder.build(extent);
} catch (PatternSyntaxException regex) {
throw new InputParseException(regex.getMessage());
case '|':
case '~':
case '<':
case '>':
case '!':
input = input.substring(input.indexOf(char0) + 1);
mask = parseFromInput(char0 + "[" + input + "]", context);
if (actor != null) {
BBC.COMMAND_CLARIFYING_BRACKET.send(actor, char0 + "[" + input + "]");
}
return mask;
}
}
if (mask == null) {
if (command.startsWith("[")) {
int end = command.lastIndexOf(']');
mask = parseFromInput(command.substring(1, end == -1 ? command.length() : end), context);
} else {
List<String> entries = entry.getValue();
BlockMaskBuilder builder = new BlockMaskBuilder();
// if (StringMan.containsAny(full, "\\^$.|?+(){}<>~$!%^&*+-/"))
{
try {
builder.addRegex(full);
} catch (SuggestInputParseException rethrow) {
throw rethrow;
} catch (InputParseException ignore) {}
}
if (mask == null) {
context.setPreferringWildcard(true);
context.setRestricted(false);
BlockStateHolder block = worldEdit.getBlockFactory().parseFromInput(full, context);
builder.add(block);
mask = builder.build(extent);
}
}
}
} else {
List<String> args = entry.getValue();
if (!args.isEmpty()) {
command += " " + StringMan.join(args, " ");
String cmdArgs = ((args.isEmpty()) ? "" : " " + StringMan.join(args, " "));
try {
mask = (Mask) dispatcher.call(command + cmdArgs, locals, new String[0]);
} catch (SuggestInputParseException rethrow) {
throw rethrow;
} catch (Throwable e) {
throw SuggestInputParseException.of(e, full, () -> {
try {
List<String> suggestions = dispatcher.get(command).getCallable().getSuggestions(cmdArgs, locals);
if (suggestions.size() <= 2) {
for (int i = 0; i < suggestions.size(); i++) {
String suggestion = suggestions.get(i);
if (suggestion.indexOf(' ') != 0) {
String[] split = suggestion.split(" ");
suggestion = BBC.color("[" + StringMan.join(split, "][") + "]");
suggestions.set(i, suggestion);
}
}
}
return suggestions;
} catch (CommandException e1) {
throw new InputParseException(e1.getMessage());
} catch (Throwable e2) {
e2.printStackTrace();
throw new InputParseException(e2.getMessage());
}
});
}
mask = (Mask) dispatcher.call(command, locals, new String[0]);
}
if (pe.and) {
masks.add(new ArrayList<>());
}
masks.get(masks.size() - 1).add(mask);
}
} catch (InputParseException ignore) {
throw ignore;
} catch (InputParseException rethrow) {
throw rethrow;
} catch (Throwable e) {
e.printStackTrace();
throw new InputParseException(e.getMessage(), e);
@ -169,6 +207,4 @@ public class DefaultMaskParser extends FaweParser<Mask> {
return null;
}
}
}

View File

@ -1,6 +1,8 @@
package com.sk89q.worldedit.extension.factory;
import com.boydti.fawe.command.FaweParser;
import com.boydti.fawe.command.SuggestInputParseException;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.random.TrueRandom;
import com.boydti.fawe.util.StringMan;
import com.sk89q.minecraft.util.commands.CommandException;
@ -20,9 +22,13 @@ import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.util.command.Dispatcher;
import com.sk89q.worldedit.util.command.SimpleDispatcher;
import com.sk89q.worldedit.util.command.parametric.ParametricBuilder;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class HashTagPatternParser extends FaweParser<Pattern> {
private final Dispatcher dispatcher;
@ -47,7 +53,9 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
@Override
public Pattern parseFromInput(String input, ParserContext context) throws InputParseException {
if (input.isEmpty()) return null;
if (input.isEmpty()) {
throw new SuggestInputParseException("No input provided", "", () -> Stream.concat(Stream.of("#", ",", "&"), BlockTypes.getNameSpaces().stream().map(n -> n + ":")).collect(Collectors.toList()));
}
List<Double> chances = new ArrayList<>();
List<Pattern> patterns = new ArrayList<>();
final CommandLocals locals = new CommandLocals();
@ -58,7 +66,8 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
try {
for (Map.Entry<ParseEntry, List<String>> entry : parse(input)) {
ParseEntry pe = entry.getKey();
String command = pe.input;
final String command = pe.input;
String full = pe.full;
Pattern pattern = null;
double chance = 1;
if (command.isEmpty()) {
@ -70,11 +79,22 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
if (charMask && input.charAt(0) == '=') {
return parseFromInput(char0 + "[" + input.substring(1) + "]", context);
}
if (char0 == '#') {
throw new SuggestInputParseException(new NoMatchException("Unkown pattern: " + full + ", See: //patterns"), full,
() -> {
if (full.length() == 1) return new ArrayList<>(dispatcher.getPrimaryAliases());
return dispatcher.getAliases().stream().filter(
s -> s.startsWith(command.toLowerCase())
).collect(Collectors.toList());
}
);
}
if (charMask) {
switch (char0) {
case '$': {
command = command.substring(1);
String value = command + ((entry.getValue().isEmpty()) ? "" : "[" + StringMan.join(entry.getValue(), "][") + "]");
String value = command.substring(1) + ((entry.getValue().isEmpty()) ? "" : "[" + StringMan.join(entry.getValue(), "][") + "]");
if (value.contains(":")) {
if (value.charAt(0) == ':') value.replaceFirst(":", "");
value = value.replaceAll(":", "][");
@ -92,12 +112,12 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
int percentIndex = command.indexOf('%');
if (percentIndex != -1) { // Legacy percent pattern
chance = Expression.compile(command.substring(0, percentIndex)).evaluate();
command = command.substring(percentIndex + 1);
String value = command.substring(percentIndex + 1);
if (!entry.getValue().isEmpty()) {
if (!command.isEmpty()) command += " ";
command += StringMan.join(entry.getValue(), " ");
if (!value.isEmpty()) value += " ";
value += StringMan.join(entry.getValue(), " ");
}
pattern = parseFromInput(command, context);
pattern = parseFromInput(value, context);
} else { // legacy block pattern
try {
pattern = worldEdit.getBlockFactory().parseFromInput(pe.full, context);
@ -109,18 +129,45 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
}
} else {
List<String> args = entry.getValue();
if (!args.isEmpty()) {
command += " " + StringMan.join(args, " ");
String cmdArgs = ((args.isEmpty()) ? "" : " " + StringMan.join(args, " "));
try {
pattern = (Pattern) dispatcher.call(command + cmdArgs, locals, new String[0]);
} catch (SuggestInputParseException rethrow) {
throw rethrow;
} catch (Throwable e) {
throw SuggestInputParseException.of(e, full, () -> {
try {
List<String> suggestions = dispatcher.get(command).getCallable().getSuggestions(cmdArgs, locals);
if (suggestions.size() <= 2) {
for (int i = 0; i < suggestions.size(); i++) {
String suggestion = suggestions.get(i);
if (suggestion.indexOf(' ') != 0) {
String[] split = suggestion.split(" ");
suggestion = BBC.color("[" + StringMan.join(split, "][") + "]");
suggestions.set(i, suggestion);
}
}
}
return suggestions;
} catch (CommandException e1) {
throw new InputParseException(e1.getMessage());
} catch (Throwable e2) {
e2.printStackTrace();
throw new InputParseException(e2.getMessage());
}
});
}
pattern = (Pattern) dispatcher.call(command, locals, new String[0]);
}
if (pattern != null) {
patterns.add(pattern);
chances.add(chance);
}
}
} catch (CommandException | ExpressionException e) {
throw new RuntimeException(e);
} catch (InputParseException rethrow) {
throw rethrow;
} catch (Throwable e) {
e.printStackTrace();
throw new InputParseException(e.getMessage(), e);
}
if (patterns.isEmpty()) {
return null;

View File

@ -39,7 +39,6 @@ public final class MaskFactory extends AbstractFactory<Mask> {
*/
public MaskFactory(WorldEdit worldEdit) {
super(worldEdit);
parsers.add(new DefaultMaskParser(worldEdit));
}

View File

@ -39,9 +39,7 @@ public final class PatternFactory extends AbstractFactory<Pattern> {
*/
public PatternFactory(WorldEdit worldEdit) {
super(worldEdit);
parsers.add(new HashTagPatternParser(worldEdit));
parsers.add(new SingleBlockPatternParser(worldEdit));
}
}

View File

@ -334,7 +334,8 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override
public Location getBlockIn() {
return getLocation();
Location loc = getLocation();
return new Location(loc.getExtent(), loc.toBlockVector(), loc.getDirection());
}
@Override

View File

@ -48,8 +48,10 @@ import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
import com.sk89q.worldedit.function.factory.Deform;
import com.sk89q.worldedit.function.factory.Deform.Mode;
import com.sk89q.worldedit.internal.command.*;
import com.sk89q.worldedit.scripting.CommandScriptLoader;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.util.command.CallableProcessor;
import com.sk89q.worldedit.util.command.CommandCallable;
import com.sk89q.worldedit.util.command.Dispatcher;
import com.sk89q.worldedit.util.command.InvalidUsageException;
@ -184,13 +186,13 @@ public final class CommandManager {
* @param clazz The class containing all the sub command methods
* @param aliases The aliases to give the command
*/
public void registerCommands(Object clazz, Object processor, String... aliases) {
public void registerCommands(Object clazz, CallableProcessor processor, String... aliases) {
if (platform != null) {
if (aliases.length == 0) {
builder.registerMethodsAsCommands(dispatcher, clazz);
builder.registerMethodsAsCommands(dispatcher, clazz, processor);
} else {
DispatcherNode graph = new CommandGraph().builder(builder).commands();
graph = graph.registerMethods(clazz);
graph = graph.registerMethods(clazz, processor);
dispatcher.registerCommand(graph.graph().getDispatcher(), aliases);
}
platform.registerCommands(dispatcher);
@ -298,6 +300,13 @@ public final class CommandManager {
public void register(Platform platform) {
log.log(Level.FINE, "Registering commands with " + platform.getClass().getCanonicalName());
this.platform = null;
try {
new CommandScriptLoader().load();
} catch (Throwable e) {
e.printStackTrace();
}
LocalConfiguration config = platform.getConfiguration();
boolean logging = config.logCommands;

View File

@ -1,6 +1,5 @@
package com.sk89q.worldedit.extent.transform;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.extent.ResettableExtent;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.jnbt.ByteTag;
@ -10,29 +9,23 @@ import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.helper.MCDirections;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.registry.state.AbstractProperty;
import com.sk89q.worldedit.registry.state.DirectionalProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.block.*;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.registry.BlockRegistry;
import jdk.nashorn.internal.ir.Block;
import com.sk89q.worldedit.world.block.BlockTypes;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Transforms blocks themselves (but not their position) according to a

View File

@ -1,5 +1,6 @@
package com.sk89q.worldedit.function.mask;
import com.boydti.fawe.command.SuggestInputParseException;
import com.boydti.fawe.object.collection.FastBitSet;
import com.boydti.fawe.object.string.MutableCharSequence;
import com.boydti.fawe.util.StringMan;
@ -15,7 +16,10 @@ import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.*;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class BlockMaskBuilder {
private static final Operator GREATER = (a, b) -> a > b;
@ -30,41 +34,51 @@ public class BlockMaskBuilder {
boolean test(int left, int right);
}
public BlockMaskBuilder filterRegex(BlockType blockType, PropertyKey key, String regex) {
private boolean filterRegex(BlockType blockType, PropertyKey key, String regex) {
Property property = blockType.getProperty(key);
if (property == null) return this;
if (property == null) return false;
List values = property.getValues();
boolean result = false;
for (int i = 0; i < values.size(); i++) {
Object value = values.get(i);
if (!value.toString().matches(regex)) {
if (!value.toString().matches(regex) && has(blockType, property, i)) {
filter(blockType, property, i);
result = true;
}
}
return this;
return result;
}
private void filterOperator(BlockType blockType, PropertyKey key, Operator operator, CharSequence value) {
private boolean filterOperator(BlockType blockType, PropertyKey key, Operator operator, CharSequence value) {
Property property = blockType.getProperty(key);
if (property == null) return;
if (property == null) return false;
int index = property.getIndexFor(value);
List values = property.getValues();
boolean result = false;
for (int i = 0; i < values.size(); i++) {
if (!operator.test(index, i)) {
if (!operator.test(index, i) && has(blockType, property, i)) {
filter(blockType, property, i);
result = true;
}
}
return result;
}
private void filterRegexOrOperator(BlockType type, PropertyKey key, Operator operator, CharSequence value) {
private boolean filterRegexOrOperator(BlockType type, PropertyKey key, Operator operator, CharSequence value) {
boolean result = false;
if (!type.hasProperty(key)) {
if (operator == EQUAL) remove(type);
if (operator == EQUAL) {
result = bitSets[type.getInternalId()] != null;
remove(type);
}
} else if (value.length() == 0) {
} else if ((operator == EQUAL || operator == EQUAL_OR_NULL) && !StringMan.isAlphanumericUnd(value)) {
filterRegex(type, key, value.toString());
result = filterRegex(type, key, value.toString());
} else {
filterOperator(type, key, operator, value);
result = filterOperator(type, key, operator, value);
}
return result;
}
public BlockMaskBuilder addRegex(String input) throws InputParseException {
@ -90,8 +104,13 @@ public class BlockMaskBuilder {
add(myType);
}
}
if (blockTypeList.isEmpty()) {
throw new InputParseException("No block found for " + input);
}
if (blockTypeList.size() == 1) type = blockTypeList.get(0);
}
// Empty string
charSequence.setSubstring(0, 0);
PropertyKey key = null;
int length = input.length();
@ -109,13 +128,40 @@ public class BlockMaskBuilder {
case ']':
case ',': {
charSequence.setSubstring(last, i);
char firstChar = input.charAt(last + 1);
if (type != null) filterRegexOrOperator(type, key, operator, charSequence);
if (key == null && PropertyKey.get(charSequence) == null) suggest(input, charSequence.toString(), type != null ? Collections.singleton(type) : blockTypeList);
if (operator == null) throw new SuggestInputParseException("No operator for " + input, "", () -> Arrays.asList("=", "~", "!", "<", ">", "<=", ">="));
boolean filtered = false;
if (type != null) {
filtered = filterRegexOrOperator(type, key, operator, charSequence);
}
else {
for (BlockTypes myType : blockTypeList) {
filterRegexOrOperator(myType, key, operator, charSequence);
filtered |= filterRegexOrOperator(myType, key, operator, charSequence);
}
}
if (!filtered) {
String value = charSequence.toString();
final PropertyKey fKey = key;
Collection<BlockTypes> types = type != null ? Collections.singleton(type) : blockTypeList;
throw new SuggestInputParseException("No value for " + input, input, () -> {
HashSet<String> values = new HashSet<>();
types.forEach(t -> {
if (t.hasProperty(fKey)) {
Property p = t.getProperty(fKey);
for (int j = 0; j < p.getValues().size(); j++) {
if (has(t, p, j)) {
String o = p.getValues().get(j).toString();
if (o.startsWith(value)) values.add(o);
}
}
}
});
return new ArrayList<>(values);
});
}
// Reset state
key = null;
operator = null;
last = i + 1;
break;
}
@ -144,7 +190,11 @@ public class BlockMaskBuilder {
operator = extra ? GREATER_EQUAL : GREATER;
break;
}
if (charSequence.length() > 0) key = PropertyKey.get(charSequence);
if (charSequence.length() > 0 || key == null) {
key = PropertyKey.get(charSequence);
if (key == null)
suggest(input, charSequence.toString(), type != null ? Collections.singleton(type) : blockTypeList);
}
last = i + 1;
break;
}
@ -166,7 +216,24 @@ public class BlockMaskBuilder {
return this;
}
///// end test /////
private boolean has(BlockType type, Property property, int index) {
AbstractProperty prop = (AbstractProperty) property;
long[] states = bitSets[type.getInternalId()];
if (states == null) return false;
List values = prop.getValues();
int localI = index << prop.getBitOffset() >> BlockTypes.BIT_OFFSET;
return (states == BlockMask.ALL || FastBitSet.get(states, localI));
}
private void suggest(String input, String property, Collection<BlockTypes> finalTypes) throws InputParseException {
throw new SuggestInputParseException(input + " does not have: " + property, input, () -> {
Set<PropertyKey> keys = new HashSet<>();
finalTypes.forEach(t -> t.getProperties().stream().forEach(p -> keys.add(p.getKey())));
return keys.stream().map(p -> p.getId()).filter(p -> p.startsWith(property)).collect(Collectors.toList());
});
}
///// end internal /////
private long[][] bitSets;
@ -230,7 +297,9 @@ public class BlockMaskBuilder {
public BlockMaskBuilder filter(BlockType type) {
for (int i = 0; i < bitSets.length; i++) {
if (i != type.getInternalId()) bitSets[i] = null;
if (i != type.getInternalId()) {
bitSets[i] = null;
}
}
return this;
}

View File

@ -20,6 +20,7 @@
package com.sk89q.worldedit.internal.command;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.util.MathMan;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
@ -355,18 +356,7 @@ public class WorldEditBinding extends BindingHelper {
public BaseBiome getBiomeType(ArgumentStack context) throws ParameterException, WorldEditException {
String input = context.next();
if (input != null) {
Actor actor = context.getContext().getLocals().get(Actor.class);
World world;
if (actor instanceof Entity) {
Extent extent = ((Entity) actor).getExtent();
if (extent instanceof World) {
world = (World) extent;
} else {
throw new ParameterException("A world is required.");
}
} else {
throw new ParameterException("An entity is required.");
}
if (MathMan.isInteger(input)) return new BaseBiome(Integer.parseInt(input));
BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry();

View File

@ -21,6 +21,7 @@ package com.sk89q.worldedit.registry.state;
import com.sk89q.worldedit.util.Direction;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nullable;
@ -36,6 +37,7 @@ public class DirectionalProperty extends AbstractProperty<Direction> {
public DirectionalProperty(final String name, final List<Direction> values, int bitOffset) {
super(name, values, bitOffset);
this.map = new int[Direction.values().length];
Arrays.fill(this.map, -1);
for (int i = 0; i < values.size(); i++) {
this.map[values.get(i).ordinal()] = i;
}
@ -53,7 +55,9 @@ public class DirectionalProperty extends AbstractProperty<Direction> {
@Override
public int getIndexFor(CharSequence string) throws IllegalArgumentException {
return getIndex(Direction.get(string));
Direction dir = Direction.get(string);
if (dir == null) return -1;
return getIndex(dir);
}
@Nullable

View File

@ -51,7 +51,8 @@ public class EnumProperty extends AbstractProperty<String> {
@Override
public int getIndexFor(CharSequence string) throws IllegalArgumentException {
return offsets.get(string);
Integer value = offsets.get(string);
return value == null ? -1 : value;
}
@Nullable

View File

@ -0,0 +1,106 @@
package com.sk89q.worldedit.scripting;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.command.FaweParser;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.util.MainUtil;
import com.google.common.base.Charsets;
import com.google.common.base.Function;
import com.google.common.io.CharStreams;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.BrushProcessor;
import com.sk89q.worldedit.extension.factory.DefaultMaskParser;
import com.sk89q.worldedit.extension.factory.HashTagPatternParser;
import com.sk89q.worldedit.extension.platform.CommandManager;
import com.sk89q.worldedit.util.command.CallableProcessor;
import com.sk89q.worldedit.util.command.ProcessedCallable;
import com.sk89q.worldedit.util.command.parametric.FunctionParametricCallable;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
public class CommandScriptLoader {
private final NashornCraftScriptEngine engine;
private final String loader;
public CommandScriptLoader() throws IOException {
this.engine = new NashornCraftScriptEngine();
try (InputStream inputStream = WorldEdit.class.getResourceAsStream("/cs_adv.js")) {
this.loader = CharStreams.toString(new InputStreamReader(inputStream, Charsets.UTF_8));
}
}
/**
* Load all file commands
* @throws Throwable
*/
public void load() throws Throwable {
File commands = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.COMMANDS);
if (commands.exists()) {
for (File file : commands.listFiles()) add(new String[0], file);
}
}
private void add(String[] aliases, File file) throws Throwable {
if (file.isDirectory()) {
if (aliases.length == 0) {
String[] newAliases = new String[] {file.getName()};
for (File newFile : file.listFiles()) {
add(newAliases, newFile);
}
} else {
Fawe.debug("Ignoring nested directory: " + file);
}
} else {
String name = file.getName();
if (name.endsWith(".js")) {
Fawe.debug("Loading script: " + name);
List<FunctionParametricCallable> cmds = getCommands(file, Collections.emptyMap());
FaweParser parser = null;
if (aliases.length == 1) {
switch (aliases[0]) {
case "brush":
if (!cmds.isEmpty()) {
BrushProcessor processor = new BrushProcessor(WorldEdit.getInstance());
for (FunctionParametricCallable cmd : cmds) {
ProcessedCallable processed = new ProcessedCallable(cmd, processor);
CommandManager.getInstance().registerCommand(aliases, cmd.getCommand(), processed);
}
}
return;
case "patterns":
parser = FaweAPI.getParser(HashTagPatternParser.class);
break;
case "masks":
parser = FaweAPI.getParser(DefaultMaskParser.class);
break;
}
if (parser != null) {
for (FunctionParametricCallable cmd : cmds) {
parser.getDispatcher().registerCommand(cmd, cmd.getCommand().aliases());
}
return;
}
}
for (FunctionParametricCallable cmd : cmds) {
CommandManager.getInstance().registerCommand(aliases, cmd.getCommand(), cmd);
}
}
}
}
private List<FunctionParametricCallable> getCommands(File file, Map<String, Object> vars) throws Throwable {
String script = new String(Files.readAllBytes(file.toPath())) + loader;
return (List) engine.evaluate(script, file.getPath(), vars);
}
}

View File

@ -0,0 +1,79 @@
/*
* 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.scripting;
import com.boydti.fawe.Fawe;
import com.sk89q.worldedit.WorldEditException;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
import java.util.Map;
public class NashornCraftScriptEngine implements CraftScriptEngine {
private static NashornScriptEngineFactory FACTORY;
private int timeLimit;
@Override
public void setTimeLimit(int milliseconds) {
timeLimit = milliseconds;
}
@Override
public int getTimeLimit() {
return timeLimit;
}
@Override
public Object evaluate(String script, String filename, Map<String, Object> args) throws Throwable {
ClassLoader cl = Fawe.get().getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(cl);
synchronized (NashornCraftScriptEngine.class) {
if (FACTORY == null) FACTORY = new NashornScriptEngineFactory();
}
;
ScriptEngine engine = FACTORY.getScriptEngine("--language=es6");
SimpleBindings bindings = new SimpleBindings();
for (Map.Entry<String, Object> entry : args.entrySet()) {
bindings.put(entry.getKey(), entry.getValue());
}
try {
Object result = engine.eval(script, bindings);
return result;
} catch (Error e) {
e.printStackTrace();
throw new ScriptException(e.getMessage());
} catch (Throwable e) {
e.printStackTrace();
while (e.getCause() != null) {
e = e.getCause();
}
if (e instanceof WorldEditException) {
throw e;
}
throw e;
} finally {
}
}
}

View File

@ -72,6 +72,7 @@ public class SimpleDispatcher implements Dispatcher {
continue;
} else {
Fawe.debug("Replacing commands is currently undefined behavior: " + StringMan.getString(alias));
commands.put(lower, mapping);
continue;
}
}

View File

@ -86,8 +86,8 @@ public final class PrimitiveBindings extends BindingHelper {
* @throws ParameterException on error
*/
@BindingMatch(type = { Boolean.class, boolean.class },
behavior = BindingBehavior.CONSUMES,
consumedCount = 1)
behavior = BindingBehavior.CONSUMES,
consumedCount = 1)
public Boolean getBoolean(ArgumentStack context) throws ParameterException {
return context.nextBoolean();
}
@ -117,7 +117,6 @@ public final class PrimitiveBindings extends BindingHelper {
throw new ParameterException(String.format(
"Expected '%s' to be a number or valid math expression (error: %s)", input, e.getMessage()));
}
}
}

View File

@ -1,14 +1,14 @@
package com.sk89q.worldedit.util.command.parametric;
import com.boydti.fawe.command.SuggestInputParseException;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.util.chat.UsageMessage;
import com.sk89q.minecraft.util.commands.*;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.util.command.*;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
public abstract class AParametricCallable implements CommandCallable {
// private final ParametricBuilder builder;
@ -206,101 +206,95 @@ public abstract class AParametricCallable implements CommandCallable {
@Override
public List<String> getSuggestions(String arguments, CommandLocals locals) throws CommandException {
String[] split = ("ignored" + " " + arguments).split(" ", -1);
// &a<current> &f<next>
// &cerrors
CommandContext context = new CommandContext(split, getValueFlags(), !arguments.endsWith(" "), locals);
ContextArgumentStack scoped = new ContextArgumentStack(context);
SuggestionContext suggestable = context.getSuggestionContext();
List<String> suggestions = new ArrayList<>(2);
ParameterData parameter = null;
ParameterData[] parameters = getParameters();
String consumed = "";
// For /command -f |
// For /command -f flag|
if (suggestable.forFlag()) {
for (int i = 0; i < getParameters().length; i++) {
ParameterData parameter = getParameters()[i];
boolean hasSuggestion = false;
int maxConsumedI = 0; // The maximum argument index
int minConsumedI = 0; // The minimum argument that has been consumed
// Collect parameters
try {
for (;maxConsumedI < parameters.length; maxConsumedI++) {
parameter = parameters[maxConsumedI];
if (parameter.getBinding().getBehavior(parameter) != BindingBehavior.PROVIDES) {
// Parse the user input into a method argument
ArgumentStack usedArguments = getScopedContext(parameter, scoped);
if (parameter.getFlag() == suggestable.getFlag()) {
String prefix = context.getFlag(parameter.getFlag());
if (prefix == null) {
prefix = "";
}
// System.out.println("(0) Return get binding suggestions " + parameter + " | " + prefix);
return parameter.getBinding().getSuggestions(parameter, prefix);
}
}
// This should not happen
// System.out.println("(1) This should not happen");
return new ArrayList<String>();
}
int consumerIndex = 0;
ParameterData lastConsumer = null;
String lastConsumed = null;
for (int i = 0; i < getParameters().length; i++) {
ParameterData parameter = getParameters()[i];
if (parameter.getFlag() != null) {
continue; // We already handled flags
}
try {
scoped.mark();
parameter.getBinding().bind(parameter, scoped, true);
if (scoped.wasConsumed()) {
lastConsumer = parameter;
lastConsumed = context.getString(scoped.position() - 1);
consumerIndex++;
}
} catch (MissingParameterException e) {
// For /command value1 |value2
// For /command |value1 value2
if (suggestable.forHangingValue()) {
// System.out.println("(2) Return get binding dangling " + parameter + " | " + "");
return parameter.getBinding().getSuggestions(parameter, "");
} else {
// For /command value1| value2
if (lastConsumer != null) {
// System.out.println("(3) Return get consumed " + lastConsumer + " | " + lastConsumed);
return lastConsumer.getBinding().getSuggestions(lastConsumer, lastConsumed);
// For /command| value1 value2
// This should never occur
} else {
// System.out.println("(4) Invalid suggestion context");
throw new RuntimeException("Invalid suggestion context");
usedArguments.mark();
try {
parameter.getBinding().bind(parameter, usedArguments, false);
minConsumedI = maxConsumedI + 1;
} catch (Throwable e) {
while (e.getCause() != null && !(e instanceof ParameterException || e instanceof InvocationTargetException)) e = e.getCause();
consumed = usedArguments.reset();
// Not optional? Then we can't execute this command
if (!parameter.isOptional()) {
if (!(e instanceof MissingParameterException)) minConsumedI = maxConsumedI;
throw e;
}
}
}
} catch (ParameterException | InvocationTargetException e) {
SuggestInputParseException suggestion = SuggestInputParseException.get(e);
if (suggestion != null) {
// System.out.println("(5) Has suggestion " + suggestion.getSuggestions());
return suggestion.getSuggestions();
}
if (suggestable.forHangingValue()) {
String name = getDescription().getParameters().get(consumerIndex).getName();
// System.out.println("(6) Has dangling invalid " + name + " | " + e.getMessage());
throw new InvalidUsageException("For parameter '" + name + "': " + e.getMessage(), this);
} else {
// System.out.println("(7) HGet binding suggestions " + parameter + " | " + lastConsumed);
return parameter.getBinding().getSuggestions(parameter, "");
}
}
}
// For /command value1 value2 |
if (suggestable.forHangingValue()) {
// There's nothing that we can suggest because there's no more parameters
// to add on, and we can't change the previous parameter
// System.out.println("(7.1) No more parameters");
return new ArrayList<String>();
} else {
// For /command value1 value2|
if (lastConsumer != null) {
// System.out.println("(8) Get binding suggestions " + lastConsumer + " | " + lastConsumed);
return lastConsumer.getBinding().getSuggestions(lastConsumer, lastConsumed);
// This should never occur
if (minConsumedI >= maxConsumedI && (parameter == null || parameter.getType() == CommandContext.class)) checkUnconsumed(scoped);
} catch (MissingParameterException ignore) {
} catch (UnconsumedParameterException e) {
suggestions.add(BBC.color("&cToo many parameters! Unused parameters: " + e.getUnconsumed()));
} catch (ParameterException e) {
String name = parameter.getName();
suggestions.add(BBC.color("&cFor parameter '" + name + "': " + e.getMessage()));
} catch (InvocationTargetException e) {
SuggestInputParseException suggestion = SuggestInputParseException.get(e);
if (suggestion != null && !suggestion.getSuggestions().isEmpty()) {
hasSuggestion = true;
suggestions.addAll(suggestion.getSuggestions());
} else {
// System.out.println("(9) Invalid suggestion context");
throw new RuntimeException("Invalid suggestion context");
Throwable t = e;
while (t.getCause() != null) t = t.getCause();
String msg = t.getMessage();
String name = parameter.getName();
if (msg != null && !msg.isEmpty()) suggestions.add(BBC.color("&cFor parameter '" + name + "': " + msg));
}
} catch (Throwable t) {
t.printStackTrace();
throw new WrappedCommandException(t);
}
// If there's 1 or less suggestions already, then show parameter suggestion
if (!hasSuggestion && suggestions.size() <= 1) {
StringBuilder suggestion = new StringBuilder();
outer:
for (String prefix = ""; minConsumedI < parameters.length; minConsumedI++) {
parameter = parameters[minConsumedI];
if (parameter.getBinding().getBehavior(parameter) != BindingBehavior.PROVIDES) {
suggestion.append(prefix);
List<String> argSuggestions = parameter.getBinding().getSuggestions(parameter, consumed);
switch (argSuggestions.size()) {
case 0:
break;
case 1:
suggestion.append(argSuggestions.iterator().next());
break;
default:
suggestion.setLength(0);
suggestions.addAll(argSuggestions);
break outer;
}
consumed = "";
prefix = " ";
}
}
if (suggestion.length() != 0) suggestions.add(suggestion.toString());
}
return suggestions;
}
}

View File

@ -191,9 +191,11 @@ public class BindingHelper implements Binding {
char bracket = parameter.isOptional() ? '[' : '<';
char endBracket = StringMan.getMatchingBracket(bracket);
StringBuilder result = new StringBuilder();
result.append("\u00A75");
result.append(bracket);
result.append("\u00A7r");
if (parameter.getFlag() != null) {
result.append('-').append(parameter.getFlag()).append(' ');
result.append('-').append(parameter.getFlag()).append("\u00A75 \u00A7r");
}
result.append(parameter.getName());
if (parameter.getDefaultValue() != null) {
@ -203,7 +205,9 @@ public class BindingHelper implements Binding {
if (range != null) {
result.append('|').append(StringMan.prettyFormat(range.min())).append(",").append(StringMan.prettyFormat(range.max()));
}
result.append("\u00A75");
result.append(endBracket);
result.append("\u00A7r");
return Collections.singletonList(result.toString());
}
return new ArrayList<>();

View File

@ -139,7 +139,7 @@ public class ContextArgumentStack implements ArgumentStack {
*/
@Override
public String reset() {
String value = context.getString(markedIndex, index - 1);
String value = (index - 1 > markedIndex) ? context.getString(markedIndex, index - 1) : "";
index = markedIndex;
return value;
}

View File

@ -28,7 +28,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.thoughtworks.paranamer;
package com.sk89q.worldedit.util.command.parametric;
import com.thoughtworks.paranamer.CachingParanamer;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

View File

@ -31,27 +31,8 @@ public class FunctionParametricCallable extends AParametricCallable {
this.function = function;
this.group = group;
List<String> paramNames = new ArrayList<>();
List<String> typeStrings = new ArrayList<>();
List<Type> types = new ArrayList<>();
List<Object[]> paramParsables = new ArrayList<>();
{
boolean checkType = false;
for (String argument : arguments) {
if (checkType) {
typeStrings.set(typeStrings.size() - 1, argument);
} else {
checkType = false;
if (argument.equals("=")) {
checkType = true;
} else if (argument.length() == 1 && command.flags().contains(argument)) {
typeStrings.add("java.lang.Boolean");
paramNames.add(argument);
} else {
typeStrings.add("java.lang.String");
paramNames.add(argument);
}
}
}
Map<Type, Binding> bindings = builder.getBindings();
Map<String, Type> unqualified = new HashMap<>();
for (Map.Entry<Type, Binding> entry : bindings.entrySet()) {
@ -60,14 +41,46 @@ public class FunctionParametricCallable extends AParametricCallable {
unqualified.put(typeStr, type);
unqualified.put(typeStr.substring(typeStr.lastIndexOf('.') + 1), type);
}
for (String typeStr : typeStrings) {
Type type = unqualified.get(typeStr);
if (type == null) type = unqualified.get("java.lang.String");
types.add(type);
{
Object[] param = null; // name | type | optional value
boolean checkEq = false;
int checkEqI = 0;
for (int i = 0; i < arguments.size(); i++) {
String arg = arguments.get(i);
if (arg.equals("=")) {
checkEqI++;
checkEq = true;
} else if (param == null || !checkEq) {
if (param != null) paramParsables.add(param);
param = new Object[3];
param[0] = arg;
if (arg.length() == 1 && command.flags().contains(arg)) {
param[1] = Boolean.class;
} else {
param[1] = String.class;
}
param[2] = null;
checkEqI = 0;
checkEq = false;
} else {
if (checkEqI == 1) {
param[1] = unqualified.getOrDefault(arg, String.class);
checkEq = false;
}
else if (checkEqI == 2) {
char c = arg.charAt(0);
if (c == '\'' || c == '"') arg = arg.substring(1, arg.length() - 1);
param[2] = arg;
checkEqI = 0;
checkEq = false;
}
}
}
if (param != null) paramParsables.add(param);
}
}
parameters = new ParameterData[paramNames.size()];
parameters = new ParameterData[paramParsables.size()];
List<Parameter> userParameters = new ArrayList<Parameter>();
// This helps keep tracks of @Nullables that appear in the middle of a list
@ -75,20 +88,25 @@ public class FunctionParametricCallable extends AParametricCallable {
int numOptional = 0;
//
// Go through each parameter
for (int i = 0; i < types.size(); i++) {
Type type = types.get(i);
for (int i = 0; i < paramParsables.size(); i++) {
Object[] parsable = paramParsables.get(i);
String paramName = (String) parsable[0];
Type type = (Type) parsable[1];
String optional = (String) parsable[2];
ParameterData parameter = new ParameterData();
parameter.setType(type);
parameter.setModifiers(new Annotation[0]);
String paramName = paramNames.get(i);
boolean flag = paramName.length() == 1 && command.flags().contains(paramName);
if (flag) {
parameter.setFlag(paramName.charAt(0), type != boolean.class && type != Boolean.class);
}
// TODO switch / Optional / Search for annotations /
if (optional != null) {
parameter.setOptional(true);
if (!optional.equalsIgnoreCase("null")) parameter.setDefaultValue(new String[]{optional});
}
parameter.setName(paramName);
@ -256,7 +274,6 @@ public class FunctionParametricCallable extends AParametricCallable {
// postInvoke handlers
{
}
return result;
} catch (MissingParameterException e) {

View File

@ -45,7 +45,6 @@ import com.sk89q.worldedit.util.command.ProcessedCallable;
import com.sk89q.worldedit.util.command.binding.PrimitiveBindings;
import com.sk89q.worldedit.util.command.binding.StandardBindings;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.thoughtworks.paranamer.FaweParanamer;
import com.thoughtworks.paranamer.Paranamer;
import java.lang.reflect.Method;
import java.lang.reflect.Type;

View File

@ -146,7 +146,7 @@ public class StringArgumentStack implements ArgumentStack {
*/
@Override
public String reset() {
String value = context.getString(markedIndex, index - 1);
String value = (index - 1 > markedIndex) ? context.getString(markedIndex, index - 1) : "";
index = markedIndex;
return value;
}

View File

@ -20,25 +20,27 @@
package com.sk89q.worldedit.world.block;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.command.SuggestInputParseException;
import com.boydti.fawe.object.string.MutableCharSequence;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.Maps;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.TileEntityBlock;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.SingleBlockStateMask;
import com.sk89q.worldedit.function.pattern.FawePattern;
import com.sk89q.worldedit.registry.state.AbstractProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.registry.state.PropertyKey;
import javax.annotation.Nullable;
import java.util.*;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* An immutable class that represents the state a block can be in.
@ -60,7 +62,7 @@ public class BlockState implements BlockStateHolder<BlockState> {
* @return BlockState
*/
@Deprecated
public static BlockState get(int combinedId) {
public static BlockState get(int combinedId) throws InputParseException {
return BlockTypes.getFromStateId(combinedId).withStateId(combinedId);
}
@ -69,7 +71,7 @@ public class BlockState implements BlockStateHolder<BlockState> {
* @param state String e.g. minecraft:water[level=4]
* @return BlockState
*/
public static BlockState get(String state) {
public static BlockState get(String state) throws InputParseException {
return get(null, state);
}
@ -80,7 +82,7 @@ public class BlockState implements BlockStateHolder<BlockState> {
* @param state String e.g. minecraft:water[level=4]
* @return BlockState
*/
public static BlockState get(@Nullable BlockType type, String state) {
public static BlockState get(@Nullable BlockType type, String state) throws InputParseException {
return get(type, state, 0);
}
@ -91,7 +93,7 @@ public class BlockState implements BlockStateHolder<BlockState> {
* @param state String e.g. minecraft:water[level=4]
* @return BlockState
*/
public static BlockState get(@Nullable BlockType type, String state, int propId) {
public static BlockState get(@Nullable BlockType type, String state, int propId) throws InputParseException {
int propStrStart = state.indexOf('[');
if (type == null) {
CharSequence key;
@ -104,6 +106,14 @@ public class BlockState implements BlockStateHolder<BlockState> {
key = charSequence;
}
type = BlockTypes.get(key);
if (type == null) {
String input = key.toString();
throw new SuggestInputParseException("Unkown block for " + input, input, () -> Stream.of(BlockTypes.values)
.filter(b -> b.getId().contains(input))
.map(e1 -> e1.getId())
.collect(Collectors.toList())
);
}
}
if (propStrStart == -1) {
return type.getDefaultState();
@ -111,6 +121,7 @@ public class BlockState implements BlockStateHolder<BlockState> {
List<? extends Property> propList = type.getProperties();
if (state.charAt(state.length() - 1) != ']') state = state + "]";
MutableCharSequence charSequence = MutableCharSequence.getTemporal();
charSequence.setString(state);
@ -133,13 +144,36 @@ public class BlockState implements BlockStateHolder<BlockState> {
switch (c) {
case ']':
case ',': {
charSequence.setSubstring(last, i);
if (property != null) {
charSequence.setSubstring(last, i);
int index = property.getIndexFor(charSequence);
if (index == -1) {
String input = charSequence.toString();
List<Object> values = property.getValues();
throw new SuggestInputParseException("No value: " + input + " for " + type, input, () ->
values.stream()
.map(v -> v.toString())
.filter(v -> v.startsWith(input))
.collect(Collectors.toList()));
}
stateId = property.modifyIndex(stateId, index);
} else {
Fawe.debug("Invalid property " + type + " | " + charSequence);
// suggest
PropertyKey key = PropertyKey.get(charSequence);
if (key == null || !type.hasProperty(key)) {
// Suggest property
String input = charSequence.toString();
BlockType finalType = type;
throw new SuggestInputParseException("Invalid property " + type + " | " + input, input, () ->
finalType.getProperties().stream()
.map(p -> p.getName())
.filter(p -> p.startsWith(input))
.collect(Collectors.toList()));
} else {
throw new SuggestInputParseException("No operator for " + state, "", () -> Arrays.asList("="));
}
}
property = null;
last = i + 1;
break;
}

View File

@ -19,6 +19,7 @@
package com.sk89q.worldedit.world.block;
import com.boydti.fawe.command.SuggestInputParseException;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.worldedit.Vector;
@ -41,6 +42,7 @@ import com.sk89q.worldedit.world.registry.LegacyMapper;
import javax.annotation.Nullable;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Stores a list of common Block String IDs.
@ -946,6 +948,7 @@ public enum BlockTypes implements BlockType {
private static final Map<String, BlockTypes> $REGISTRY = new HashMap<>();
private static int $LENGTH;
public static final BlockTypes[] values;
private static final Set<String> $NAMESPACES = new LinkedHashSet<String>();
static {
try {
@ -979,8 +982,9 @@ public enum BlockTypes implements BlockType {
}
}
public static BlockTypes parse(String input) throws InputParseException {
input = input.toLowerCase();
public static BlockTypes parse(final String type) throws InputParseException {
final String inputLower = type.toLowerCase();
String input = inputLower;
if (!input.split("\\[", 2)[0].contains(":")) input = "minecraft:" + input;
BlockTypes result = $REGISTRY.get(input);
@ -991,7 +995,12 @@ public enum BlockTypes implements BlockType {
if (block != null) return block.getBlockType();
} catch (NumberFormatException e) {
} catch (IndexOutOfBoundsException e) {}
throw new InputParseException("Unkown block for " + input);
throw new SuggestInputParseException("Unkown block for " + inputLower, inputLower, () -> Stream.of(BlockTypes.values)
.filter(b -> b.getId().contains(inputLower))
.map(e1 -> e1.getId())
.collect(Collectors.toList())
);
}
private static BlockTypes register(final String id) {
@ -1014,9 +1023,15 @@ public enum BlockTypes implements BlockType {
existing.init(id, internalId);
if (typeName.startsWith("minecraft:")) $REGISTRY.put(typeName.substring(10), existing);
$REGISTRY.put(typeName, existing);
String nameSpace = typeName.substring(0, typeName.indexOf(':'));
$NAMESPACES.add(nameSpace);
return existing;
}
public static Set<String> getNameSpaces() {
return $NAMESPACES;
}
public static final @Nullable BlockTypes get(final String id) {
return $REGISTRY.get(id);
}