Various minor
JavaScript-API Allow command replacing Tweak primary thread checks Tab completion Schematic resolving help tweaks optimize change set fix color brush
This commit is contained in:
parent
0021ab0d61
commit
beb2e0e1b0
@ -53,7 +53,6 @@ apply plugin: 'com.github.johnrengelman.shadow'
|
||||
shadowJar {
|
||||
dependencies {
|
||||
include(dependency('com.github.luben:zstd-jni:1.1.1'))
|
||||
// include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('co.aikar:fastutil-lite:1.0'))
|
||||
include(dependency(':core'))
|
||||
}
|
||||
|
@ -627,6 +627,11 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
return ((BlocksHubBukkit) blocksHubPlugin).getApi();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMainThread() {
|
||||
return Bukkit.isPrimaryThread();
|
||||
}
|
||||
|
||||
private Version version = null;
|
||||
|
||||
public Version getVersion() {
|
||||
|
@ -68,7 +68,7 @@ public class AsyncChunk implements Chunk {
|
||||
|
||||
@Override
|
||||
public ChunkSnapshot getChunkSnapshot(boolean includeMaxblocky, boolean includeBiome, boolean includeBiomeTempRain) {
|
||||
if (Thread.currentThread() == Fawe.get().getMainThread()) {
|
||||
if (Fawe.isMainThread()) {
|
||||
return world.getChunkAt(x, z).getChunkSnapshot(includeMaxblocky, includeBiome, includeBiomeTempRain);
|
||||
}
|
||||
return whenLoaded(new RunnableVal<ChunkSnapshot>() {
|
||||
@ -80,7 +80,7 @@ public class AsyncChunk implements Chunk {
|
||||
}
|
||||
|
||||
private <T> T whenLoaded(RunnableVal<T> task) {
|
||||
if (Thread.currentThread() == Fawe.get().getMainThread()) {
|
||||
if (Fawe.isMainThread()) {
|
||||
task.run();
|
||||
return task.value;
|
||||
}
|
||||
|
@ -201,6 +201,11 @@ public class Fawe {
|
||||
* @param s
|
||||
*/
|
||||
public static void debug(Object s) {
|
||||
Actor actor = Request.request().getActor();
|
||||
if (actor != null && actor.isPlayer()) {
|
||||
actor.print(BBC.color(BBC.PREFIX.original() + " " + s));
|
||||
return;
|
||||
}
|
||||
debugPlain(BBC.PREFIX.original() + " " + s);
|
||||
}
|
||||
|
||||
@ -729,7 +734,7 @@ public class Fawe {
|
||||
}
|
||||
|
||||
public static boolean isMainThread() {
|
||||
return INSTANCE != null ? INSTANCE.thread == Thread.currentThread() : true;
|
||||
return INSTANCE != null ? imp().isMainThread() : true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,4 +65,8 @@ public interface IFawe {
|
||||
public default FormBuilder getFormBuilder() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default boolean isMainThread() {
|
||||
return Fawe.get().getMainThread() == Thread.currentThread();
|
||||
}
|
||||
}
|
||||
|
@ -6,11 +6,8 @@ import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.internal.registry.InputParser;
|
||||
import com.sk89q.worldedit.util.command.Dispatcher;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public abstract class FaweParser<T> extends InputParser<T> {
|
||||
protected FaweParser(WorldEdit worldEdit) {
|
||||
@ -28,27 +25,13 @@ 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;
|
||||
}
|
||||
|
||||
protected static class ParseEntry {
|
||||
public boolean and;
|
||||
public String input;
|
||||
public String full;
|
||||
|
||||
public ParseEntry(String input, boolean type) {
|
||||
public ParseEntry(String full, String input, boolean type) {
|
||||
this.full = full;
|
||||
this.input = input;
|
||||
this.and = type;
|
||||
}
|
||||
@ -59,66 +42,54 @@ public abstract class FaweParser<T> extends InputParser<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public List<Map.Entry<ParseEntry, List<String>>> parse(String command) 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> args = new ArrayList<>();
|
||||
int len = command.length();
|
||||
String current = null;
|
||||
int end = -1;
|
||||
boolean newEntry = true;
|
||||
for (int i = 0; i < len; i++) {
|
||||
int prefix = 0;
|
||||
boolean or = false;
|
||||
char c = command.charAt(i);
|
||||
if (i < end) continue;
|
||||
List<String> inputs = new ArrayList<>();
|
||||
List<Boolean> and = new ArrayList<>();
|
||||
int last = 0;
|
||||
outer:
|
||||
for (int i = 0; i < toParse.length(); i++) {
|
||||
char c = toParse.charAt(i);
|
||||
switch (c) {
|
||||
case ',':
|
||||
case '&':
|
||||
or = true;
|
||||
case ',': {
|
||||
prefix = 1;
|
||||
if (current == null) {
|
||||
throw new InputParseException("Duplicate separator");
|
||||
String result = toParse.substring(last, i);
|
||||
if (!result.isEmpty()) {
|
||||
inputs.add(result);
|
||||
and.add(c == '&');
|
||||
} else {
|
||||
throw new InputParseException("Invalid dangling character " + c);
|
||||
}
|
||||
newEntry = true;
|
||||
break;
|
||||
}
|
||||
case '[': {
|
||||
int depth = 0;
|
||||
end = len;
|
||||
loop:
|
||||
for (int j = i + 1; j < len; j++) {
|
||||
char c2 = command.charAt(j);
|
||||
switch (c2) {
|
||||
case '[':
|
||||
depth++;
|
||||
continue;
|
||||
case ']':
|
||||
if (depth-- <= 0) {
|
||||
end = j;
|
||||
break loop;
|
||||
}
|
||||
last = i + 1;
|
||||
continue outer;
|
||||
default:
|
||||
if (StringMan.getMatchingBracket(c) != c) {
|
||||
int next = StringMan.findMatchingBracket(toParse, i);
|
||||
if (next != -1) {
|
||||
i = next;
|
||||
} else {
|
||||
toParse += "]";
|
||||
i = toParse.length();
|
||||
}
|
||||
continue outer;
|
||||
}
|
||||
String arg = command.substring(i + 1, end);
|
||||
args.add(arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (newEntry) {
|
||||
newEntry = false;
|
||||
int index = StringMan.indexOf(command, Math.max(i, end) + prefix, '[', '&', ',');
|
||||
if (index < 0) index = len;
|
||||
end = index;
|
||||
current = command.substring(i + prefix, end);
|
||||
if (prefix == 1) args = new ArrayList<>();
|
||||
ParseEntry entry = new ParseEntry(current, or);
|
||||
keys.add(new AbstractMap.SimpleEntry<>(entry, args));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < keys.size() - 1; i++) { // Apply greedy and
|
||||
if (keys.get(i + 1).getKey().and) {
|
||||
keys.get(i).getKey().and = true;
|
||||
inputs.add(toParse.substring(last, toParse.length()));
|
||||
for (int i = 0; i < inputs.size(); i++) {
|
||||
String full = inputs.get(i);
|
||||
String command = full;
|
||||
List<String> args = new ArrayList<>();
|
||||
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);
|
||||
args.add(arg);
|
||||
command = full.substring(0, startPos);
|
||||
}
|
||||
Collections.reverse(args);
|
||||
ParseEntry entry = new ParseEntry(full, command, i > 0 ? and.get(i - 1) : false);
|
||||
keys.add(new AbstractMap.SimpleEntry<>(entry, args));
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
@ -2,87 +2,87 @@ 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 SuggestSupplier<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, SuggestSupplier<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, SuggestSupplier<List<String>> getSuggestions) {
|
||||
InputParseException e = find(other);
|
||||
if (e != null) return of(e, prefix, getSuggestions);
|
||||
return of(new InputParseException(other.getMessage()), prefix, getSuggestions);
|
||||
}
|
||||
|
||||
public static SuggestInputParseException of(InputParseException other, String prefix, SuggestSupplier<List<String>> getSuggestions) {
|
||||
if (other instanceof SuggestInputParseException) return (SuggestInputParseException) other;
|
||||
return new SuggestInputParseException(other, prefix, getSuggestions);
|
||||
}
|
||||
|
||||
public SuggestInputParseException(InputParseException other, String prefix, SuggestSupplier<List<String>> getSuggestions) {
|
||||
super(other.getMessage());
|
||||
checkNotNull(getSuggestions);
|
||||
checkNotNull(other);
|
||||
this.cause = other;
|
||||
this.getSuggestions = getSuggestions;
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public interface SuggestSupplier<T> {
|
||||
T get() throws InputParseException;
|
||||
}
|
||||
|
||||
public static InputParseException find(Throwable e) {
|
||||
do {
|
||||
if (e instanceof InputParseException) return (InputParseException) e;
|
||||
e = e.getCause();
|
||||
}
|
||||
while (e != null);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static SuggestInputParseException get(Throwable 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);
|
||||
|
||||
public List<String> getSuggestions() throws InputParseException {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,47 @@ public class Commands {
|
||||
}
|
||||
}
|
||||
|
||||
public static Command fromArgs(String[] aliases, String usage, String desc, int min, int max, String flags, String help, boolean queued /* ignored */) {
|
||||
return new Command() {
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return Command.class;
|
||||
}
|
||||
@Override
|
||||
public String[] aliases() {
|
||||
return aliases;
|
||||
}
|
||||
@Override
|
||||
public String usage() {
|
||||
return usage;
|
||||
}
|
||||
@Override
|
||||
public String desc() {
|
||||
return desc;
|
||||
}
|
||||
@Override
|
||||
public int min() {
|
||||
return min;
|
||||
}
|
||||
@Override
|
||||
public int max() {
|
||||
return max;
|
||||
}
|
||||
@Override
|
||||
public String flags() {
|
||||
return flags;
|
||||
}
|
||||
@Override
|
||||
public String help() {
|
||||
return help;
|
||||
}
|
||||
@Override
|
||||
public boolean anyFlags() {
|
||||
return !(flags.isEmpty() || flags.matches("[a-z]+"));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Command translate(Class clazz, final Command command) {
|
||||
if (cmdConfig == null || command instanceof TranslatedCommand) {
|
||||
return command;
|
||||
|
@ -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")
|
||||
|
@ -21,10 +21,9 @@ import com.sk89q.worldedit.blocks.BlockMaterial;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import com.sk89q.worldedit.world.registry.BundledBlockData;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.UUID;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -409,7 +408,7 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, CHUNKSECTIONS, SECTION> impl
|
||||
if (chunk != null) {
|
||||
return chunk;
|
||||
}
|
||||
boolean sync = Thread.currentThread() == Fawe.get().getMainThread();
|
||||
boolean sync = Fawe.isMainThread();
|
||||
if (sync) {
|
||||
return loadChunk(getWorld(), cx, cz, true);
|
||||
} else if (getSettings().HISTORY.CHUNK_WAIT_MS > 0) {
|
||||
|
@ -265,30 +265,34 @@ public abstract class FaweChangeSet implements ChangeSet {
|
||||
int bz = cz << 4;
|
||||
synchronized (FaweChangeSet.this) {
|
||||
// Biome changes
|
||||
if (previous.getBiomeArray() != null) {
|
||||
byte[] previousBiomes = previous.getBiomeArray();
|
||||
{
|
||||
byte[] nextBiomes = next.getBiomeArray();
|
||||
int index = 0;
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int zz = bz + z;
|
||||
for (int x = 0; x < 16; x++) {
|
||||
byte idFrom = previousBiomes[index];
|
||||
byte idTo = nextBiomes[index];
|
||||
if (idFrom != idTo && idTo != 0) {
|
||||
addBiomeChange(bx + x, zz, FaweCache.getBiome(idFrom & 0xFF), FaweCache.getBiome(idTo & 0xFF));
|
||||
if (nextBiomes != null) {
|
||||
byte[] previousBiomes = previous.getBiomeArray();
|
||||
if (previousBiomes != null) {
|
||||
|
||||
int index = 0;
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int zz = bz + z;
|
||||
for (int x = 0; x < 16; x++) {
|
||||
byte idFrom = previousBiomes[index];
|
||||
byte idTo = nextBiomes[index];
|
||||
if (idFrom != idTo && idTo != 0) {
|
||||
addBiomeChange(bx + x, zz, FaweCache.getBiome(idFrom & 0xFF), FaweCache.getBiome(idTo & 0xFF));
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
// TODO
|
||||
}
|
||||
// Block changes
|
||||
for (int layer = 0; layer < layers; layer++) {
|
||||
char[] currentLayer = next.getIdArray(layer);
|
||||
char[] previousLayer = previous.getIdArray(layer);
|
||||
if (currentLayer == null) {
|
||||
continue;
|
||||
}
|
||||
char[] previousLayer = previous.getIdArray(layer);
|
||||
int startY = layer << 4;
|
||||
int index = 0;
|
||||
for (int y = 0; y < 16; y++) {
|
||||
|
@ -24,7 +24,7 @@ public class SummedColorTable {
|
||||
this.hasAlpha = new int[raw.length];
|
||||
this.alpha = calculateAlpha ? new long[raw.length] : null;
|
||||
this.alphaInverse = calculateAlpha ? new float[256] : null;
|
||||
this.areaInverses = new float[Character.MAX_VALUE];
|
||||
this.areaInverses = new float[1024 * 1024];
|
||||
for (int i = 0; i < areaInverses.length; i++) {
|
||||
areaInverses[i] = 1f / (i + 1);
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@ -123,6 +125,12 @@ public class NullExtent extends FaweRegionExtent {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Operation commit() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
|
||||
throw new FaweException(reason);
|
||||
|
@ -28,8 +28,7 @@ public class StripNBTExtent extends AbstractDelegateExtent {
|
||||
*/
|
||||
public StripNBTExtent(Extent extent, Set<String> strip) {
|
||||
super(extent);
|
||||
this.
|
||||
strip = strip.toArray(new String[strip.size()]);
|
||||
this.strip = strip.toArray(new String[strip.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -48,7 +48,7 @@ public class AngleColorPattern extends DataAnglePattern {
|
||||
int height = extent.getNearestSurfaceTerrainBlock(x, z, y, 0, maxY);
|
||||
if (height > 0) {
|
||||
BaseBlock below = extent.getLazyBlock(x, height - 1, z);
|
||||
if (FaweCache.canPassThrough(block.getId(), block.getData())) {
|
||||
if (FaweCache.canPassThrough(below.getId(), below.getData())) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ public class StructureFormat implements ClipboardReader, ClipboardWriter {
|
||||
Map<String, Tag> entityEntryMap = entityEntry.getValue();
|
||||
ListTag posTag = (ListTag) entityEntryMap.get("pos");
|
||||
CompoundTag nbtTag = (CompoundTag) entityEntryMap.get("nbt");
|
||||
String id = ((StringTag) entityEntryMap.get("Id")).getValue();
|
||||
String id = nbtTag.getString("Id");
|
||||
Location location = NBTConversions.toLocation(clipboard, posTag, nbtTag.getListTag("Rotation"));
|
||||
if (!id.isEmpty()) {
|
||||
BaseEntity state = new BaseEntity(id, nbtTag);
|
||||
|
@ -585,7 +585,7 @@ public class MainUtil {
|
||||
long ratio = total / compressedSize;
|
||||
long saved = total - compressedSize;
|
||||
|
||||
if (ratio > 3 && Thread.currentThread() != Fawe.get().getMainThread() && actor != null) {
|
||||
if (ratio > 3 && !Fawe.isMainThread() && actor != null) {
|
||||
BBC.COMPRESSED.send(actor, saved, ratio);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -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,85 @@ 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);
|
||||
if (lookC == startC) return -1;
|
||||
boolean forward = isBracketForwards(startC);
|
||||
int increment = forward ? 1 : -1;
|
||||
int end = forward ? sequence.length() : -1;
|
||||
int count = 0;
|
||||
for (int i = index + increment; i != end; i += increment) {
|
||||
char c = sequence.charAt(i);
|
||||
if (c == startC) {
|
||||
count++;
|
||||
} else if (c == lookC && count-- == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static String prettyFormat(double d) {
|
||||
if (d == Double.MIN_VALUE) return "-∞";
|
||||
if (d == Double.MAX_VALUE) return "∞";
|
||||
if(d == (long) d) return String.format("%d",(long)d);
|
||||
else return String.format("%s",d);
|
||||
}
|
||||
|
||||
public static boolean isBracketForwards(char c) {
|
||||
switch (c) {
|
||||
case '[':
|
||||
case '(':
|
||||
case '{':
|
||||
case '<':
|
||||
return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static char getMatchingBracket(char c) {
|
||||
switch (c) {
|
||||
case '[': return ']';
|
||||
case '(': return ')';
|
||||
case '{': return '}';
|
||||
case '<': return '>';
|
||||
case ']': return '[';
|
||||
case ')': return '(';
|
||||
case '}': return '{';
|
||||
case '>': return '<';
|
||||
default: return c;
|
||||
}
|
||||
}
|
||||
|
||||
public static int parseInt(CharSequence string) {
|
||||
int val = 0;
|
||||
boolean neg = false;
|
||||
int numIndex = 1;
|
||||
int len = string.length();
|
||||
outer:
|
||||
for (int i = len - 1; i >= 0; i--) {
|
||||
char c = string.charAt(i);
|
||||
switch (c) {
|
||||
case '-':
|
||||
val = -val;
|
||||
break;
|
||||
default:
|
||||
val = val + (c - 48) * numIndex;
|
||||
numIndex *= 10;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
public static String removeFromSet(final String string, final Collection<String> replacements) {
|
||||
final StringBuilder sb = new StringBuilder(string);
|
||||
int size = string.length();
|
||||
@ -189,7 +270,7 @@ public class StringMan {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isAlphanumericUnd(final String str) {
|
||||
public static boolean isAlphanumericUnd(final CharSequence str) {
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
final char c = str.charAt(i);
|
||||
if ((c < 0x30) || ((c >= 0x3a) && (c <= 0x40)) || ((c > 0x5a) && (c <= 0x60)) || (c > 0x7a) || (c == '_')) {
|
||||
|
@ -188,7 +188,7 @@ public abstract class TaskManager {
|
||||
if (r == null) {
|
||||
return;
|
||||
}
|
||||
if (Thread.currentThread() == Fawe.get().getMainThread()) {
|
||||
if (Fawe.isMainThread()) {
|
||||
r.run();
|
||||
} else {
|
||||
task(r);
|
||||
@ -336,7 +336,7 @@ public abstract class TaskManager {
|
||||
* @return
|
||||
*/
|
||||
public <T> T syncWhenFree(final RunnableVal<T> function, int timeout) {
|
||||
if (Fawe.get().getMainThread() == Thread.currentThread()) {
|
||||
if (Fawe.isMainThread()) {
|
||||
function.run();
|
||||
return function.value;
|
||||
}
|
||||
@ -389,7 +389,7 @@ public abstract class TaskManager {
|
||||
}
|
||||
|
||||
public <T> T sync(final Supplier<T> function, int timeout) {
|
||||
if (Fawe.get().getMainThread() == Thread.currentThread()) {
|
||||
if (Fawe.isMainThread()) {
|
||||
return function.get();
|
||||
}
|
||||
final AtomicBoolean running = new AtomicBoolean(true);
|
||||
|
@ -3,6 +3,7 @@ package com.boydti.fawe.util.image;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParameterException;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
@ -16,6 +17,13 @@ import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class ImageUtil {
|
||||
public static BufferedImage getScaledInstance(BufferedImage img,
|
||||
@ -208,7 +216,6 @@ public class ImageUtil {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static URI getImageURI(String arg) throws ParameterException {
|
||||
try {
|
||||
if (arg.startsWith("http")) {
|
||||
|
@ -363,19 +363,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
|
||||
this(world, null, null, null, null, null, true, null, null, null, blockBag, eventBus, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily copy a region
|
||||
*
|
||||
* @param region
|
||||
* @return
|
||||
*/
|
||||
public BlockArrayClipboard lazyCopy(Region region) {
|
||||
WorldCopyClipboard faweClipboard = new WorldCopyClipboard(this, region);
|
||||
BlockArrayClipboard weClipboard = new BlockArrayClipboard(region, faweClipboard);
|
||||
weClipboard.setOrigin(region.getMinimumPoint());
|
||||
return weClipboard;
|
||||
}
|
||||
|
||||
/**
|
||||
* The limit for this specific edit (blocks etc)
|
||||
*
|
||||
@ -2865,9 +2852,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
|
||||
distribution.add(new Countable<BaseBlock>(FaweCache.CACHE_BLOCK[i], count));
|
||||
}
|
||||
}
|
||||
Collections.sort(distribution);
|
||||
// Collections.reverse(distribution);
|
||||
|
||||
return distribution;
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@ import com.boydti.fawe.object.extent.ResettableExtent;
|
||||
import com.boydti.fawe.util.*;
|
||||
import com.boydti.fawe.util.cui.CUI;
|
||||
import com.boydti.fawe.wrappers.WorldWrapper;
|
||||
import com.intellectualcrafters.plot.object.PlotArea;
|
||||
import com.sk89q.jchronic.Chronic;
|
||||
import com.sk89q.jchronic.Options;
|
||||
import com.sk89q.jchronic.utils.Span;
|
||||
@ -1170,7 +1171,7 @@ public class LocalSession implements TextureHolder {
|
||||
|
||||
if (hasCUISupport) {
|
||||
actor.dispatchCUIEvent(event);
|
||||
} else {
|
||||
} else if (actor.isPlayer()) {
|
||||
CUI cui = Fawe.get().getCUI(actor);
|
||||
if (cui != null) cui.dispatchCUIEvent(event);
|
||||
}
|
||||
|
@ -8,7 +8,8 @@ import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.platform.CommandManager;
|
||||
import com.sk89q.worldedit.util.command.*;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParametricCallable;
|
||||
import com.sk89q.worldedit.util.command.parametric.AParametricCallable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public abstract class HelpBuilder implements Runnable {
|
||||
@ -69,13 +70,12 @@ public abstract class HelpBuilder implements Runnable {
|
||||
if (c instanceof DelegateCallable) {
|
||||
c = ((DelegateCallable) c).getParent();
|
||||
}
|
||||
if (c instanceof ParametricCallable) {
|
||||
Object obj = ((ParametricCallable) c).getObject();
|
||||
Command command = obj.getClass().getAnnotation(Command.class);
|
||||
if (c instanceof AParametricCallable) {
|
||||
Command command = ((AParametricCallable) c).getCommand();
|
||||
if (command != null && command.aliases().length != 0) {
|
||||
group = command.aliases()[0];
|
||||
} else {
|
||||
group = obj.getClass().getSimpleName().replaceAll("Commands", "").replaceAll("Util$", "");
|
||||
group = ((AParametricCallable) c).getGroup();
|
||||
}
|
||||
} else if (c instanceof Dispatcher) {
|
||||
group = mapping.getPrimaryAlias();
|
||||
|
@ -1,5 +1,8 @@
|
||||
package com.sk89q.worldedit.command;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.DataAnglePattern;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.clipboard.MultiClipboardHolder;
|
||||
@ -8,11 +11,11 @@ import com.boydti.fawe.object.pattern.*;
|
||||
import com.boydti.fawe.object.random.SimplexRandom;
|
||||
import com.boydti.fawe.util.ColorUtil;
|
||||
import com.boydti.fawe.util.TextureUtil;
|
||||
import com.boydti.fawe.wrappers.LocationMaskedPlayerWrapper;
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.worldedit.EmptyClipboardException;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.worldedit.*;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
@ -26,11 +29,13 @@ import com.sk89q.worldedit.function.pattern.RandomPattern;
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.ExpressionException;
|
||||
import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment;
|
||||
import com.sk89q.worldedit.scripting.RhinoCraftScriptEngine;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.util.command.binding.Range;
|
||||
import com.sk89q.worldedit.util.command.parametric.Optional;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.awt.Color;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -45,6 +45,7 @@ import com.sk89q.worldedit.event.extent.PlayerSaveClipboardEvent;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.ClipboardFormats;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
@ -54,6 +55,8 @@ import com.sk89q.worldedit.util.command.binding.Switch;
|
||||
import com.sk89q.worldedit.util.command.parametric.Optional;
|
||||
import com.sk89q.worldedit.util.io.file.FilenameException;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.*;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
@ -69,6 +72,7 @@ import java.util.regex.Pattern;
|
||||
|
||||
|
||||
import static com.boydti.fawe.util.ReflectionUtils.as;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Commands that work with schematic files.
|
||||
@ -187,16 +191,26 @@ public class SchematicCommands extends MethodCommands {
|
||||
player.print(BBC.getPrefix() + "Remapped schematic");
|
||||
}
|
||||
|
||||
private File resolve(File dir, String filename, @Nullable ClipboardFormat format) {
|
||||
if (format != null) {
|
||||
if (!filename.matches(".*\\.[\\w].*")) {
|
||||
filename = filename + "." + format.getExtension();
|
||||
}
|
||||
return MainUtil.resolveRelative(new File(dir, filename));
|
||||
}
|
||||
for (ClipboardFormat f : ClipboardFormat.values()) {
|
||||
File file = MainUtil.resolveRelative(new File(dir, filename + "." + f.getExtension()));
|
||||
if (file.exists()) return file;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Command(aliases = {"load"}, usage = "[<format>] <filename>", desc = "Load a schematic into your clipboard")
|
||||
@Deprecated
|
||||
@CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load", "worldedit.schematic.upload", "worldedit.schematic.load.other"})
|
||||
public void load(final Player player, final LocalSession session, @Optional("schematic") final String formatName, String filename) throws FilenameException {
|
||||
public void load(final Player player, final LocalSession session, @Optional() final String formatName, String filename) throws FilenameException {
|
||||
final LocalConfiguration config = this.worldEdit.getConfiguration();
|
||||
final ClipboardFormat format = ClipboardFormat.findByAlias(formatName);
|
||||
if (format == null) {
|
||||
BBC.CLIPBOARD_INVALID_FORMAT.send(player, formatName);
|
||||
return;
|
||||
}
|
||||
ClipboardFormat format = formatName == null ? null : ClipboardFormat.findByAlias(formatName);
|
||||
InputStream in = null;
|
||||
try {
|
||||
URI uri;
|
||||
@ -220,8 +234,14 @@ public class SchematicCommands extends MethodCommands {
|
||||
File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, player.getUniqueId().toString()) : working;
|
||||
File f;
|
||||
if (filename.startsWith("#")) {
|
||||
f = player.openFileOpenDialog(new String[] { format.getExtension() });
|
||||
if (!f.exists()) {
|
||||
String[] extensions;
|
||||
if (format != null) {
|
||||
extensions = new String[] { format.getExtension() };
|
||||
} else {
|
||||
extensions = ClipboardFormats.getFileExtensionArray();
|
||||
}
|
||||
f = player.openFileOpenDialog(extensions);
|
||||
if (f == null || !f.exists()) {
|
||||
player.printError("Schematic " + filename + " does not exist! (" + f + ")");
|
||||
return;
|
||||
}
|
||||
@ -230,32 +250,30 @@ public class SchematicCommands extends MethodCommands {
|
||||
BBC.NO_PERM.send(player, "worldedit.schematic.load.other");
|
||||
return;
|
||||
}
|
||||
if (!filename.matches(".*\\.[\\w].*")) {
|
||||
filename += "." + format.getExtension();
|
||||
if (format == null && filename.matches(".*\\.[\\w].*")) {
|
||||
String extension = filename.substring(filename.lastIndexOf('.') + 1, filename.length());
|
||||
format = ClipboardFormat.findByExtension(extension);
|
||||
}
|
||||
f = MainUtil.resolveRelative(new File(dir, filename));
|
||||
f = resolve(dir, filename, format);
|
||||
}
|
||||
if (f.getName().replaceAll("." + format.getExtension(), "").isEmpty()) {
|
||||
File directory = f.getParentFile();
|
||||
if (directory.exists()) {
|
||||
int max = MainUtil.getMaxFileId(directory) - 1;
|
||||
f = new File(directory, max + "." + format.getExtension());
|
||||
} else {
|
||||
f = new File(directory, "1." + format.getExtension());
|
||||
}
|
||||
}
|
||||
if (!f.exists()) {
|
||||
if (f == null || !f.exists()) {
|
||||
if (!filename.contains("../")) {
|
||||
dir = this.worldEdit.getWorkingDirectoryFile(config.saveDir);
|
||||
f = this.worldEdit.getSafeSaveFile(player, dir, filename, format.getExtension(), format.getExtension());
|
||||
f = resolve(dir, filename, format);
|
||||
}
|
||||
}
|
||||
if (!f.exists() || !MainUtil.isInSubDirectory(working, f)) {
|
||||
if (f == null || !f.exists() || !MainUtil.isInSubDirectory(working, f)) {
|
||||
player.printError("Schematic " + filename + " does not exist! (" + f.exists() + "|" + f + "|" + (!MainUtil.isInSubDirectory(working, f)) + ")");
|
||||
return;
|
||||
}
|
||||
if (format == null) {
|
||||
format = ClipboardFormat.findByFile(f);
|
||||
if (format == null) {
|
||||
BBC.CLIPBOARD_INVALID_FORMAT.send(player, f.getName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
in = new FileInputStream(f);
|
||||
|
||||
uri = f.toURI();
|
||||
}
|
||||
format.hold(player, uri, in);
|
||||
|
@ -46,8 +46,8 @@ public class AreaPickaxe implements BlockTool {
|
||||
editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop);
|
||||
|
||||
for (int x = ox - range; x <= ox + range; ++x) {
|
||||
for (int y = oy - range; y <= oy + range; ++y) {
|
||||
for (int z = oz - range; z <= oz + range; ++z) {
|
||||
for (int z = oz - range; z <= oz + range; ++z) {
|
||||
for (int y = oy + range; y >= oy - range; --y) {
|
||||
if (editSession.getLazyBlock(x, y, z).getId() != initialType) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
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;
|
||||
@ -22,11 +24,13 @@ 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 java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class DefaultMaskParser extends FaweParser<Mask> {
|
||||
private final Dispatcher dispatcher;
|
||||
@ -52,23 +56,27 @@ 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.of("#", ",", "&").map(n -> n + ":").collect(Collectors.toList())
|
||||
// TODO namespaces
|
||||
);
|
||||
}
|
||||
Extent extent = Request.request().getExtent();
|
||||
if (extent == null) extent = context.getExtent();
|
||||
HashSet<BaseBlock> blocks = new HashSet<BaseBlock>();
|
||||
List<Mask> intersection = new ArrayList<>();
|
||||
List<Mask> union = new ArrayList<>();
|
||||
List<List<Mask>> masks = new ArrayList<>();
|
||||
masks.add(new ArrayList<>());
|
||||
|
||||
final CommandLocals locals = new CommandLocals();
|
||||
Actor actor = context != null ? context.getActor() : null;
|
||||
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,101 +87,116 @@ 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;
|
||||
}
|
||||
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 {
|
||||
try {
|
||||
context.setPreferringWildcard(true);
|
||||
context.setRestricted(false);
|
||||
BaseBlock block = worldEdit.getBlockFactory().parseFromInput(command, context);
|
||||
if (pe.and) {
|
||||
mask = new BlockMask(extent, block);
|
||||
} else {
|
||||
blocks.add(block);
|
||||
continue;
|
||||
}
|
||||
} catch (NoMatchException e) {
|
||||
throw new NoMatchException(e.getMessage() + " See: //masks");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mask == null) {
|
||||
if (command.startsWith("[")) {
|
||||
int end = command.lastIndexOf(']');
|
||||
mask = parseFromInput(command.substring(1, end == -1 ? command.length() : end), context);
|
||||
} else {
|
||||
context.setPreferringWildcard(true);
|
||||
context.setRestricted(false);
|
||||
BaseBlock block = worldEdit.getBlockFactory().parseFromInput(command, context);
|
||||
mask = new BlockMask(extent, block);
|
||||
}
|
||||
}
|
||||
} 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 (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) { // &
|
||||
intersection.add(mask);
|
||||
} else {
|
||||
if (!intersection.isEmpty()) {
|
||||
if (intersection.size() == 1) {
|
||||
throw new InputParseException("Error, floating &");
|
||||
}
|
||||
union.add(new MaskIntersection(intersection));
|
||||
intersection.clear();
|
||||
}
|
||||
union.add(mask);
|
||||
if (pe.and) {
|
||||
masks.add(new ArrayList<>());
|
||||
}
|
||||
masks.get(masks.size() - 1).add(mask);
|
||||
}
|
||||
} catch (InputParseException rethrow) {
|
||||
throw rethrow;
|
||||
} catch (Throwable e) {
|
||||
InputParseException ips = SuggestInputParseException.find(e);
|
||||
if (ips != null) throw ips;
|
||||
e.printStackTrace();
|
||||
throw new InputParseException(e.getMessage(), e);
|
||||
}
|
||||
if (!blocks.isEmpty()) {
|
||||
union.add(new BlockMask(extent, blocks));
|
||||
}
|
||||
if (!intersection.isEmpty()) {
|
||||
if (intersection.size() == 1) {
|
||||
throw new InputParseException("Error, floating &");
|
||||
List<Mask> maskUnions = new ArrayList<>();
|
||||
for (List<Mask> maskList : masks) {
|
||||
if (maskList.size() == 1) {
|
||||
maskUnions.add(maskList.get(0));
|
||||
} else if (maskList.size() != 0) {
|
||||
maskUnions.add(new MaskUnion(maskList));
|
||||
}
|
||||
union.add(new MaskIntersection(intersection));
|
||||
intersection.clear();
|
||||
}
|
||||
if (union.isEmpty()) {
|
||||
return null;
|
||||
} else if (union.size() == 1) {
|
||||
return union.get(0);
|
||||
if (maskUnions.size() == 1) {
|
||||
return maskUnions.get(0);
|
||||
} else if (maskUnions.size() != 0) {
|
||||
return new MaskIntersection(maskUnions);
|
||||
} else {
|
||||
return new MaskUnion(union);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
public static Class<DefaultMaskParser> inject() {
|
||||
return DefaultMaskParser.class;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
@ -16,13 +18,15 @@ import com.sk89q.worldedit.function.pattern.RandomPattern;
|
||||
import com.sk89q.worldedit.internal.command.ActorAuthorizer;
|
||||
import com.sk89q.worldedit.internal.command.WorldEditBinding;
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
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 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 +51,10 @@ 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.of("#", ",", "&").map(n -> n + ":").collect(Collectors.toList()));
|
||||
// TODO namespace
|
||||
}
|
||||
List<Double> chances = new ArrayList<>();
|
||||
List<Pattern> patterns = new ArrayList<>();
|
||||
final CommandLocals locals = new CommandLocals();
|
||||
@ -58,7 +65,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 +78,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,15 +111,15 @@ 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(command, context);
|
||||
pattern = worldEdit.getBlockFactory().parseFromInput(pe.full, context);
|
||||
} catch (NoMatchException e) {
|
||||
throw new NoMatchException(e.getMessage() + " See: //patterns");
|
||||
}
|
||||
@ -109,18 +128,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 (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) {
|
||||
InputParseException ips = SuggestInputParseException.find(e);
|
||||
if (ips != null) throw ips;
|
||||
e.printStackTrace();
|
||||
throw new InputParseException(e.getMessage(), e);
|
||||
}
|
||||
if (patterns.isEmpty()) {
|
||||
return null;
|
||||
@ -135,7 +181,8 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
|
||||
public static Class<HashTagPatternParser> inject() {
|
||||
return HashTagPatternParser.class;
|
||||
}
|
||||
}
|
||||
|
@ -48,17 +48,14 @@ 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.CommandCallable;
|
||||
import com.sk89q.worldedit.util.command.Dispatcher;
|
||||
import com.sk89q.worldedit.util.command.InvalidUsageException;
|
||||
import com.sk89q.worldedit.util.command.*;
|
||||
import com.sk89q.worldedit.util.command.composition.ProvidedValue;
|
||||
import com.sk89q.worldedit.util.command.fluent.CommandGraph;
|
||||
import com.sk89q.worldedit.util.command.fluent.DispatcherNode;
|
||||
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.command.parametric.*;
|
||||
import com.sk89q.worldedit.util.eventbus.Subscribe;
|
||||
import com.sk89q.worldedit.util.logging.DynamicStreamHandler;
|
||||
import com.sk89q.worldedit.util.logging.LogFormat;
|
||||
@ -184,13 +181,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);
|
||||
@ -244,6 +241,9 @@ public final class CommandManager {
|
||||
}
|
||||
}
|
||||
|
||||
commandMap.clear();
|
||||
methodMap.clear();
|
||||
|
||||
dispatcher = graph
|
||||
.group("/anvil")
|
||||
.describeAs("Anvil command")
|
||||
@ -295,6 +295,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;
|
||||
@ -403,6 +410,7 @@ public final class CommandManager {
|
||||
// exceptions without writing a hook into every dispatcher, we need to unwrap these
|
||||
// exceptions and rethrow their converted form, if their is one.
|
||||
try {
|
||||
Request.request().setActor(finalActor);
|
||||
Object result = 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
|
||||
@ -485,6 +493,16 @@ public final class CommandManager {
|
||||
TaskManager.IMP.taskNow(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// int space0 = args.indexOf(' ');
|
||||
// String arg0 = space0 == -1 ? args : args.substring(0, space0);
|
||||
// CommandMapping cmd = dispatcher.get(arg0);
|
||||
// if (cmd != null && cmd.getCallable() instanceof AParametricCallable) {
|
||||
// Command info = ((AParametricCallable) cmd.getCallable()).getDefinition();
|
||||
// if (!info.queued()) {
|
||||
// handleCommandOnCurrentThread(finalEvent);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
if (!fp.runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -522,7 +540,8 @@ public final class CommandManager {
|
||||
return commandLog;
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
|
||||
public static Class<CommandManager> inject() {
|
||||
return CommandManager.class;
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package com.sk89q.worldedit.extension.platform;
|
||||
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.sk89q.util.ReflectionUtil;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.WorldVector;
|
||||
@ -13,7 +15,13 @@ import com.sk89q.worldedit.internal.cui.CUIEvent;
|
||||
import com.sk89q.worldedit.session.SessionKey;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class PlayerProxy extends AbstractPlayerActor {
|
||||
|
@ -213,9 +213,7 @@ public class AbstractDelegateExtent implements LightingExtent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final
|
||||
@Nullable
|
||||
Operation commit() {
|
||||
public @Nullable Operation commit() {
|
||||
Operation ours = commitBefore();
|
||||
Operation other = null;
|
||||
if (extent != this) other = extent.commit();
|
||||
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.extent.clipboard;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class ClipboardFormats {
|
||||
/**
|
||||
* Find the clipboard format named by the given alias.
|
||||
*
|
||||
* @param alias
|
||||
* the alias
|
||||
* @return the format, otherwise null if none is matched
|
||||
*/
|
||||
@Nullable
|
||||
public static ClipboardFormat findByAlias(String alias) {
|
||||
return ClipboardFormat.findByAlias(alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the format of given a file.
|
||||
*
|
||||
* @param file
|
||||
* the file
|
||||
* @return the format, otherwise null if one cannot be detected
|
||||
*/
|
||||
@Nullable
|
||||
public static ClipboardFormat findByFile(File file) {
|
||||
checkNotNull(file);
|
||||
|
||||
for (ClipboardFormat format : ClipboardFormat.values()) {
|
||||
if (format.isFormat(file)) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a multimap from a file extension to the potential matching formats.
|
||||
*/
|
||||
public static Multimap<String, ClipboardFormat> getFileExtensionMap() {
|
||||
HashMultimap<String, ClipboardFormat> map = HashMultimap.create();
|
||||
for (ClipboardFormat format : ClipboardFormat.values()) {
|
||||
map.put(format.getExtension(), format);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public static Collection<ClipboardFormat> getAll() {
|
||||
return Arrays.asList(ClipboardFormat.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Not public API, only used by SchematicCommands.
|
||||
* It is not in SchematicCommands because it may rely on internal register calls.
|
||||
*/
|
||||
public static String[] getFileExtensionArray() {
|
||||
List<String> exts = new ArrayList<>();
|
||||
HashMultimap<String, ClipboardFormat> map = HashMultimap.create();
|
||||
for (ClipboardFormat format : ClipboardFormat.values()) {
|
||||
exts.add(format.getExtension());
|
||||
}
|
||||
return exts.toArray(new String[exts.size()]);
|
||||
}
|
||||
|
||||
private ClipboardFormats() {}
|
||||
}
|
@ -45,6 +45,7 @@ import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.event.extent.PlayerSaveClipboardEvent;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
@ -540,6 +541,18 @@ public enum ClipboardFormat {
|
||||
return aliasMap.get(alias.toLowerCase().trim());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ClipboardFormat findByExtension(String extension) {
|
||||
checkNotNull(extension);
|
||||
extension = extension.toLowerCase();
|
||||
for (ClipboardFormat format : values()) {
|
||||
if (format.getExtension().equalsIgnoreCase(extension)) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the format given a file.
|
||||
*
|
||||
|
@ -0,0 +1,102 @@
|
||||
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.util.MainUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
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.ProcessedCallable;
|
||||
import com.sk89q.worldedit.util.command.parametric.FunctionParametricCallable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class CommandScriptLoader {
|
||||
private final NashornCraftScriptEngine engine;
|
||||
private final String loader;
|
||||
|
||||
public CommandScriptLoader() throws IOException {
|
||||
this.engine = new NashornCraftScriptEngine();
|
||||
|
||||
try (InputStream inputStream = Fawe.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);
|
||||
}
|
||||
}
|
@ -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 {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -169,7 +169,6 @@ public class SessionManager {
|
||||
checkNotNull(owner);
|
||||
|
||||
LocalSession session = getIfPresent(owner);
|
||||
LocalConfiguration config = worldEdit.getConfiguration();
|
||||
SessionKey sessionKey = owner.getSessionKey();
|
||||
|
||||
// No session exists yet -- create one
|
||||
@ -182,12 +181,14 @@ public class SessionManager {
|
||||
session = new LocalSession();
|
||||
}
|
||||
|
||||
LocalConfiguration config = worldEdit.getConfiguration();
|
||||
session.setConfiguration(config);
|
||||
session.setBlockChangeLimit(config.defaultChangeLimit);
|
||||
|
||||
sessions.put(getKey(owner), new SessionHolder(sessionKey, session));
|
||||
}
|
||||
|
||||
LocalConfiguration config = worldEdit.getConfiguration();
|
||||
// Set the limit on the number of blocks that an operation can
|
||||
// change at once, or don't if the owner has an override or there
|
||||
// is no limit. There is also a default limit
|
||||
|
@ -21,7 +21,10 @@ package com.sk89q.worldedit.session.request;
|
||||
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParametricCallable;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ -30,19 +33,16 @@ import javax.annotation.Nullable;
|
||||
*/
|
||||
public final class Request {
|
||||
|
||||
private static final ThreadLocal<Request> threadLocal =
|
||||
new ThreadLocal<Request>() {
|
||||
@Override
|
||||
protected Request initialValue() {
|
||||
return new Request();
|
||||
}
|
||||
};
|
||||
private static final ThreadLocal<Request> threadLocal = ThreadLocal.withInitial(Request::new);
|
||||
|
||||
private
|
||||
@Nullable
|
||||
World world;
|
||||
private
|
||||
@Nullable
|
||||
Actor actor;
|
||||
private
|
||||
@Nullable
|
||||
LocalSession session;
|
||||
private
|
||||
@Nullable
|
||||
@ -87,6 +87,15 @@ public final class Request {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Actor getActor() {
|
||||
return actor;
|
||||
}
|
||||
|
||||
public void setActor(@Nullable Actor actor) {
|
||||
this.actor = actor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the request session.
|
||||
*
|
||||
@ -143,7 +152,8 @@ public final class Request {
|
||||
threadLocal.remove();
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
|
||||
public static Class<Request> inject() {
|
||||
return Request.class;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,310 @@
|
||||
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.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.util.command.*;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
|
||||
public abstract class AParametricCallable implements CommandCallable {
|
||||
// private final ParametricBuilder builder;
|
||||
// private ParameterData[] parameters;
|
||||
// private Set<Character> valueFlags = new HashSet<Character>();
|
||||
// private boolean anyFlags;
|
||||
// private Set<Character> legacyFlags = new HashSet<Character>();
|
||||
// private SimpleDescription description = new SimpleDescription();
|
||||
// private String permission;
|
||||
// private Command command;
|
||||
|
||||
public abstract ParameterData[] getParameters();
|
||||
public abstract Set<Character> getValueFlags();
|
||||
public abstract Set<Character> getLegacyFlags();
|
||||
public abstract SimpleDescription getDescription();
|
||||
public abstract String[] getPermissions();
|
||||
public abstract ParametricBuilder getBuilder();
|
||||
public abstract boolean anyFlags();
|
||||
public abstract Command getCommand();
|
||||
public Command getDefinition() {
|
||||
return getCommand();
|
||||
}
|
||||
public abstract String getGroup();
|
||||
@Override
|
||||
public abstract String toString();
|
||||
|
||||
/**
|
||||
* Get the right {@link ArgumentStack}.
|
||||
*
|
||||
* @param parameter the parameter
|
||||
* @param existing the existing scoped context
|
||||
* @return the context to use
|
||||
*/
|
||||
public static ArgumentStack getScopedContext(Parameter parameter, ArgumentStack existing) {
|
||||
if (parameter.getFlag() != null) {
|
||||
CommandContext context = existing.getContext();
|
||||
|
||||
if (parameter.isValueFlag()) {
|
||||
return new StringArgumentStack(context, context.getFlag(parameter.getFlag()), false);
|
||||
} else {
|
||||
String v = context.hasFlag(parameter.getFlag()) ? "true" : "false";
|
||||
return new StringArgumentStack(context, v, true);
|
||||
}
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether a parameter is allowed to consume arguments.
|
||||
*
|
||||
* @param i the index of the parameter
|
||||
* @param scoped the scoped context
|
||||
* @return true if arguments may be consumed
|
||||
*/
|
||||
public boolean mayConsumeArguments(int i, ContextArgumentStack scoped) {
|
||||
CommandContext context = scoped.getContext();
|
||||
ParameterData parameter = getParameters()[i];
|
||||
|
||||
// Flag parameters: Always consume
|
||||
// Required non-flag parameters: Always consume
|
||||
// Optional non-flag parameters:
|
||||
// - Before required parameters: Consume if there are 'left over' args
|
||||
// - At the end: Always consumes
|
||||
|
||||
if (parameter.isOptional()) {
|
||||
if (parameter.getFlag() != null) {
|
||||
return !parameter.isValueFlag() || context.hasFlag(parameter.getFlag());
|
||||
} else {
|
||||
int numberFree = context.argsLength() - scoped.position();
|
||||
for (int j = i; j < getParameters().length; j++) {
|
||||
if (getParameters()[j].isNonFlagConsumer() && !getParameters()[j].isOptional()) {
|
||||
// We already checked if the consumed count was > -1
|
||||
// when we created this object
|
||||
numberFree -= getParameters()[j].getConsumedCount();
|
||||
}
|
||||
}
|
||||
|
||||
// Skip this optional parameter
|
||||
if (numberFree < 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default value for a parameter.
|
||||
*
|
||||
* @param i the index of the parameter
|
||||
* @param scoped the scoped context
|
||||
* @return a value
|
||||
* @throws ParameterException on an error
|
||||
* @throws CommandException on an error
|
||||
*/
|
||||
public Object getDefaultValue(int i, ContextArgumentStack scoped) throws ParameterException, CommandException, InvocationTargetException {
|
||||
CommandContext context = scoped.getContext();
|
||||
ParameterData parameter = getParameters()[i];
|
||||
|
||||
String[] defaultValue = parameter.getDefaultValue();
|
||||
if (defaultValue != null) {
|
||||
try {
|
||||
return parameter.getBinding().bind(parameter, new StringArgumentStack(context, defaultValue, false), false);
|
||||
} catch (MissingParameterException e) {
|
||||
throw new ParametricException(
|
||||
"The default value of the parameter using the binding " +
|
||||
parameter.getBinding().getClass() + " in the method\n" +
|
||||
toString() + "\nis invalid");
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check to see if all arguments, including flag arguments, were consumed.
|
||||
*
|
||||
* @param scoped the argument scope
|
||||
* @throws UnconsumedParameterException thrown if parameters were not consumed
|
||||
*/
|
||||
public void checkUnconsumed(ContextArgumentStack scoped) throws UnconsumedParameterException {
|
||||
CommandContext context = scoped.getContext();
|
||||
String unconsumed;
|
||||
String unconsumedFlags = getUnusedFlags(context);
|
||||
|
||||
if ((unconsumed = scoped.getUnconsumed()) != null) {
|
||||
throw new UnconsumedParameterException(unconsumed + " " + unconsumedFlags);
|
||||
}
|
||||
|
||||
if (unconsumedFlags != null) {
|
||||
throw new UnconsumedParameterException(unconsumedFlags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any unused flag arguments.
|
||||
*
|
||||
* @param context the command context
|
||||
*/
|
||||
public String getUnusedFlags(CommandContext context) {
|
||||
if (!anyFlags()) {
|
||||
Set<Character> unusedFlags = null;
|
||||
for (char flag : context.getFlags()) {
|
||||
boolean found = false;
|
||||
|
||||
if (getLegacyFlags().contains(flag)) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (ParameterData parameter : getParameters()) {
|
||||
Character paramFlag = parameter.getFlag();
|
||||
if (paramFlag != null && flag == paramFlag) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (unusedFlags == null) {
|
||||
unusedFlags = new HashSet<Character>();
|
||||
}
|
||||
unusedFlags.add(flag);
|
||||
}
|
||||
}
|
||||
|
||||
if (unusedFlags != null) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Character flag : unusedFlags) {
|
||||
builder.append("-").append(flag).append(" ");
|
||||
}
|
||||
|
||||
return builder.toString().trim();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testPermission(CommandLocals locals) {
|
||||
String[] perms = getPermissions();
|
||||
if (perms != null && perms.length != 0) {
|
||||
for (String perm : perms) {
|
||||
if (getBuilder().getAuthorizer().testPermission(locals, perm)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@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 = "";
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
Throwable tmp = e;
|
||||
SuggestInputParseException suggestion = SuggestInputParseException.get(tmp);
|
||||
try {
|
||||
if (suggestion != null && !suggestion.getSuggestions().isEmpty()) {
|
||||
hasSuggestion = true;
|
||||
suggestions.addAll(suggestion.getSuggestions());
|
||||
} else {
|
||||
Throwable t = tmp;
|
||||
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 (InputParseException e2) {
|
||||
throw new WrappedCommandException(e2);
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -0,0 +1,328 @@
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.google.common.primitives.Chars;
|
||||
import com.sk89q.minecraft.util.commands.*;
|
||||
import com.sk89q.worldedit.util.command.*;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class FunctionParametricCallable extends AParametricCallable {
|
||||
|
||||
private final ParametricBuilder builder;
|
||||
private final ParameterData[] parameters;
|
||||
private final Set<Character> valueFlags = new HashSet<Character>();
|
||||
private final boolean anyFlags;
|
||||
private final Set<Character> legacyFlags = new HashSet<Character>();
|
||||
private final SimpleDescription description = new SimpleDescription();
|
||||
private final String permission;
|
||||
private final Command command;
|
||||
private final Function<Object[], ?> function;
|
||||
private final String group;
|
||||
|
||||
public FunctionParametricCallable(ParametricBuilder builder, String group, Command command, String permission, List<String> arguments, Function<Object[], ?> function) {
|
||||
this.command = command;
|
||||
this.permission = permission;
|
||||
this.builder = builder;
|
||||
this.function = function;
|
||||
this.group = group;
|
||||
|
||||
List<Object[]> paramParsables = new ArrayList<>();
|
||||
{
|
||||
Map<Type, Binding> bindings = builder.getBindings();
|
||||
Map<String, Type> unqualified = new HashMap<>();
|
||||
for (Map.Entry<Type, Binding> entry : bindings.entrySet()) {
|
||||
Type type = entry.getKey();
|
||||
String typeStr = type.getTypeName();
|
||||
unqualified.put(typeStr, type);
|
||||
unqualified.put(typeStr.substring(typeStr.lastIndexOf('.') + 1), 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[paramParsables.size()];
|
||||
List<Parameter> userParameters = new ArrayList<Parameter>();
|
||||
|
||||
// This helps keep tracks of @Nullables that appear in the middle of a list
|
||||
// of parameters
|
||||
int numOptional = 0;
|
||||
//
|
||||
// Go through each parameter
|
||||
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]);
|
||||
|
||||
boolean flag = paramName.length() == 1 && command.flags().contains(paramName);
|
||||
if (flag) {
|
||||
parameter.setFlag(paramName.charAt(0), type != boolean.class && type != Boolean.class);
|
||||
}
|
||||
|
||||
if (optional != null) {
|
||||
parameter.setOptional(true);
|
||||
if (!optional.equalsIgnoreCase("null")) parameter.setDefaultValue(new String[]{optional});
|
||||
}
|
||||
|
||||
parameter.setName(paramName);
|
||||
|
||||
// Track all value flags
|
||||
if (parameter.isValueFlag()) {
|
||||
valueFlags.add(parameter.getFlag());
|
||||
}
|
||||
|
||||
// No special @annotation binding... let's check for the type
|
||||
if (parameter.getBinding() == null) {
|
||||
parameter.setBinding(builder.getBindings().get(type));
|
||||
|
||||
// Don't know how to parse for this type of value
|
||||
if (parameter.getBinding() == null) {
|
||||
throw new ParametricException("Don't know how to handle the parameter type '" + type + "' in\n" + StringMan.getString(command.aliases()));
|
||||
}
|
||||
}
|
||||
|
||||
// Do some validation of this parameter
|
||||
parameter.validate(() -> StringMan.getString(command.aliases()), i + 1);
|
||||
|
||||
// Keep track of optional parameters
|
||||
if (parameter.isOptional() && parameter.getFlag() == null) {
|
||||
numOptional++;
|
||||
} else {
|
||||
if (numOptional > 0 && parameter.isNonFlagConsumer()) {
|
||||
if (parameter.getConsumedCount() < 0) {
|
||||
throw new ParametricException(
|
||||
"Found an parameter using the binding " +
|
||||
parameter.getBinding().getClass().getCanonicalName() +
|
||||
"\nthat does not know how many arguments it consumes, but " +
|
||||
"it follows an optional parameter\nMethod: " + StringMan.getString(command.aliases()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parameters[i] = parameter;
|
||||
|
||||
// Make a list of "real" parameters
|
||||
if (parameter.isUserInput()) {
|
||||
userParameters.add(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Gather legacy flags
|
||||
anyFlags = command.anyFlags();
|
||||
legacyFlags.addAll(Chars.asList(command.flags().toCharArray()));
|
||||
|
||||
// Finish description
|
||||
description.setDescription(!command.desc().isEmpty() ? command.desc() : null);
|
||||
description.setHelp(!command.help().isEmpty() ? command.help() : null);
|
||||
description.overrideUsage(!command.usage().isEmpty() ? command.usage() : null);
|
||||
description.setPermissions(Arrays.asList(permission));
|
||||
|
||||
if (command.usage().isEmpty() && (command.min() > 0 || command.max() > 0)) {
|
||||
boolean hasUserParameters = false;
|
||||
|
||||
for (ParameterData parameter : parameters) {
|
||||
if (parameter.getBinding().getBehavior(parameter) != BindingBehavior.PROVIDES) {
|
||||
hasUserParameters = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasUserParameters) {
|
||||
description.overrideUsage("(unknown usage information)");
|
||||
}
|
||||
}
|
||||
|
||||
// Set parameters
|
||||
description.setParameters(userParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParameterData[] getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public Set<Character> getValueFlags() {
|
||||
return valueFlags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Character> getLegacyFlags() {
|
||||
return legacyFlags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object call(String stringArguments, CommandLocals locals, String[] parentCommands) throws CommandException {
|
||||
// Test permission
|
||||
if (!testPermission(locals)) {
|
||||
throw new CommandPermissionsException();
|
||||
}
|
||||
if (locals.get(CommandCallable.class) == null) locals.put(CommandCallable.class, this);
|
||||
|
||||
String calledCommand = parentCommands.length > 0 ? parentCommands[parentCommands.length - 1] : "_";
|
||||
String[] split = (calledCommand + " " + stringArguments).split(" ", -1);
|
||||
CommandContext context = new CommandContext(split, getValueFlags(), false, locals);
|
||||
|
||||
// Provide help if -? is specified
|
||||
if (context.hasFlag('?')) {
|
||||
throw new InvalidUsageException(null, this, true);
|
||||
}
|
||||
|
||||
Object[] args = new Object[parameters.length];
|
||||
ContextArgumentStack arguments = new ContextArgumentStack(context);
|
||||
ParameterData parameter = null;
|
||||
|
||||
try {
|
||||
// preProcess handlers
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Collect parameters
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
parameter = parameters[i];
|
||||
|
||||
if (mayConsumeArguments(i, arguments)) {
|
||||
// Parse the user input into a method argument
|
||||
ArgumentStack usedArguments = getScopedContext(parameter, arguments);
|
||||
|
||||
try {
|
||||
usedArguments.mark();
|
||||
args[i] = parameter.getBinding().bind(parameter, usedArguments, false);
|
||||
} catch (ParameterException e) {
|
||||
// Not optional? Then we can't execute this command
|
||||
if (!parameter.isOptional()) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
usedArguments.reset();
|
||||
args[i] = getDefaultValue(i, arguments);
|
||||
}
|
||||
} else {
|
||||
args[i] = getDefaultValue(i, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for unused arguments
|
||||
checkUnconsumed(arguments);
|
||||
|
||||
// preInvoke handlers
|
||||
{
|
||||
if (context.argsLength() < command.min()) {
|
||||
throw new MissingParameterException();
|
||||
}
|
||||
if (command.max() != -1 && context.argsLength() > command.max()) {
|
||||
throw new UnconsumedParameterException(context.getRemainingString(command.max()));
|
||||
}
|
||||
}
|
||||
|
||||
// Execute!
|
||||
Object result = function.apply(args);
|
||||
|
||||
// postInvoke handlers
|
||||
{
|
||||
}
|
||||
return result;
|
||||
} catch (MissingParameterException e) {
|
||||
throw new InvalidUsageException("Too few parameters!", this, true);
|
||||
} catch (UnconsumedParameterException e) {
|
||||
throw new InvalidUsageException("Too many parameters! Unused parameters: " + e.getUnconsumed(), this, true);
|
||||
} catch (ParameterException e) {
|
||||
assert parameter != null;
|
||||
String name = parameter.getName();
|
||||
|
||||
throw new InvalidUsageException("For parameter '" + name + "': " + e.getMessage(), this, true);
|
||||
} catch (InvocationTargetException e) {
|
||||
if (e.getCause() instanceof CommandException) {
|
||||
throw (CommandException) e.getCause();
|
||||
}
|
||||
throw new WrappedCommandException(e);
|
||||
} catch (Throwable t) {
|
||||
throw new WrappedCommandException(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testPermission(CommandLocals locals) {
|
||||
return permission != null ? (builder.getAuthorizer().testPermission(locals, permission)) : true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleDescription getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPermissions() {
|
||||
return new String[]{permission};
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParametricBuilder getBuilder() {
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean anyFlags() {
|
||||
return anyFlags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return command.aliases()[0];
|
||||
}
|
||||
}
|
@ -23,9 +23,13 @@ import com.sk89q.worldedit.util.command.SimpleParameter;
|
||||
import com.sk89q.worldedit.util.command.binding.PrimitiveBindings;
|
||||
import com.sk89q.worldedit.util.command.binding.Range;
|
||||
import com.sk89q.worldedit.util.command.binding.Text;
|
||||
|
||||
import javax.xml.ws.Provider;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Describes a parameter in detail.
|
||||
@ -155,6 +159,10 @@ public class ParameterData extends SimpleParameter {
|
||||
* Validate this parameter and its binding.
|
||||
*/
|
||||
public void validate(Method method, int parameterIndex) throws ParametricException {
|
||||
validate(() -> method.toGenericString(), parameterIndex);
|
||||
}
|
||||
|
||||
public void validate(Supplier<String> method, int parameterIndex) throws ParametricException {
|
||||
// We can't have indeterminate consumers without @Switches otherwise
|
||||
// it may screw up parameter processing for later bindings
|
||||
BindingBehavior behavior = getBinding().getBehavior(this);
|
||||
@ -166,7 +174,7 @@ public class ParameterData extends SimpleParameter {
|
||||
getBinding().getClass().getCanonicalName() +
|
||||
"\nmay or may not consume parameters (isIndeterminateConsumer(" + type + ") = true)" +
|
||||
"\nand therefore @Switch(flag) is required for parameter #" + parameterIndex + " of \n" +
|
||||
method.toGenericString());
|
||||
method.get());
|
||||
}
|
||||
|
||||
// getConsumedCount() better return -1 if the BindingBehavior is not CONSUMES
|
||||
@ -176,7 +184,7 @@ public class ParameterData extends SimpleParameter {
|
||||
getBinding().getClass().getCanonicalName() +
|
||||
"\neven though its behavior type is " + behavior.name() +
|
||||
"\nfor parameter #" + parameterIndex + " of \n" +
|
||||
method.toGenericString());
|
||||
method.get());
|
||||
}
|
||||
|
||||
// getConsumedCount() should not return 0 if the BindingBehavior is not PROVIDES
|
||||
@ -186,7 +194,7 @@ public class ParameterData extends SimpleParameter {
|
||||
getBinding().getClass().getCanonicalName() +
|
||||
"\nwhen its behavior type is " + behavior.name() + " and not PROVIDES " +
|
||||
"\nfor parameter #" + parameterIndex + " of \n" +
|
||||
method.toGenericString());
|
||||
method.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ import java.util.Set;
|
||||
/**
|
||||
* The implementation of a {@link CommandCallable} for the {@link ParametricBuilder}.
|
||||
*/
|
||||
public class ParametricCallable implements CommandCallable {
|
||||
public class ParametricCallable extends AParametricCallable {
|
||||
|
||||
private final ParametricBuilder builder;
|
||||
private final Object object;
|
||||
@ -60,6 +60,7 @@ public class ParametricCallable implements CommandCallable {
|
||||
private final Set<Character> legacyFlags = new HashSet<Character>();
|
||||
private final SimpleDescription description = new SimpleDescription();
|
||||
private final CommandPermissions commandPermissions;
|
||||
private final Command definition;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
@ -179,6 +180,22 @@ public class ParametricCallable implements CommandCallable {
|
||||
|
||||
// Get permissions annotation
|
||||
commandPermissions = method.getAnnotation(CommandPermissions.class);
|
||||
this.definition = definition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command getCommand() {
|
||||
return object.getClass().getAnnotation(Command.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command getDefinition() {
|
||||
return definition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroup() {
|
||||
return object.getClass().getSimpleName().replaceAll("Commands", "").replaceAll("Util$", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -187,6 +204,7 @@ public class ParametricCallable implements CommandCallable {
|
||||
if (!testPermission(locals)) {
|
||||
throw new CommandPermissionsException();
|
||||
}
|
||||
if (locals.get(CommandCallable.class) == null) locals.put(CommandCallable.class, this);
|
||||
|
||||
String calledCommand = parentCommands.length > 0 ? parentCommands[parentCommands.length - 1] : "_";
|
||||
String[] split = (calledCommand + " " + stringArguments).split(" ", -1);
|
||||
@ -279,94 +297,8 @@ public class ParametricCallable implements CommandCallable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSuggestions(String arguments, CommandLocals locals) throws CommandException {
|
||||
String[] split = ("ignored" + " " + arguments).split(" ", -1);
|
||||
CommandContext context = new CommandContext(split, getValueFlags(), !arguments.endsWith(" "), locals);
|
||||
ContextArgumentStack scoped = new ContextArgumentStack(context);
|
||||
SuggestionContext suggestable = context.getSuggestionContext();
|
||||
|
||||
|
||||
// For /command -f |
|
||||
// For /command -f flag|
|
||||
if (suggestable.forFlag()) {
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
ParameterData parameter = parameters[i];
|
||||
|
||||
if (parameter.getFlag() == suggestable.getFlag()) {
|
||||
String prefix = context.getFlag(parameter.getFlag());
|
||||
if (prefix == null) {
|
||||
prefix = "";
|
||||
}
|
||||
|
||||
return parameter.getBinding().getSuggestions(parameter, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
// This should not happen
|
||||
return new ArrayList<String>();
|
||||
}
|
||||
|
||||
int consumerIndex = 0;
|
||||
ParameterData lastConsumer = null;
|
||||
String lastConsumed = null;
|
||||
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
ParameterData parameter = parameters[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()) {
|
||||
return parameter.getBinding().getSuggestions(parameter, "");
|
||||
} else {
|
||||
// For /command value1| value2
|
||||
if (lastConsumer != null) {
|
||||
return lastConsumer.getBinding().getSuggestions(lastConsumer, lastConsumed);
|
||||
// For /command| value1 value2
|
||||
// This should never occur
|
||||
} else {
|
||||
throw new RuntimeException("Invalid suggestion context");
|
||||
}
|
||||
}
|
||||
} catch (ParameterException | InvocationTargetException e) {
|
||||
SuggestInputParseException suggestion = SuggestInputParseException.get(e);
|
||||
if (suggestion != null) {
|
||||
return suggestion.getSuggestions();
|
||||
}
|
||||
if (suggestable.forHangingValue()) {
|
||||
String name = getDescription().getParameters().get(consumerIndex).getName();
|
||||
throw new InvalidUsageException("For parameter '" + name + "': " + e.getMessage(), this);
|
||||
} else {
|
||||
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
|
||||
return new ArrayList<String>();
|
||||
} else {
|
||||
// For /command value1 value2|
|
||||
if (lastConsumer != null) {
|
||||
return lastConsumer.getBinding().getSuggestions(lastConsumer, lastConsumed);
|
||||
// This should never occur
|
||||
} else {
|
||||
throw new RuntimeException("Invalid suggestion context");
|
||||
}
|
||||
|
||||
}
|
||||
public ParameterData[] getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -378,179 +310,34 @@ public class ParametricCallable implements CommandCallable {
|
||||
return valueFlags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Character> getLegacyFlags() {
|
||||
return legacyFlags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleDescription getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testPermission(CommandLocals locals) {
|
||||
if (commandPermissions != null) {
|
||||
for (String perm : commandPermissions.value()) {
|
||||
if (builder.getAuthorizer().testPermission(locals, perm)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
public String[] getPermissions() {
|
||||
return commandPermissions != null ? commandPermissions.value() : new String[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the right {@link ArgumentStack}.
|
||||
*
|
||||
* @param parameter the parameter
|
||||
* @param existing the existing scoped context
|
||||
* @return the context to use
|
||||
*/
|
||||
public static ArgumentStack getScopedContext(Parameter parameter, ArgumentStack existing) {
|
||||
if (parameter.getFlag() != null) {
|
||||
CommandContext context = existing.getContext();
|
||||
|
||||
if (parameter.isValueFlag()) {
|
||||
return new StringArgumentStack(context, context.getFlag(parameter.getFlag()), false);
|
||||
} else {
|
||||
String v = context.hasFlag(parameter.getFlag()) ? "true" : "false";
|
||||
return new StringArgumentStack(context, v, true);
|
||||
}
|
||||
}
|
||||
|
||||
return existing;
|
||||
@Override
|
||||
public ParametricBuilder getBuilder() {
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether a parameter is allowed to consume arguments.
|
||||
*
|
||||
* @param i the index of the parameter
|
||||
* @param scoped the scoped context
|
||||
* @return true if arguments may be consumed
|
||||
*/
|
||||
public boolean mayConsumeArguments(int i, ContextArgumentStack scoped) {
|
||||
CommandContext context = scoped.getContext();
|
||||
ParameterData parameter = parameters[i];
|
||||
|
||||
// Flag parameters: Always consume
|
||||
// Required non-flag parameters: Always consume
|
||||
// Optional non-flag parameters:
|
||||
// - Before required parameters: Consume if there are 'left over' args
|
||||
// - At the end: Always consumes
|
||||
|
||||
if (parameter.isOptional()) {
|
||||
if (parameter.getFlag() != null) {
|
||||
return !parameter.isValueFlag() || context.hasFlag(parameter.getFlag());
|
||||
} else {
|
||||
int numberFree = context.argsLength() - scoped.position();
|
||||
for (int j = i; j < parameters.length; j++) {
|
||||
if (parameters[j].isNonFlagConsumer() && !parameters[j].isOptional()) {
|
||||
// We already checked if the consumed count was > -1
|
||||
// when we created this object
|
||||
numberFree -= parameters[j].getConsumedCount();
|
||||
}
|
||||
}
|
||||
|
||||
// Skip this optional parameter
|
||||
if (numberFree < 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@Override
|
||||
public boolean anyFlags() {
|
||||
return anyFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default value for a parameter.
|
||||
*
|
||||
* @param i the index of the parameter
|
||||
* @param scoped the scoped context
|
||||
* @return a value
|
||||
* @throws ParameterException on an error
|
||||
* @throws CommandException on an error
|
||||
*/
|
||||
public Object getDefaultValue(int i, ContextArgumentStack scoped) throws ParameterException, CommandException, InvocationTargetException {
|
||||
CommandContext context = scoped.getContext();
|
||||
ParameterData parameter = parameters[i];
|
||||
|
||||
String[] defaultValue = parameter.getDefaultValue();
|
||||
if (defaultValue != null) {
|
||||
try {
|
||||
return parameter.getBinding().bind(parameter, new StringArgumentStack(context, defaultValue, false), false);
|
||||
} catch (MissingParameterException e) {
|
||||
throw new ParametricException(
|
||||
"The default value of the parameter using the binding " +
|
||||
parameter.getBinding().getClass() + " in the method\n" +
|
||||
method.toGenericString() + "\nis invalid");
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check to see if all arguments, including flag arguments, were consumed.
|
||||
*
|
||||
* @param scoped the argument scope
|
||||
* @throws UnconsumedParameterException thrown if parameters were not consumed
|
||||
*/
|
||||
public void checkUnconsumed(ContextArgumentStack scoped) throws UnconsumedParameterException {
|
||||
CommandContext context = scoped.getContext();
|
||||
String unconsumed;
|
||||
String unconsumedFlags = getUnusedFlags(context);
|
||||
|
||||
if ((unconsumed = scoped.getUnconsumed()) != null) {
|
||||
throw new UnconsumedParameterException(unconsumed + " " + unconsumedFlags);
|
||||
}
|
||||
|
||||
if (unconsumedFlags != null) {
|
||||
throw new UnconsumedParameterException(unconsumedFlags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any unused flag arguments.
|
||||
*
|
||||
* @param context the command context
|
||||
*/
|
||||
public String getUnusedFlags(CommandContext context) {
|
||||
if (!anyFlags) {
|
||||
Set<Character> unusedFlags = null;
|
||||
for (char flag : context.getFlags()) {
|
||||
boolean found = false;
|
||||
|
||||
if (legacyFlags.contains(flag)) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (ParameterData parameter : parameters) {
|
||||
Character paramFlag = parameter.getFlag();
|
||||
if (paramFlag != null && flag == paramFlag) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (unusedFlags == null) {
|
||||
unusedFlags = new HashSet<Character>();
|
||||
}
|
||||
unusedFlags.add(flag);
|
||||
}
|
||||
}
|
||||
|
||||
if (unusedFlags != null) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Character flag : unusedFlags) {
|
||||
builder.append("-").append(flag).append(" ");
|
||||
}
|
||||
|
||||
return builder.toString().trim();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@Override
|
||||
public String toString() {
|
||||
return method.toGenericString();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -573,7 +360,8 @@ public class ParametricCallable implements CommandCallable {
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
|
||||
public static Class<ParametricCallable> inject() {
|
||||
return ParametricCallable.class;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
51
core/src/main/resources/cs_adv.js
Normal file
51
core/src/main/resources/cs_adv.js
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
|
||||
var ARGUMENT_NAMES = /([^\s,]+)/g;
|
||||
function getParamNames(func) {
|
||||
var a = func.toString().replace(STRIP_COMMENTS, '');
|
||||
var r = a.slice(a.indexOf('(')+1, a.indexOf(')')).match(ARGUMENT_NAMES);
|
||||
var l = new java.util.ArrayList();
|
||||
if(r !== null) {
|
||||
for (var i = 0; i < r.length; i++) {
|
||||
l.add(r[i]);
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
function getAllFunctions(){
|
||||
var a = new java.util.ArrayList();
|
||||
for (var f in this){
|
||||
if (this.hasOwnProperty(f) && this[f] instanceof Function && !/a/i.test(f)){
|
||||
a.add(this[f]);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
var functions = getAllFunctions();
|
||||
var commands = new java.util.ArrayList()
|
||||
for (var i = 0; i < functions.length; i++) {
|
||||
var f = functions[i];
|
||||
if (f.hasOwnProperty('desc'))
|
||||
{
|
||||
if (!f.hasOwnProperty('permission')) f.permission = "fawe.use";
|
||||
if (!f.hasOwnProperty('aliases')) f.aliases = [f.name];
|
||||
if (!f.hasOwnProperty('queued')) f.queued = true;
|
||||
var cmd = com.boydti.fawe.config.Commands.fromArgs(f.aliases, f.usage, f.desc, f.min, f.max, f.flags, f.help, f.queued);
|
||||
var man = com.sk89q.worldedit.extension.platform.CommandManager.getInstance();
|
||||
var builder = man.getBuilder();
|
||||
var args = getParamNames(f);
|
||||
|
||||
var wrap = Java.extend(java.util.function.Function, {
|
||||
apply: function(a) {
|
||||
return f.apply(null, a);
|
||||
}
|
||||
});
|
||||
var w2 = new wrap();
|
||||
var callable = new com.sk89q.worldedit.util.command.parametric.FunctionParametricCallable(builder, "", cmd, f.permission, args, w2);
|
||||
commands.add(callable);
|
||||
}
|
||||
}
|
||||
commands;
|
||||
}
|
Loading…
Reference in New Issue
Block a user