Change mask, pattern and transform syntax

This commit is contained in:
Jesse Boyd 2017-05-09 10:18:19 +10:00
parent 1e31827c9f
commit 69f4b7abd6
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
67 changed files with 3039 additions and 1552 deletions

View File

@ -60,6 +60,7 @@ import com.sk89q.worldedit.command.util.EntityRemover;
import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.extension.factory.DefaultBlockParser;
import com.sk89q.worldedit.extension.factory.DefaultMaskParser;
import com.sk89q.worldedit.extension.factory.DefaultTransformParser;
import com.sk89q.worldedit.extension.factory.HashTagPatternParser;
import com.sk89q.worldedit.extension.platform.AbstractPlayerActor;
import com.sk89q.worldedit.extension.platform.CommandManager;
@ -190,6 +191,10 @@ public class Fawe {
private VisualQueue visualQueue;
private Updater updater;
private TextureUtil textures;
private DefaultTransformParser transformParser;
// @Deprecated
// private boolean isJava8 = MainUtil.getJavaVersion() >= 1.8;
/**
* Get the implementation specific class
@ -273,6 +278,7 @@ public class Fawe {
@Override
public void run() {
try {
transformParser = new DefaultTransformParser(getWorldEdit());
visualQueue = new VisualQueue();
WEManager.IMP.managers.addAll(Fawe.this.IMP.getMaskManagers());
WEManager.IMP.managers.add(new PlotSquaredFeature());
@ -283,7 +289,7 @@ public class Fawe {
TaskManager.IMP.repeat(timer, 1);
if (Settings.IMP.UPDATE && isJava8()) {
if (Settings.IMP.UPDATE) {
// Delayed updating
updater = new Updater();
TaskManager.IMP.async(new Runnable() {
@ -309,10 +315,13 @@ public class Fawe {
return false;
}
private boolean isJava8 = MainUtil.getJavaVersion() >= 1.8;
// @Deprecated
// public boolean isJava8() {
// return isJava8;
// }
public boolean isJava8() {
return isJava8;
public DefaultTransformParser getTransformParser() {
return transformParser;
}
/**

View File

@ -10,14 +10,12 @@ import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.RegionWrapper;
import com.boydti.fawe.object.changeset.DiskStorageHistory;
import com.boydti.fawe.object.mask.CustomMask;
import com.boydti.fawe.object.schematic.Schematic;
import com.boydti.fawe.regions.FaweMaskManager;
import com.boydti.fawe.util.EditSessionBuilder;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MemUtil;
import com.boydti.fawe.util.SetQueue;
import com.boydti.fawe.util.StringMan;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.WEManager;
import com.boydti.fawe.wrappers.WorldWrapper;
@ -26,15 +24,12 @@ import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.ShortTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.tool.BrushTool;
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.extent.Extent;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
@ -42,7 +37,6 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.internal.registry.AbstractFactory;
import com.sk89q.worldedit.internal.registry.InputParser;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.world.AbstractWorld;
import com.sk89q.worldedit.world.World;
import java.io.File;
@ -60,7 +54,6 @@ import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.zip.GZIPInputStream;
@ -94,26 +87,48 @@ public class FaweAPI {
}
/**
* Add a custom mask for use in e.g //mask #id:<input>
* @param name The mask id
* @param mask The mask class
* Add a custom mask for use in e.g {@literal //mask #id:<input>}
* @see com.sk89q.worldedit.command.MaskCommands
* @param methods The class with a bunch of mask methods
* @return true if the mask was registered
*/
public static boolean registerMask(String name, Class<? extends CustomMask> mask) {
public static boolean registerMasks(Object methods) {
DefaultMaskParser parser = getParser(DefaultMaskParser.class);
if (parser != null) parser.register(methods);
return parser != null;
}
/**
* Add a custom material for use in e.g {@literal //material #id:<input>}
* @see com.sk89q.worldedit.command.PatternCommands
* @param methods The class with a bunch of pattern methods
* @return true if the mask was registered
*/
public static boolean registerPatterns(Object methods) {
HashTagPatternParser parser = getParser(HashTagPatternParser.class);
if (parser != null) parser.register(methods);
return parser != null;
}
public static <T> T getParser(Class<T> parserClass) {
try {
Field field = AbstractFactory.class.getDeclaredField("parsers");
field.setAccessible(true);
List<InputParser> parsers = (List<InputParser>) field.get(WorldEdit.getInstance().getMaskFactory());
ArrayList<InputParser> parsers = new ArrayList<>();
parsers.addAll((List<InputParser>) field.get(WorldEdit.getInstance().getMaskFactory()));
parsers.addAll((List<InputParser>) field.get(WorldEdit.getInstance().getBlockFactory()));
parsers.addAll((List<InputParser>) field.get(WorldEdit.getInstance().getItemFactory()));
parsers.addAll((List<InputParser>) field.get(WorldEdit.getInstance().getPatternFactory()));
for (InputParser parser : parsers) {
if (parser instanceof DefaultMaskParser) {
((DefaultMaskParser) parser).addMask(name, mask);
return true;
if (parserClass.isAssignableFrom(parser.getClass())) {
return (T) parser;
}
}
return null;
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return false;
}
/**
@ -151,7 +166,7 @@ public class FaweAPI {
* - The WorldEdit EditSession can do a lot more<br>
* Remember to enqueue it when you're done!<br>
* @see com.boydti.fawe.object.FaweQueue#enqueue()
* @param worldName The name of the world
* @param world The name of the world
* @param autoqueue If it should start dispatching before you enqueue it.
* @return
*/

View File

@ -5,8 +5,11 @@ import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.internal.registry.InputParser;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public abstract class FaweParser<T> extends InputParser<T> {
protected FaweParser(WorldEdit worldEdit) {
@ -37,4 +40,83 @@ public abstract class FaweParser<T> extends InputParser<T> {
}
return remainder;
}
protected static class ParseEntry {
public boolean and;
public String input;
public ParseEntry(String input, boolean type) {
this.input = input;
this.and = type;
}
@Override
public String toString() {
return input + " | " + and;
}
}
public List<Map.Entry<ParseEntry, List<String>>> parse(String command) 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;
for (int i = 0; i < len; i++) {
boolean newEntry = i == 0;
boolean prefix = false;
boolean or = false;
char c = command.charAt(i);
if (i < end) continue;
switch (c) {
case '&':
or = true;
case ',': {
prefix = true;
if (current == null) {
throw new InputParseException("Duplicate separator");
}
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;
}
}
}
String arg = command.substring(i + 1, end);
args.add(arg);
// start
break;
}
}
if (newEntry) {
int index = StringMan.indexOf(command, i + 1, '[', '&', ',');
if (index < 0) index = len;
end = index;
current = command.substring(i + (prefix ? 1 : 0), end);
args = new ArrayList<>();
ParseEntry entry = new ParseEntry(current, or);
keys.add(new AbstractMap.SimpleEntry<ParseEntry, List<String>>(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;
}
}
return keys;
}
}

View File

@ -1,5 +1,15 @@
package com.boydti.fawe.command;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.extent.NullExtent;
import com.boydti.fawe.object.extent.ResettableExtent;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extension.factory.DefaultTransformParser;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
@ -11,6 +21,7 @@ import com.sk89q.worldedit.util.command.parametric.BindingBehavior;
import com.sk89q.worldedit.util.command.parametric.BindingHelper;
import com.sk89q.worldedit.util.command.parametric.BindingMatch;
import com.sk89q.worldedit.util.command.parametric.ParameterException;
import com.sk89q.worldedit.world.World;
import java.lang.annotation.Annotation;
import javax.annotation.Nullable;
@ -50,6 +61,32 @@ public class FawePrimitiveBinding extends BindingHelper {
}
}
/**
* Gets an {@link com.sk89q.worldedit.extent.Extent} from a {@link ArgumentStack}.
*
* @param context the context
* @return an extent
* @throws ParameterException on other error
*/
@BindingMatch(type = ResettableExtent.class,
behavior = BindingBehavior.PROVIDES)
public ResettableExtent getResettableExtent(ArgumentStack context) throws ParameterException, InputParseException {
String input = context.next();
if (input.equalsIgnoreCase("#null")) return new NullExtent();
DefaultTransformParser parser = Fawe.get().getTransformParser();
Actor actor = context.getContext().getLocals().get(Actor.class);
ParserContext parserContext = new ParserContext();
parserContext.setActor(context.getContext().getLocals().get(Actor.class));
if (actor instanceof Entity) {
Extent extent = ((Entity) actor).getExtent();
if (extent instanceof World) {
parserContext.setWorld((World) extent);
}
}
parserContext.setSession(WorldEdit.getInstance().getSessionManager().get(actor));
return parser.parseFromInput(input, parserContext);
}
/**
* Gets a type from a {@link ArgumentStack}.
*

View File

@ -1,13 +1,8 @@
package com.boydti.fawe.command;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.StringMan;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.factory.DefaultMaskParser;
import com.sk89q.worldedit.util.command.parametric.ParameterData;
import com.sk89q.worldedit.world.registry.BundledBlockData;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MaskBinding extends FaweBinding {
@ -20,25 +15,25 @@ public class MaskBinding extends FaweBinding {
@Override
public List<String> getSuggestions(ParameterData parameter, String prefix) {
int index = prefix.lastIndexOf(",");
String start = index != -1 ? prefix.substring(0, index) : "";
String current = index != -1 ? prefix.substring(index) : prefix;
if (current.isEmpty()) {
return MainUtil.prepend(start, Arrays.asList(DefaultMaskParser.ALL_MASKS));
}
if (current.startsWith("#") || current.startsWith("=")) {
return new ArrayList<>();
}
if (StringMan.isAlphanumeric(current.charAt(0) + "")) {
String[] split2 = current.split(":");
if (split2.length == 2 || current.endsWith(":")) {
start = (start.isEmpty() ? split2[0] : start + " " + split2[0]) + ":";
current = split2.length == 2 ? split2[1] : "";
return MainUtil.prepend(start, MainUtil.filter(current, BundledBlockData.getInstance().getBlockStates(split2[0])));
}
List<String> blocks = BundledBlockData.getInstance().getBlockNames(split2[0]);
return MainUtil.prepend(start, blocks);
}
// int index = prefix.lastIndexOf(",");
// String start = index != -1 ? prefix.substring(0, index) : "";
// String current = index != -1 ? prefix.substring(index) : prefix;
// if (current.isEmpty()) {
// return MainUtil.prepend(start, Arrays.asList(DefaultMaskParser.ALL_MASKS));
// }
// if (current.startsWith("#") || current.startsWith("=")) {
// return new ArrayList<>();
// }
// if (StringMan.isAlphanumeric(current.charAt(0) + "")) {
// String[] split2 = current.split(":");
// if (split2.length == 2 || current.endsWith(":")) {
// start = (start.isEmpty() ? split2[0] : start + " " + split2[0]) + ":";
// current = split2.length == 2 ? split2[1] : "";
// return MainUtil.prepend(start, MainUtil.filter(current, BundledBlockData.getInstance().getBlockStates(split2[0])));
// }
// List<String> blocks = BundledBlockData.getInstance().getBlockNames(split2[0]);
// return MainUtil.prepend(start, blocks);
// }
return new ArrayList<>();
}
}

View File

@ -1,12 +1,8 @@
package com.boydti.fawe.command;
import com.boydti.fawe.util.MainUtil;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.factory.HashTagPatternParser;
import com.sk89q.worldedit.util.command.parametric.ParameterData;
import com.sk89q.worldedit.world.registry.BundledBlockData;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class PatternBinding extends FaweBinding {
@ -19,31 +15,32 @@ public class PatternBinding extends FaweBinding {
@Override
public List<String> getSuggestions(ParameterData parameter, String prefix) {
int index = prefix.lastIndexOf(",|%");
String start = index != -1 ? prefix.substring(0, index) : "";
String current = index != -1 ? prefix.substring(index) : prefix;
if (current.isEmpty()) {
return MainUtil.prepend(start, Arrays.asList(HashTagPatternParser.ALL_PATTERNS));
}
if (current.startsWith("#") || current.startsWith("=")) {
return new ArrayList<>();
}
if ("hand".startsWith(prefix)) {
return MainUtil.prepend(start, Arrays.asList("hand"));
}
if ("pos1".startsWith(prefix)) {
return MainUtil.prepend(start, Arrays.asList("pos1"));
}
if (current.contains("|")) {
return new ArrayList<>();
}
String[] split2 = current.split(":");
if (split2.length == 2 || current.endsWith(":")) {
start = (start.isEmpty() ? split2[0] : start + " " + split2[0]) + ":";
current = split2.length == 2 ? split2[1] : "";
return MainUtil.prepend(start, MainUtil.filter(current, BundledBlockData.getInstance().getBlockStates(split2[0])));
}
List<String> blocks = BundledBlockData.getInstance().getBlockNames(split2[0]);
return MainUtil.prepend(start, blocks);
return new ArrayList<>();
// int index = prefix.lastIndexOf(",|%");
// String start = index != -1 ? prefix.substring(0, index) : "";
// String current = index != -1 ? prefix.substring(index) : prefix;
// if (current.isEmpty()) {
// return MainUtil.prepend(start, Arrays.asList(HashTagPatternParser.ALL_PATTERNS));
// }
// if (current.startsWith("#") || current.startsWith("=")) {
// return new ArrayList<>();
// }
// if ("hand".startsWith(prefix)) {
// return MainUtil.prepend(start, Arrays.asList("hand"));
// }
// if ("pos1".startsWith(prefix)) {
// return MainUtil.prepend(start, Arrays.asList("pos1"));
// }
// if (current.contains("|")) {
// return new ArrayList<>();
// }
// String[] split2 = current.split(":");
// if (split2.length == 2 || current.endsWith(":")) {
// start = (start.isEmpty() ? split2[0] : start + " " + split2[0]) + ":";
// current = split2.length == 2 ? split2[1] : "";
// return MainUtil.prepend(start, MainUtil.filter(current, BundledBlockData.getInstance().getBlockStates(split2[0])));
// }
// List<String> blocks = BundledBlockData.getInstance().getBlockNames(split2[0]);
// return MainUtil.prepend(start, blocks);
}
}

View File

@ -217,13 +217,14 @@ public enum BBC {
COMMAND_INVALID_SYNTAX("The command was not used properly (no more help available).", "WorldEdit.Command"),
HELP_SUGGEST("&7Couldn't find %s0. Maybe try one of &c%s1 &7?", "WorldEdit.Help"),
HELP_HEADER_CATEGORIES("Command Types", "WorldEdit.Help"),
HELP_HEADER_SUBCOMMANDS("Subcommands", "WorldEdit.Help"),
HELP_HEADER_COMMAND("&cHelp for: &7%s0", "WorldEdit.Help"),
HELP_ITEM_ALLOWED("&a%s0&8 - &7%s1", "WorldEdit.Help"),
HELP_ITEM_DENIED("&c%s0&8 - &7%s1", "WorldEdit.Help"),
HELP_HEADER("Help: page %s0/%s1", "WorldEdit.Help"),
HELP_HEADER_FOOTER("&7Use: &8//help [type|command] [#]&7\n&7Wiki: https://git.io/vSKE5", "WorldEdit.Help"),
HELP_HEADER_FOOTER("&7Use: &8//help [type|command|search] [#]&7\n&7Wiki: https://git.io/vSKE5", "WorldEdit.Help"),
PROGRESS_MESSAGE("%s1/%s0 (%s2%) @%s3cps %s4s left", "Progress"),
PROGRESS_FINISHED("[ Done! ]", "Progress"),
@ -292,14 +293,14 @@ public enum BBC {
TIP_FAST("&7Tip: Set fast and without undo using &c//fast", "Tips"),
TIP_CANCEL("&7Tip: You can &c//cancel &7an edit in progress", "Tips"),
TIP_MASK("&7Tip: Set a global destination mask with &c/gmask", "Tips"),
TIP_MASK_ANGLE("Tip: Replace upward slopes of 3-20 blocks using&c //replace /-20:-3 bedrock", "Tips"),
TIP_SET_LINEAR("&7Tip: Set blocks linearly with&c //set #l3d:wood,bedrock", "Tips"),
TIP_SURFACE_SPREAD("&7Tip: Spread a flat surface with&c //set #surfacespread:5:0:5:#existing", "Tips"),
TIP_MASK_ANGLE("Tip: Replace upward slopes of 3-20 blocks using&c //replace /[-20][-3] bedrock", "Tips"),
TIP_SET_LINEAR("&7Tip: Set blocks linearly with&c //set #l3d[wood,bedrock]", "Tips"),
TIP_SURFACE_SPREAD("&7Tip: Spread a flat surface with&c //set #surfacespread[5][0][5][#existing]", "Tips"),
TIP_SET_HAND("&7Tip: Use your current hand with &c//set hand", "Tips"),
// replace
TIP_REPLACE_ID("&7Tip: Replace only the block id:&c //replace woodenstair #id:cobblestair", "Tips"),
TIP_REPLACE_LIGHT("Tip: Remove light sources with&c //replace #brightness:1:15 0", "Tips"),
TIP_REPLACE_ID("&7Tip: Replace only the block id:&c //replace woodenstair #id[cobblestair]", "Tips"),
TIP_REPLACE_LIGHT("Tip: Remove light sources with&c //replace #brightness[1][15] 0", "Tips"),
TIP_TAB_COMPLETE("Tip: The replace command supports tab completion", "Tips"),
// clipboard
@ -322,7 +323,7 @@ public enum BBC {
TIP_BRUSH_MASK("&7Tip: Set a brush destination mask with &c/mask", "Tips"),
TIP_BRUSH_MASK_SOURCE("&7Tip: Set a brush source mask with &c/smask", "Tips"),
TIP_BRUSH_TRANSFORM("&7Tip: Set a brush transform with &c/transform", "Tips"),
TIP_BRUSH_RELATIVE("&7Tip: Use a relative clipboard pattern with //br sphere #~:#copy", "Tips"),
TIP_BRUSH_RELATIVE("&7Tip: Use a relative clipboard pattern with //br sphere #~[#copy]", "Tips"),
TIP_BRUSH_COMMAND("&7Tip: Try the command brush &c//br cmd <radius> <cmd1;cmd2>", "Tips"),
// regen
@ -419,10 +420,10 @@ public enum BBC {
if (args[i] == null) {
continue;
}
m = m.replaceAll("%s" + i, args[i].toString());
m = m.replace("%s" + i, args[i].toString());
}
if (args.length > 0) {
m = m.replaceAll("%s", args[0].toString());
m = m.replace("%s", args[0].toString());
}
return m;
}

View File

@ -30,11 +30,11 @@ public class Commands {
}
}
public static Command translate(final Command command) {
public static Command translate(Class clazz, final Command command) {
if (cmdConfig == null || command instanceof TranslatedCommand) {
return command;
}
return new TranslatedCommand(command);
return new TranslatedCommand(clazz.getSimpleName(), command);
}
public static String getAlias(String command) {
@ -53,12 +53,17 @@ public class Commands {
private final String help;
private final Command command;
public TranslatedCommand(Command command) {
public TranslatedCommand(String clazz, Command command) {
String id = command.aliases()[0];
ConfigurationSection commands = cmdConfig.getConfigurationSection(id);
ConfigurationSection commands;
if (cmdConfig.contains(clazz + "." + id) || !cmdConfig.contains(id)) {
commands = cmdConfig.getConfigurationSection(clazz + "." + id);
} else {
commands = cmdConfig.getConfigurationSection(id);
}
boolean set = false;
if (commands == null) {
set = (commands = cmdConfig.createSection(id)) != null;
set = (commands = cmdConfig.createSection(clazz + "." + id)) != null;
}
HashMap<String, Object> options = new HashMap<>();

View File

@ -18,7 +18,6 @@ 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.ArrayList;
import java.util.Collection;
import java.util.UUID;
import java.util.concurrent.ForkJoinPool;
@ -87,7 +86,8 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, CHUNKSECTIONS, SECTION> exte
@Override
public void optimize() {
final ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool();
if (Fawe.get().isJava8()) {
// if (Fawe.get().isJava8())
{
map.forEachChunk(new RunnableVal<FaweChunk>() {
@Override
public void run(final FaweChunk chunk) {
@ -100,21 +100,22 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, CHUNKSECTIONS, SECTION> exte
}
});
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} else {
final ArrayList<Runnable> tasks = new ArrayList<Runnable>(map.size());
map.forEachChunk(new RunnableVal<FaweChunk>() {
@Override
public void run(final FaweChunk chunk) {
tasks.add(new Runnable() {
@Override
public void run() {
chunk.optimize();
}
});
}
});
TaskManager.IMP.parallel(tasks);
}
// else {
// final ArrayList<Runnable> tasks = new ArrayList<Runnable>(map.size());
// map.forEachChunk(new RunnableVal<FaweChunk>() {
// @Override
// public void run(final FaweChunk chunk) {
// tasks.add(new Runnable() {
// @Override
// public void run() {
// chunk.optimize();
// }
// });
// }
// });
// TaskManager.IMP.parallel(tasks);
// }
}

View File

@ -372,7 +372,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
for (int z = 0; z < getLength(); z++) {
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
biomes[index] = biome;
}
}
@ -496,7 +496,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
overlay[index] = (char) pattern.apply(mutable).getCombined();
@ -517,7 +517,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
main[index] = (char) pattern.apply(mutable).getCombined();
@ -537,7 +537,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
floor[index] = (char) pattern.apply(mutable).getCombined();
@ -558,7 +558,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
char combined = (char) pattern.apply(mutable).getCombined();
@ -1063,7 +1063,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
for (int z = 0; z < getLength(); z++) {
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
main[index] = combined;
}
}
@ -1076,7 +1076,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
for (int z = 0; z < getLength(); z++) {
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
floor[index] = combined;
}
}
@ -1090,7 +1090,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
for (int z = 0; z < getLength(); z++) {
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
main[index] = combined;
floor[index] = combined;
}

View File

@ -1,7 +1,10 @@
package com.boydti.fawe.object;
@Deprecated
/**
* @Deprecated use ThreadLocalRandom instead
*/
public class PseudoRandom {
public static PseudoRandom random = new PseudoRandom();
private long state;
@ -32,7 +35,7 @@ public class PseudoRandom {
}
public double nextDouble() {
return Math.max(0, Math.min(1, Math.abs((double) nextLong() / Long.MAX_VALUE)));
return 0x1.0p-63 * (((nextLong()) & 0x7FFFFFFFFFFFFFFFl));
}
public int random(final int n) {

View File

@ -12,6 +12,7 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.mask.BlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.function.operation.Operations;
@ -33,7 +34,7 @@ public class LayerBrush implements Brush {
@Override
public void build(EditSession editSession, Vector position, Pattern ignore, double size) throws MaxChangedBlocksException {
final FaweQueue queue = editSession.getQueue();
final AdjacentAnyMask adjacent = new AdjacentAnyMask(editSession, Arrays.asList(new BaseBlock(0)));
final AdjacentAnyMask adjacent = new AdjacentAnyMask(new BlockMask(editSession, new BaseBlock(0)));
final SolidBlockMask solid = new SolidBlockMask(editSession);
final RadiusMask radius = new RadiusMask(0, (int) size);
visitor = new RecursiveVisitor(vector -> solid.test(vector) && radius.test(vector) && adjacent.test(vector), function -> true);

View File

@ -1,19 +1,17 @@
package com.boydti.fawe.object.brush;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.collection.BlockVectorSet;
import com.boydti.fawe.object.collection.LocalBlockVectorSet;
import com.boydti.fawe.object.mask.AdjacentAnyMask;
import com.boydti.fawe.object.mask.RadiusMask;
import com.boydti.fawe.object.mask.SurfaceMask;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.BreadthFirstSearch;
@ -25,7 +23,7 @@ public class ScatterBrush implements Brush {
private final int count;
private final int distance;
private Mask mask;
private AdjacentAnyMask adjacent;
private AdjacentAnyMask surface;
public ScatterBrush(int count, int distance) {
this.count = count;
@ -46,18 +44,12 @@ public class ScatterBrush implements Brush {
if (this.mask == null) {
this.mask = Masks.alwaysTrue();
}
this.adjacent = new AdjacentAnyMask(editSession, Arrays.asList(new BaseBlock(0)));
for (int id = 0; id < 256; id++) {
if (FaweCache.canPassThrough(id, 0)) {
adjacent.add(new BaseBlock(id, -1));
}
}
final SolidBlockMask solid = new SolidBlockMask(editSession);
surface = new SurfaceMask(editSession);
final RadiusMask radius = new RadiusMask(0, (int) size);
final int distance = Math.min((int) size, this.distance);
RecursiveVisitor visitor = new RecursiveVisitor(vector -> solid.test(vector) && radius.test(vector) && adjacent.test(vector), function -> true);
RecursiveVisitor visitor = new RecursiveVisitor(vector -> radius.test(vector) && surface.test(vector), function -> true);
visitor.visit(position);
visitor.setDirections(Arrays.asList(BreadthFirstSearch.DIAGONAL_DIRECTIONS));
Operations.completeBlindly(visitor);
@ -67,7 +59,6 @@ public class ScatterBrush implements Brush {
length = 1;
visited.add(position);
}
LocalBlockVectorSet placed = new LocalBlockVectorSet();
int maxFails = 1000;
for (int i = 0; i < count; i++) {
@ -98,7 +89,7 @@ public class ScatterBrush implements Brush {
}
public Vector getDirection(Vector pt) {
return adjacent.direction(pt);
return surface.direction(pt);
}
public void apply(EditSession editSession, LocalBlockVectorSet placed, Vector pt, Pattern p, double size) throws MaxChangedBlocksException {

View File

@ -2,13 +2,12 @@ package com.boydti.fawe.object.brush;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.collection.LocalBlockVectorSet;
import com.boydti.fawe.object.mask.AdjacentAnyMask;
import com.boydti.fawe.object.mask.SurfaceMask;
import com.boydti.fawe.object.pattern.BiomePattern;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.SolidBlockMask;
@ -43,14 +42,14 @@ public class SplatterBrush extends ScatterBrush {
finalPattern = p;
}
final int size2 = (int) (size * size);
final AdjacentAnyMask adjacent = new AdjacentAnyMask(editSession, Arrays.asList(new BaseBlock(0)));
SurfaceMask surface = new SurfaceMask(editSession);
final SolidBlockMask solid = new SolidBlockMask(editSession);
RecursiveVisitor visitor = new RecursiveVisitor(new Mask() {
@Override
public boolean test(Vector vector) {
double dist = vector.distanceSq(position);
if (dist < size2 && !placed.contains(vector) && (PseudoRandom.random.random(5) < 2) && solid.test(vector) && adjacent.test(vector)) {
if (dist < size2 && !placed.contains(vector) && (PseudoRandom.random.random(5) < 2) && surface.test(vector)) {
placed.add(vector);
return true;
}

View File

@ -10,6 +10,7 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.mask.RegionMask;
import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.function.operation.Operations;
@ -45,7 +46,7 @@ public class StencilBrush extends HeightBrush {
map.setSize(size);
int cutoff = onlyWhite ? maxY : 0;
final SolidBlockMask solid = new SolidBlockMask(editSession);
final AdjacentAnyMask adjacent = new AdjacentAnyMask(editSession, solid.getInverseBlocks());
final AdjacentAnyMask adjacent = new AdjacentAnyMask(Masks.negate(solid));
RegionMask region = new RegionMask(new CuboidRegion(position.subtract(size, size, size), position.add(size, size, size)));
RecursiveVisitor visitor = new RecursiveVisitor(new Mask() {
@Override

View File

@ -1,15 +1,11 @@
package com.boydti.fawe.object.brush;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.mask.AdjacentAnyMask;
import com.boydti.fawe.object.mask.RadiusMask;
import com.boydti.fawe.object.mask.SurfaceMask;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern;
@ -20,19 +16,10 @@ import java.util.Arrays;
public class SurfaceSphereBrush implements Brush {
@Override
public void build(EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
Mask mask = editSession.getMask();
if (mask == null) {
mask = Masks.alwaysTrue();
}
AdjacentAnyMask adjacent = new AdjacentAnyMask(editSession, Arrays.asList(new BaseBlock(0)));
for (int id = 0; id < 256; id++) {
if (FaweCache.canPassThrough(id, 0)) {
adjacent.add(new BaseBlock(id, -1));
}
}
SurfaceMask surface = new SurfaceMask(editSession);
final SolidBlockMask solid = new SolidBlockMask(editSession);
final RadiusMask radius = new RadiusMask(0, (int) size);
RecursiveVisitor visitor = new RecursiveVisitor(vector -> solid.test(vector) && radius.test(vector) && adjacent.test(vector), vector -> editSession.setBlock(vector, pattern));
RecursiveVisitor visitor = new RecursiveVisitor(vector -> radius.test(vector) && surface.test(vector), vector -> editSession.setBlock(vector, pattern));
visitor.visit(position);
visitor.setDirections(Arrays.asList(BreadthFirstSearch.DIAGONAL_DIRECTIONS));
Operations.completeBlindly(visitor);

View File

@ -1,16 +1,15 @@
package com.boydti.fawe.object.collection;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.random.SimpleRandom;
import com.boydti.fawe.util.MathMan;
import java.util.ArrayList;
import java.util.Map;
public class FastRandomCollection<T> extends RandomCollection<T> {
private PseudoRandom random = new PseudoRandom();
private T[] values;
public FastRandomCollection(Map<T, Double> weights) {
super(weights);
public FastRandomCollection(Map<T, Double> weights, SimpleRandom random) {
super(weights, random);
int max = 0;
int[] counts = new int[weights.size()];
Double[] weightDoubles = weights.values().toArray(new Double[weights.size()]);
@ -39,7 +38,7 @@ public class FastRandomCollection<T> extends RandomCollection<T> {
}
@Override
public T next() {
return values[random.nextInt(values.length)];
public T next(int x, int y, int z) {
return values[random.nextInt(x, y, z, values.length)];
}
}

View File

@ -1,17 +1,34 @@
package com.boydti.fawe.object.collection;
import com.boydti.fawe.object.random.SimpleRandom;
import java.util.Map;
public abstract class RandomCollection<T> {
public RandomCollection(Map<T, Double> weights) {}
public static <T> RandomCollection<T> of(Map<T, Double> weights) {
import static com.google.common.base.Preconditions.checkNotNull;
public abstract class RandomCollection<T> {
protected SimpleRandom random;
public RandomCollection(Map<T, Double> weights, SimpleRandom random) {
this.random = random;
}
public static <T> RandomCollection<T> of(Map<T, Double> weights, SimpleRandom random) {
try {
return new FastRandomCollection<>(weights);
return new FastRandomCollection<>(weights, random);
} catch (IllegalArgumentException ignore) {
return new SimpleRandomCollection<>(weights);
return new SimpleRandomCollection<>(weights, random);
}
}
public abstract T next();
public void setRandom(SimpleRandom random) {
checkNotNull(random);
this.random = random;
}
public SimpleRandom getRandom() {
return random;
}
public abstract T next(int x, int y, int z);
}

View File

@ -1,23 +1,20 @@
package com.boydti.fawe.object.collection;
import com.boydti.fawe.object.random.SimpleRandom;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Random;
import java.util.TreeMap;
public class SimpleRandomCollection<E> extends RandomCollection<E> {
private final NavigableMap<Double, E> map = new TreeMap<Double, E>();
private final Random random;
private double total = 0;
public SimpleRandomCollection(Map<E, Double> weights) {
super(weights);
this.random = new Random();
public SimpleRandomCollection(Map<E, Double> weights, SimpleRandom random) {
super(weights, random);
for (Map.Entry<E, Double> entry : weights.entrySet()) {
add(entry.getValue(), entry.getKey());
}
}
public void add(double weight, E result) {
@ -26,8 +23,7 @@ public class SimpleRandomCollection<E> extends RandomCollection<E> {
map.put(total, result);
}
public E next() {
double value = random.nextDouble() * total;
return map.ceilingEntry(value).getValue();
public E next(int x, int y, int z) {
return map.ceilingEntry(random.nextDouble(x, y, z)).getValue();
}
}

View File

@ -1,59 +0,0 @@
package com.boydti.fawe.object.extent;
import com.sk89q.worldedit.MutableBlockVector;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.regions.Region;
import static com.google.common.base.Preconditions.checkNotNull;
public class ClipboardExtent extends ResettableExtent {
private final Clipboard clipboard;
private final Vector origin;
private final boolean ignoreAir;
private Extent extent;
private final MutableBlockVector mutable = new MutableBlockVector();
public ClipboardExtent(Extent parent, Clipboard clipboard, boolean ignoreAir) {
super(parent);
checkNotNull(clipboard);
this.extent = parent;
this.clipboard = clipboard;
this.origin = clipboard.getOrigin();
this.ignoreAir = ignoreAir;
}
@Override
public boolean setBlock(Vector to, BaseBlock block) throws WorldEditException {
Region region = clipboard.getRegion();
ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, clipboard.getRegion(), clipboard.getOrigin(), extent, to);
if (ignoreAir) {
copy.setSourceMask(new ExistingBlockMask(clipboard));
}
Operations.completeLegacy(copy);
return true;
}
@Override
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
mutable.mutX(x);
mutable.mutY(y);
mutable.mutZ(z);
return setBlock(mutable, block);
}
@Override
public ResettableExtent setExtent(Extent extent) {
this.extent = extent;
return super.setExtent(extent);
}
}

View File

@ -1,162 +0,0 @@
package com.boydti.fawe.object.extent;
import com.boydti.fawe.object.mask.CustomMask;
import com.boydti.fawe.util.ExtentTraverser;
import com.sk89q.worldedit.EmptyClipboardException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.factory.DefaultMaskParser;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.NoMatchException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.NullExtent;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.internal.registry.InputParser;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.session.ClipboardHolder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Parses mask input strings.
*/
public class DefaultTransformParser extends InputParser<ResettableExtent> {
public DefaultTransformParser(WorldEdit worldEdit) {
super(worldEdit);
}
private static CustomMask[] customMasks = new CustomMask[0];
public void addMask(CustomMask mask) {
checkNotNull(mask);
List<CustomMask> list = new ArrayList<>(Arrays.asList(customMasks));
list.add(mask);
customMasks = list.toArray(new CustomMask[list.size()]);
}
public List<CustomMask> getCustomMasks() {
return Arrays.asList(customMasks);
}
@Override
public ResettableExtent parseFromInput(String input, ParserContext context) throws InputParseException {
Extent extent = new NullExtent();
for (String component : input.split(" ")) {
if (component.isEmpty()) {
continue;
}
extent = getTansformComponent(extent, component, context);
}
if (extent instanceof ResettableExtent) {
return (ResettableExtent) extent;
}
return null;
}
private ResettableExtent getTansformComponent(Extent parent, String component, ParserContext context) throws InputParseException {
final char firstChar = component.charAt(0);
switch (firstChar) {
case '#':
int colon = component.indexOf(':');
if (colon != -1) {
String rest = component.substring(colon + 1);
switch (component.substring(0, colon).toLowerCase()) {
case "#pattern": {
Pattern pattern = worldEdit.getPatternFactory().parseFromInput(rest, context);
return new PatternTransform(parent, pattern);
}
case "#offset": {
try {
String[] split2 = component.split(":");
double x = Math.abs(Expression.compile(split2[1]).evaluate());
double y = Math.abs(Expression.compile(split2[2]).evaluate());
double z = Math.abs(Expression.compile(split2[3]).evaluate());
rest = rest.substring(Math.min(rest.length(), split2[1].length() + split2[2].length() + split2[3].length() + 3));
if (!rest.isEmpty()) {
parent = parseFromInput(rest, context);
}
return new OffsetExtent(parent, (int) x, (int) y, (int) z);
} catch (NumberFormatException | ExpressionException e) {
throw new InputParseException("The correct format is #offset:<dx>:<dy>:<dz>");
}
}
case "#scale": {
try {
String[] split2 = component.split(":");
double x = Math.abs(Expression.compile(split2[1]).evaluate());
double y = Math.abs(Expression.compile(split2[2]).evaluate());
double z = Math.abs(Expression.compile(split2[3]).evaluate());
rest = rest.substring(Math.min(rest.length(), split2[1].length() + split2[2].length() + split2[3].length() + 3));
if (!rest.isEmpty()) {
parent = parseFromInput(rest, context);
}
return new ScaleTransform(parent, x, y, z);
} catch (NumberFormatException | ExpressionException e) {
throw new InputParseException("The correct format is #scale:<dx>:<dy>:<dz>");
}
}
case "#rotate": {
try {
String[] split2 = component.split(":");
double x = (Expression.compile(split2[1]).evaluate());
double y = (Expression.compile(split2[2]).evaluate());
double z = (Expression.compile(split2[3]).evaluate());
rest = rest.substring(Math.min(rest.length(), split2[1].length() + split2[2].length() + split2[3].length() + 3));
if (!rest.isEmpty()) {
parent = parseFromInput(rest, context);
}
ExtentTraverser traverser = new ExtentTraverser(parent).find(TransformExtent.class);
BlockTransformExtent affine = (TransformExtent) (traverser != null ? traverser.get() : null);
if (affine == null) {
parent = affine = new TransformExtent(parent, context.requireWorld().getWorldData().getBlockRegistry());
}
AffineTransform transform = (AffineTransform) affine.getTransform();
transform = transform.rotateX(x);
transform = transform.rotateY(y);
transform = transform.rotateZ(z);
affine.setTransform(transform);
return (ResettableExtent) parent;
} catch (NumberFormatException | ExpressionException e) {
throw new InputParseException("The correct format is #rotate:<dx>:<dy>:<dz>");
}
}
default:
throw new NoMatchException("Unrecognized transform '" + component + "'");
}
} else {
switch (component) {
case "#clipboard": {
LocalSession session = context.requireSession();
if (session != null) {
try {
ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard();
return new ClipboardExtent(parent, clipboard, true);
} catch (EmptyClipboardException e) {
throw new InputParseException("To use #clipboard, please first copy something to your clipboard");
}
} else {
throw new InputParseException("No session is available, so no clipboard is available");
}
}
}
}
default:
throw new NoMatchException("Unrecognized transform '" + component + "'");
}
}
public static Class<?> inject() {
return DefaultTransformParser.class;
}
}

View File

@ -11,14 +11,13 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.Collection;
import javax.annotation.Nullable;
public abstract class FaweRegionExtent extends AbstractDelegateExtent {
public abstract class FaweRegionExtent extends ResettableExtent {
private final FaweLimit limit;
/**

View File

@ -0,0 +1,39 @@
package com.boydti.fawe.object.extent;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import java.util.Arrays;
import java.util.Collection;
public class Linear3DTransform extends SelectTransform {
private final Collection<ResettableExtent> extents;
private final ResettableExtent[] extentsArray;
public Linear3DTransform(ResettableExtent[] extents) {
this.extentsArray = extents;
this.extents = Arrays.asList(extents);
}
@Override
public ResettableExtent setExtent(Extent extent) {
for (ResettableExtent cur : extentsArray) {
cur.setExtent(extent);
}
return this;
}
@Override
public AbstractDelegateExtent getExtent(int x, int y, int z) {
int index = (x + y + z) % extentsArray.length;
if (index < 0) {
index += extentsArray.length;
}
return extentsArray[index];
}
@Override
public AbstractDelegateExtent getExtent(int x, int z) {
return getExtent(x, 0, z);
}
}

View File

@ -0,0 +1,39 @@
package com.boydti.fawe.object.extent;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import java.util.Arrays;
import java.util.Collection;
public class LinearTransform extends SelectTransform {
private final Collection<ResettableExtent> extents;
private final ResettableExtent[] extentsArray;
private int index;
public LinearTransform(ResettableExtent[] extents) {
this.extentsArray = extents;
this.extents = Arrays.asList(extents);
}
@Override
public ResettableExtent setExtent(Extent extent) {
for (ResettableExtent cur : extentsArray) {
cur.setExtent(extent);
}
return this;
}
@Override
public AbstractDelegateExtent getExtent(int x, int y, int z) {
if (index == extentsArray.length) {
index = 0;
}
return extentsArray[index];
}
@Override
public AbstractDelegateExtent getExtent(int x, int z) {
return getExtent(x, 0, z);
}
}

View File

@ -0,0 +1,59 @@
package com.boydti.fawe.object.extent;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.Collection;
import javax.annotation.Nullable;
public class MultiTransform extends RandomTransform {
private AbstractDelegateExtent[] extents;
public MultiTransform(Collection<ResettableExtent> extents) {
for (ResettableExtent extent : extents) add(extent, 1);
}
public MultiTransform() {
this.extents = new AbstractDelegateExtent[0];
}
@Override
public void add(ResettableExtent extent, double chance) {
super.add(extent, chance);
this.extents = getExtents().toArray(new AbstractDelegateExtent[getExtents().size()]);
}
@Override
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
boolean result = false;
for (AbstractDelegateExtent extent : extents) result |= extent.setBlock(x, y, z, block);
return result;
}
@Override
public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException {
boolean result = false;
for (AbstractDelegateExtent extent : extents) result |= extent.setBlock(location, block);
return result;
}
@Override
public boolean setBiome(Vector2D position, BaseBiome biome) {
boolean result = false;
for (AbstractDelegateExtent extent : extents) result |= extent.setBiome(position, biome);
return result;
}
@Nullable
@Override
public Entity createEntity(Location location, BaseEntity entity) {
Entity created = null;
for (AbstractDelegateExtent extent : extents) created = extent.createEntity(location, entity);
return created;
}
}

View File

@ -34,6 +34,16 @@ public class NullExtent extends FaweRegionExtent {
this.reason = failReason;
}
public NullExtent() {
super(new com.sk89q.worldedit.extent.NullExtent(), FaweLimit.MAX);
this.reason = BBC.WORLDEDIT_CANCEL_REASON_MANUAL;
}
@Override
public ResettableExtent setExtent(Extent extent) {
return this;
}
@Override
public BaseBiome getBiome(final Vector2D arg0) {
throw new FaweException(reason);

View File

@ -21,21 +21,16 @@ public class OffsetExtent extends ResettableExtent {
@Override
public boolean setBiome(Vector2D position, BaseBiome biome) {
return super.setBiome(mutable.setComponents(position.getBlockX() + dx, position.getBlockZ() + dz), biome);
return getExtent().setBiome(mutable.setComponents(position.getBlockX() + dx, position.getBlockZ() + dz), biome);
}
@Override
public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException {
return super.setBlock(location.getBlockX() + dx, location.getBlockY() + dy, location.getBlockZ() + dz, block);
return getExtent().setBlock(location.getBlockX() + dx, location.getBlockY() + dy, location.getBlockZ() + dz, block);
}
@Override
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
return super.setBlock(x + dx, y + dy, z + dz, block);
}
@Override
public ResettableExtent setExtent(Extent extent) {
return super.setExtent(extent);
return getExtent().setBlock(x + dx, y + dy, z + dz, block);
}
}

View File

@ -0,0 +1,52 @@
package com.boydti.fawe.object.extent;
import com.sk89q.worldedit.MutableBlockVector2D;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.SplittableRandom;
public class RandomOffsetTransform extends ResettableExtent {
private final int dx, dy, dz;
private final SplittableRandom random;
private MutableBlockVector2D mutable = new MutableBlockVector2D();
public RandomOffsetTransform(Extent parent, int dx, int dy, int dz) {
super(parent);
this.dx = dx + 1;
this.dy = dy + 1;
this.dz = dz + 1;
this.random = new SplittableRandom();
}
@Override
public boolean setBiome(Vector2D pos, BaseBiome biome) {
int x = pos.getBlockX() + random.nextInt(1 + (dx << 1)) - dx;
int z = pos.getBlockZ() + random.nextInt(1 + (dz << 1)) - dz;
return super.setBiome(mutable.setComponents(x, z), biome);
}
@Override
public boolean setBlock(Vector pos, BaseBlock block) throws WorldEditException {
int x = pos.getBlockX() + random.nextInt(1 + (dx << 1)) - dx;
int y = pos.getBlockY() + random.nextInt(1 + (dy << 1)) - dy;
int z = pos.getBlockZ() + random.nextInt(1 + (dz << 1)) - dz;
return super.setBlock(x, y, z, block);
}
@Override
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
x = x + random.nextInt(1 + (dx << 1)) - dx;
y = y + random.nextInt(1 + (dy << 1)) - dy;
z = z + random.nextInt(1 + (dz << 1)) - dz;
return super.setBlock(x, y, z, block);
}
@Override
public ResettableExtent setExtent(Extent extent) {
return super.setExtent(extent);
}
}

View File

@ -0,0 +1,83 @@
package com.boydti.fawe.object.extent;
import com.boydti.fawe.object.collection.RandomCollection;
import com.boydti.fawe.object.random.SimpleRandom;
import com.boydti.fawe.object.random.TrueRandom;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.pattern.RandomPattern;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Uses a random pattern of a weighted list of patterns.
*/
public class RandomTransform extends SelectTransform {
private final SimpleRandom random;
private Map<ResettableExtent, Double> weights = new HashMap<>();
private RandomCollection<ResettableExtent> collection;
private LinkedHashSet<ResettableExtent> extents = new LinkedHashSet<>();
public RandomTransform() {
this(new TrueRandom());
}
@Override
public AbstractDelegateExtent getExtent(int x, int y, int z) {
return collection.next(x, y, z);
}
@Override
public AbstractDelegateExtent getExtent(int x, int z) {
return collection.next(x, 0, z);
}
public RandomTransform(SimpleRandom random) {
this.random = random;
}
@Override
public ResettableExtent setExtent(Extent extent) {
for (AbstractDelegateExtent current : extents) {
if (current instanceof ResettableExtent) {
((ResettableExtent) current).setExtent(extent);
}
}
return this;
}
/**
* Add a pattern to the weight list of patterns.
*
* <p>The probability for the pattern added is chance / max where max is
* the sum of the probabilities of all added patterns.</p>
*
* @param extent the extent
* @param chance the chance, which can be any positive number
*/
public void add(ResettableExtent extent, double chance) {
checkNotNull(extent);
weights.put(extent, chance);
collection = RandomCollection.of(weights, random);
this.extents.add(extent);
}
public Set<ResettableExtent> getExtents() {
return extents;
}
public RandomCollection<ResettableExtent> getCollection() {
return collection;
}
public static Class<?> inject() {
return RandomPattern.class;
}
}

View File

@ -3,6 +3,7 @@ package com.boydti.fawe.object.extent;
import com.boydti.fawe.util.ExtentTraverser;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.world.World;
import static com.google.common.base.Preconditions.checkNotNull;
@ -14,10 +15,11 @@ public class ResettableExtent extends AbstractDelegateExtent {
public ResettableExtent setExtent(Extent extent) {
checkNotNull(extent);
if (getExtent() instanceof ResettableExtent) {
((ResettableExtent) getExtent()).setExtent(extent);
Extent next = getExtent();
if (!(next instanceof NullExtent) && !(next instanceof World) && next instanceof ResettableExtent) {
((ResettableExtent) next).setExtent(extent);
} else {
new ExtentTraverser(this).setNext(extent);
new ExtentTraverser(this).setNext(new AbstractDelegateExtent(extent));
}
return this;
}

View File

@ -0,0 +1,50 @@
package com.boydti.fawe.object.extent;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.*;
import com.sk89q.worldedit.extent.NullExtent;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.biome.BaseBiome;
import javax.annotation.Nullable;
public abstract class SelectTransform extends ResettableExtent {
public SelectTransform() {
super(new NullExtent());
}
public abstract AbstractDelegateExtent getExtent(int x, int y, int z);
public abstract AbstractDelegateExtent getExtent(int x, int z);
public Extent getExtent(Vector pos) {
return getExtent(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ());
}
public Extent getExtent(Vector2D pos) {
return getExtent(pos.getBlockX(), pos.getBlockZ());
}
@Override
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
return getExtent(x, y, z).setBlock(x, y, z, block);
}
@Override
public boolean setBlock(Vector position, BaseBlock block) throws WorldEditException {
return getExtent(position).setBlock(position, block);
}
@Nullable
@Override
public Entity createEntity(Location position, BaseEntity entity) {
return getExtent(position.getBlockX(), position.getBlockY(), position.getBlockZ()).createEntity(position, entity);
}
@Override
public boolean setBiome(Vector2D position, BaseBiome biome) {
return getExtent(position).setBiome(position, biome);
}
}

View File

@ -2,25 +2,22 @@ package com.boydti.fawe.object.mask;
import com.sk89q.worldedit.MutableBlockVector;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.BlockMask;
import java.util.Arrays;
import java.util.Collection;
import com.sk89q.worldedit.function.mask.Mask;
/**
* Just an optimized version of the Adjacent Mask for single adjacency
*/
public class AdjacentAnyMask extends BlockMask {
public class AdjacentAnyMask implements Mask {
private final Mask mask;
private MutableBlockVector mutable = new MutableBlockVector();
public AdjacentAnyMask(Extent extent, BaseBlock... blocks) {
this(extent, Arrays.asList(blocks));
public AdjacentAnyMask(Mask mask) {
this.mask = mask;
}
public AdjacentAnyMask(Extent extent, Collection<BaseBlock> blocks) {
super(extent, blocks);
public Mask getMask() {
return mask;
}
@Override
@ -29,19 +26,19 @@ public class AdjacentAnyMask extends BlockMask {
int y = v.getBlockY();
int z = v.getBlockZ();
v.mutY(y + 1);
if (super.test(v)) { v.mutY(y); return true; }
if (mask.test(v)) { v.mutY(y); return true; }
v.mutY(y - 1);
if (super.test(v)) { v.mutY(y); return true; }
if (mask.test(v)) { v.mutY(y); return true; }
v.mutY(y);
v.mutX(x + 1);
if (super.test(v)) { v.mutX(x); return true; }
if (mask.test(v)) { v.mutX(x); return true; }
v.mutX(x - 1);
if (super.test(v)) { v.mutX(x); return true; }
if (mask.test(v)) { v.mutX(x); return true; }
v.mutX(x);
v.mutZ(z + 1);
if (super.test(v)) { v.mutZ(z); return true; }
if (mask.test(v)) { v.mutZ(z); return true; }
v.mutZ(z - 1);
if (super.test(v)) { v.mutZ(z); return true; }
if (mask.test(v)) { v.mutZ(z); return true; }
v.mutZ(z);
return false;
}
@ -51,19 +48,19 @@ public class AdjacentAnyMask extends BlockMask {
int y = v.getBlockY();
int z = v.getBlockZ();
v.mutY(y + 1);
if (super.test(v)) { v.mutY(y); return mutable.setComponents(0, 1, 0); }
if (mask.test(v)) { v.mutY(y); return mutable.setComponents(0, 1, 0); }
v.mutY(y - 1);
if (super.test(v)) { v.mutY(y); return mutable.setComponents(0, -1, 0); }
if (mask.test(v)) { v.mutY(y); return mutable.setComponents(0, -1, 0); }
v.mutY(y);
v.mutX(x + 1);
if (super.test(v)) { v.mutX(x); return mutable.setComponents(1, 0, 0); }
if (mask.test(v)) { v.mutX(x); return mutable.setComponents(1, 0, 0); }
v.mutX(x - 1);
if (super.test(v)) { v.mutX(x); return mutable.setComponents(-1, 0, 0); }
if (mask.test(v)) { v.mutX(x); return mutable.setComponents(-1, 0, 0); }
v.mutX(x);
v.mutZ(z + 1);
if (super.test(v)) { v.mutZ(z); return mutable.setComponents(0, 0, 1); }
if (mask.test(v)) { v.mutZ(z); return mutable.setComponents(0, 0, 1); }
v.mutZ(z - 1);
if (super.test(v)) { v.mutZ(z); return mutable.setComponents(0, 0, - 1); }
if (mask.test(v)) { v.mutZ(z); return mutable.setComponents(0, 0, - 1); }
v.mutZ(z);
return null;
}

View File

@ -1,16 +1,14 @@
package com.boydti.fawe.object.mask;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.BlockMask;
import java.util.Collection;
import com.sk89q.worldedit.function.mask.Mask;
public class AdjacentMask extends BlockMask {
public class AdjacentMask implements Mask {
private final int min, max;
private final Mask mask;
public AdjacentMask(Extent extent, Collection<BaseBlock> blocks, int requiredMin, int requiredMax) {
super(extent, blocks);
public AdjacentMask(Mask mask, int requiredMin, int requiredMax) {
this.mask = mask;
this.min = requiredMin;
this.max = requiredMax;
}
@ -22,19 +20,19 @@ public class AdjacentMask extends BlockMask {
double y = v.getY();
double z = v.getZ();
v.mutX(x + 1);
if (super.test(v) && ++count == min && max >= 8) { v.mutX(x); return true; }
if (mask.test(v) && ++count == min && max >= 8) { v.mutX(x); return true; }
v.mutX(x - 1);
if (super.test(v) && ++count == min && max >= 8) { v.mutX(x); return true; }
if (mask.test(v) && ++count == min && max >= 8) { v.mutX(x); return true; }
v.mutX(x);
v.mutY(y + 1);
if (super.test(v) && ++count == min && max >= 8) { v.mutY(y); return true; }
if (mask.test(v) && ++count == min && max >= 8) { v.mutY(y); return true; }
v.mutY(y - 1);
if (super.test(v) && ++count == min && max >= 8) { v.mutY(y); return true; }
if (mask.test(v) && ++count == min && max >= 8) { v.mutY(y); return true; }
v.mutY(y);
v.mutZ(z + 1);
if (super.test(v) && ++count == min && max >= 8) { v.mutZ(z); return true; }
if (mask.test(v) && ++count == min && max >= 8) { v.mutZ(z); return true; }
v.mutZ(z - 1);
if (super.test(v) && ++count == min && max >= 8) { v.mutZ(z); return true; }
if (mask.test(v) && ++count == min && max >= 8) { v.mutZ(z); return true; }
v.mutZ(z);
return count >= min && count <= max;
}

View File

@ -0,0 +1,24 @@
package com.boydti.fawe.object.mask;
import com.sk89q.worldedit.MutableBlockVector2D;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.AbstractExtentMask;
import com.sk89q.worldedit.world.biome.BaseBiome;
public class BiomeMask extends AbstractExtentMask {
private final BaseBiome biome;
private MutableBlockVector2D mutable = new MutableBlockVector2D();
public BiomeMask(Extent extent, BaseBiome biome) {
super(extent);
this.biome = biome;
}
@Override
public boolean test(Vector vector) {
Vector2D pos = mutable.setComponents(vector.getBlockX(), vector.getBlockZ());
return getExtent().getBiome(pos).getId() == biome.getId();
}
}

View File

@ -1,25 +0,0 @@
package com.boydti.fawe.object.mask;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.function.mask.Mask;
import java.util.List;
public abstract class CustomMask implements Mask {
/**
* Constructor for custom mask
* When used in commands, use #custom:<input>
* @param masks Any previous masks set (usually from //mask [previous] [thismask]
* @param input The input to parse
* @param context The context (for extent, player etc)
*/
public CustomMask(List<Mask> masks, String input, ParserContext context) {
try {
this.getClass(). getConstructor ( List.class, String.class, ParserContext.class ) ;
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Constructor for " + getClass() + " must be <init>(List.class, String.class, ParserContext.class)");
}
}
public abstract String description();
}

View File

@ -0,0 +1,20 @@
package com.boydti.fawe.object.mask;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.function.mask.AbstractMask;
import java.util.SplittableRandom;
public class RandomMask extends AbstractMask {
private final SplittableRandom random;
private final double threshold;
public RandomMask(double threshold) {
this.random = new SplittableRandom();
this.threshold = (threshold - 0.5) * Integer.MAX_VALUE;
}
@Override
public boolean test(Vector vector) {
return random.nextInt() <= threshold;
}
}

View File

@ -0,0 +1,21 @@
package com.boydti.fawe.object.mask;
import com.boydti.fawe.object.random.SimplexNoise;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.function.mask.AbstractMask;
public class SimplexMask extends AbstractMask {
private final double min, max, scale;
public SimplexMask(double scale, double min, double max) {
this.scale = scale;
this.min = min;
this.max = max;
}
@Override
public boolean test(Vector vector) {
double value = SimplexNoise.noise(vector.getBlockX() * scale, vector.getBlockY() * scale, vector.getBlockZ() * scale);
return value >= min && value <= max;
}
}

View File

@ -4,20 +4,24 @@ import com.boydti.fawe.FaweCache;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.BlockMask;
public class SurfaceMask extends AdjacentAnyMask {
private final Extent extent;
public SurfaceMask(Extent extent) {
super(extent);
super(new BlockMask(extent, new BaseBlock(0)));
BlockMask mask = (BlockMask) getMask();
for (int id = 0; id < 256; id++) {
if (FaweCache.canPassThrough(id, 0)) {
add(new BaseBlock(id, -1));
mask.add(new BaseBlock(id, -1));
}
}
this.extent = extent;
}
@Override
public boolean test(Vector v) {
BaseBlock block = getExtent().getBlock(v);
return !test(block.getId()) && super.test(v);
return !getMask().test(v) && super.test(v);
}
}

View File

@ -1,16 +1,14 @@
package com.boydti.fawe.object.mask;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.BlockMask;
import java.util.Collection;
import com.sk89q.worldedit.function.mask.Mask;
public class WallMask extends BlockMask {
public class WallMask implements Mask {
private final int min, max;
private final Mask mask;
public WallMask(Extent extent, Collection<BaseBlock> blocks, int requiredMin, int requiredMax) {
super(extent, blocks);
public WallMask(Mask mask, int requiredMin, int requiredMax) {
this.mask = mask;
this.min = requiredMin;
this.max = requiredMax;
}
@ -22,14 +20,14 @@ public class WallMask extends BlockMask {
double y = v.getY();
double z = v.getZ();
v.mutX(x + 1);
if (super.test(v) && ++count == min && max >= 8) { v.mutX(x); return true; }
if (mask.test(v) && ++count == min && max >= 8) { v.mutX(x); return true; }
v.mutX(x - 1);
if (super.test(v) && ++count == min && max >= 8) { v.mutX(x); return true; }
if (mask.test(v) && ++count == min && max >= 8) { v.mutX(x); return true; }
v.mutX(x);
v.mutZ(z + 1);
if (super.test(v) && ++count == min && max >= 8) { v.mutZ(z); return true; }
if (mask.test(v) && ++count == min && max >= 8) { v.mutZ(z); return true; }
v.mutZ(z - 1);
if (super.test(v) && ++count == min && max >= 8) { v.mutZ(z); return true; }
if (mask.test(v) && ++count == min && max >= 8) { v.mutZ(z); return true; }
v.mutZ(z);
return count >= min && count <= max;
}

View File

@ -0,0 +1,54 @@
package com.boydti.fawe.object.pattern;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.collection.LocalBlockVectorSet;
import com.boydti.fawe.util.FaweTimer;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.pattern.AbstractPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
public class BufferedPattern2D extends AbstractPattern implements ResettablePattern {
private final Pattern pattern;
private final LocalBlockVectorSet set = new LocalBlockVectorSet();
private final FaweTimer timer;
private final long[] actionTime;
public BufferedPattern2D(FawePlayer fp, Pattern parent) {
long[] actionTime = fp.getMeta("lastActionTime");
if (actionTime == null) fp.setMeta("lastActionTime", actionTime = new long[2]);
this.actionTime = actionTime;
this.pattern = parent;
this.timer = Fawe.get().getTimer();
}
@Override
public BaseBlock apply(Vector position) {
return pattern.apply(position);
}
@Override
public boolean apply(Extent extent, Vector setPosition, Vector getPosition) throws WorldEditException {
long now = timer.getTick();
try {
if (!set.add(setPosition.getBlockX(), 0, setPosition.getBlockZ())) {
return false;
}
return pattern.apply(extent, setPosition, getPosition);
} catch (UnsupportedOperationException ignore) {}
return false;
}
@Override
public void reset() {
long now = timer.getTick();
if (now - actionTime[1] > 5) {
set.clear();
}
actionTime[1] = actionTime[0];
actionTime[0] = now;
}
}

View File

@ -1,6 +1,7 @@
package com.boydti.fawe.object.pattern;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.pattern.AbstractPattern;
@ -16,4 +17,12 @@ public class ExistingPattern extends AbstractPattern {
public BaseBlock apply(Vector position) {
return extent.getBlock(position);
}
@Override
public boolean apply(Extent extent, Vector set, Vector get) throws WorldEditException {
if (set.getBlockX() == get.getBlockX() && set.getBlockZ() == get.getBlockZ() && set.getBlockY() == get.getBlockY()) {
return false;
}
return extent.setBlock(set, extent.getBlock(get));
}
}

View File

@ -0,0 +1,10 @@
package com.boydti.fawe.object.random;
public interface SimpleRandom {
public double nextDouble(int x, int y, int z);
public default int nextInt(int x, int y, int z, int len) {
double val = nextDouble(x, y, z);
return (int) (val * len);
}
}

View File

@ -0,0 +1,355 @@
package com.boydti.fawe.object.random;
/*
* A speed-improved simplex noise algorithm for 2D, 3D and 4D in Java.
*
* Based on example code by Stefan Gustavson (stegu@itn.liu.se).
* Optimisations by Peter Eastman (peastman@drizzle.stanford.edu).
* Better rank ordering method for 4D by Stefan Gustavson in 2012.
*
* This could be speeded up even further, but it's useful as it is.
*
* Version 2012-03-09
*
* This code was placed in the public domain by its original author,
* Stefan Gustavson. You may use it as you see fit, but
* attribution is appreciated.
*
*/
public class SimplexNoise {
private static Grad grad3[] = {new Grad(1,1,0),new Grad(-1,1,0),new Grad(1,-1,0),new Grad(-1,-1,0),
new Grad(1,0,1),new Grad(-1,0,1),new Grad(1,0,-1),new Grad(-1,0,-1),
new Grad(0,1,1),new Grad(0,-1,1),new Grad(0,1,-1),new Grad(0,-1,-1)};
private static Grad grad4[]= {new Grad(0,1,1,1),new Grad(0,1,1,-1),new Grad(0,1,-1,1),new Grad(0,1,-1,-1),
new Grad(0,-1,1,1),new Grad(0,-1,1,-1),new Grad(0,-1,-1,1),new Grad(0,-1,-1,-1),
new Grad(1,0,1,1),new Grad(1,0,1,-1),new Grad(1,0,-1,1),new Grad(1,0,-1,-1),
new Grad(-1,0,1,1),new Grad(-1,0,1,-1),new Grad(-1,0,-1,1),new Grad(-1,0,-1,-1),
new Grad(1,1,0,1),new Grad(1,1,0,-1),new Grad(1,-1,0,1),new Grad(1,-1,0,-1),
new Grad(-1,1,0,1),new Grad(-1,1,0,-1),new Grad(-1,-1,0,1),new Grad(-1,-1,0,-1),
new Grad(1,1,1,0),new Grad(1,1,-1,0),new Grad(1,-1,1,0),new Grad(1,-1,-1,0),
new Grad(-1,1,1,0),new Grad(-1,1,-1,0),new Grad(-1,-1,1,0),new Grad(-1,-1,-1,0)};
private static short p[] = {151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180};
// To remove the need for index wrapping, double the permutation table length
private static short perm[] = new short[512];
private static short permMod12[] = new short[512];
static {
for(int i=0; i<512; i++)
{
perm[i]=p[i & 255];
permMod12[i] = (short)(perm[i] % 12);
}
}
// Skewing and unskewing factors for 2, 3, and 4 dimensions
private static final double F2 = 0.5*(Math.sqrt(3.0)-1.0);
private static final double G2 = (3.0-Math.sqrt(3.0))/6.0;
private static final double F3 = 1.0/3.0;
private static final double G3 = 1.0/6.0;
private static final double F4 = (Math.sqrt(5.0)-1.0)/4.0;
private static final double G4 = (5.0-Math.sqrt(5.0))/20.0;
// This method is a *lot* faster than using (int)Math.floor(x)
private static int fastfloor(double x) {
int xi = (int)x;
return x<xi ? xi-1 : xi;
}
private static double dot(Grad g, double x, double y) {
return g.x*x + g.y*y; }
private static double dot(Grad g, double x, double y, double z) {
return g.x*x + g.y*y + g.z*z; }
private static double dot(Grad g, double x, double y, double z, double w) {
return g.x*x + g.y*y + g.z*z + g.w*w; }
// 2D simplex noise
public static double noise(double xin, double yin) {
double n0, n1, n2; // Noise contributions from the three corners
// Skew the input space to determine which simplex cell we're in
double s = (xin+yin)*F2; // Hairy factor for 2D
int i = fastfloor(xin+s);
int j = fastfloor(yin+s);
double t = (i+j)*G2;
double X0 = i-t; // Unskew the cell origin back to (x,y) space
double Y0 = j-t;
double x0 = xin-X0; // The x,y distances from the cell origin
double y0 = yin-Y0;
// For the 2D case, the simplex shape is an equilateral triangle.
// Determine which simplex we are in.
int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords
if(x0>y0) {i1=1; j1=0;} // lower triangle, XY order: (0,0)->(1,0)->(1,1)
else {i1=0; j1=1;} // upper triangle, YX order: (0,0)->(0,1)->(1,1)
// A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
// a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
// c = (3-sqrt(3))/6
double x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
double y1 = y0 - j1 + G2;
double x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords
double y2 = y0 - 1.0 + 2.0 * G2;
// Work out the hashed gradient indices of the three simplex corners
int ii = i & 255;
int jj = j & 255;
int gi0 = permMod12[ii+perm[jj]];
int gi1 = permMod12[ii+i1+perm[jj+j1]];
int gi2 = permMod12[ii+1+perm[jj+1]];
// Calculate the contribution from the three corners
double t0 = 0.5 - x0*x0-y0*y0;
if(t0<0) n0 = 0.0;
else {
t0 *= t0;
n0 = t0 * t0 * dot(grad3[gi0], x0, y0); // (x,y) of grad3 used for 2D gradient
}
double t1 = 0.5 - x1*x1-y1*y1;
if(t1<0) n1 = 0.0;
else {
t1 *= t1;
n1 = t1 * t1 * dot(grad3[gi1], x1, y1);
}
double t2 = 0.5 - x2*x2-y2*y2;
if(t2<0) n2 = 0.0;
else {
t2 *= t2;
n2 = t2 * t2 * dot(grad3[gi2], x2, y2);
}
// Add contributions from each corner to get the final noise value.
// The result is scaled to return values in the interval [-1,1].
return 70.0 * (n0 + n1 + n2);
}
// 3D simplex noise
public static double noise(double xin, double yin, double zin) {
double n0, n1, n2, n3; // Noise contributions from the four corners
// Skew the input space to determine which simplex cell we're in
double s = (xin+yin+zin)*F3; // Very nice and simple skew factor for 3D
int i = fastfloor(xin+s);
int j = fastfloor(yin+s);
int k = fastfloor(zin+s);
double t = (i+j+k)*G3;
double X0 = i-t; // Unskew the cell origin back to (x,y,z) space
double Y0 = j-t;
double Z0 = k-t;
double x0 = xin-X0; // The x,y,z distances from the cell origin
double y0 = yin-Y0;
double z0 = zin-Z0;
// For the 3D case, the simplex shape is a slightly irregular tetrahedron.
// Determine which simplex we are in.
int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords
if(x0>=y0) {
if(y0>=z0)
{ i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } // X Y Z order
else if(x0>=z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } // X Z Y order
else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } // Z X Y order
}
else { // x0<y0
if(y0<z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } // Z Y X order
else if(x0<z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } // Y Z X order
else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } // Y X Z order
}
// A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
// a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
// a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
// c = 1/6.
double x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords
double y1 = y0 - j1 + G3;
double z1 = z0 - k1 + G3;
double x2 = x0 - i2 + 2.0*G3; // Offsets for third corner in (x,y,z) coords
double y2 = y0 - j2 + 2.0*G3;
double z2 = z0 - k2 + 2.0*G3;
double x3 = x0 - 1.0 + 3.0*G3; // Offsets for last corner in (x,y,z) coords
double y3 = y0 - 1.0 + 3.0*G3;
double z3 = z0 - 1.0 + 3.0*G3;
// Work out the hashed gradient indices of the four simplex corners
int ii = i & 255;
int jj = j & 255;
int kk = k & 255;
int gi0 = permMod12[ii+perm[jj+perm[kk]]];
int gi1 = permMod12[ii+i1+perm[jj+j1+perm[kk+k1]]];
int gi2 = permMod12[ii+i2+perm[jj+j2+perm[kk+k2]]];
int gi3 = permMod12[ii+1+perm[jj+1+perm[kk+1]]];
// Calculate the contribution from the four corners
double t0 = 0.6 - x0*x0 - y0*y0 - z0*z0;
if(t0<0) n0 = 0.0;
else {
t0 *= t0;
n0 = t0 * t0 * dot(grad3[gi0], x0, y0, z0);
}
double t1 = 0.6 - x1*x1 - y1*y1 - z1*z1;
if(t1<0) n1 = 0.0;
else {
t1 *= t1;
n1 = t1 * t1 * dot(grad3[gi1], x1, y1, z1);
}
double t2 = 0.6 - x2*x2 - y2*y2 - z2*z2;
if(t2<0) n2 = 0.0;
else {
t2 *= t2;
n2 = t2 * t2 * dot(grad3[gi2], x2, y2, z2);
}
double t3 = 0.6 - x3*x3 - y3*y3 - z3*z3;
if(t3<0) n3 = 0.0;
else {
t3 *= t3;
n3 = t3 * t3 * dot(grad3[gi3], x3, y3, z3);
}
// Add contributions from each corner to get the final noise value.
// The result is scaled to stay just inside [-1,1]
return 32.0*(n0 + n1 + n2 + n3);
}
// 4D simplex noise, better simplex rank ordering method 2012-03-09
public static double noise(double x, double y, double z, double w) {
double n0, n1, n2, n3, n4; // Noise contributions from the five corners
// Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in
double s = (x + y + z + w) * F4; // Factor for 4D skewing
int i = fastfloor(x + s);
int j = fastfloor(y + s);
int k = fastfloor(z + s);
int l = fastfloor(w + s);
double t = (i + j + k + l) * G4; // Factor for 4D unskewing
double X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space
double Y0 = j - t;
double Z0 = k - t;
double W0 = l - t;
double x0 = x - X0; // The x,y,z,w distances from the cell origin
double y0 = y - Y0;
double z0 = z - Z0;
double w0 = w - W0;
// For the 4D case, the simplex is a 4D shape I won't even try to describe.
// To find out which of the 24 possible simplices we're in, we need to
// determine the magnitude ordering of x0, y0, z0 and w0.
// Six pair-wise comparisons are performed between each possible pair
// of the four coordinates, and the results are used to rank the numbers.
int rankx = 0;
int ranky = 0;
int rankz = 0;
int rankw = 0;
if(x0 > y0) rankx++; else ranky++;
if(x0 > z0) rankx++; else rankz++;
if(x0 > w0) rankx++; else rankw++;
if(y0 > z0) ranky++; else rankz++;
if(y0 > w0) ranky++; else rankw++;
if(z0 > w0) rankz++; else rankw++;
int i1, j1, k1, l1; // The integer offsets for the second simplex corner
int i2, j2, k2, l2; // The integer offsets for the third simplex corner
int i3, j3, k3, l3; // The integer offsets for the fourth simplex corner
// [rankx, ranky, rankz, rankw] is a 4-vector with the numbers 0, 1, 2 and 3
// in some order. We use a thresholding to set the coordinates in turn.
// Rank 3 denotes the largest coordinate.
i1 = rankx >= 3 ? 1 : 0;
j1 = ranky >= 3 ? 1 : 0;
k1 = rankz >= 3 ? 1 : 0;
l1 = rankw >= 3 ? 1 : 0;
// Rank 2 denotes the second largest coordinate.
i2 = rankx >= 2 ? 1 : 0;
j2 = ranky >= 2 ? 1 : 0;
k2 = rankz >= 2 ? 1 : 0;
l2 = rankw >= 2 ? 1 : 0;
// Rank 1 denotes the second smallest coordinate.
i3 = rankx >= 1 ? 1 : 0;
j3 = ranky >= 1 ? 1 : 0;
k3 = rankz >= 1 ? 1 : 0;
l3 = rankw >= 1 ? 1 : 0;
// The fifth corner has all coordinate offsets = 1, so no need to compute that.
double x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords
double y1 = y0 - j1 + G4;
double z1 = z0 - k1 + G4;
double w1 = w0 - l1 + G4;
double x2 = x0 - i2 + 2.0*G4; // Offsets for third corner in (x,y,z,w) coords
double y2 = y0 - j2 + 2.0*G4;
double z2 = z0 - k2 + 2.0*G4;
double w2 = w0 - l2 + 2.0*G4;
double x3 = x0 - i3 + 3.0*G4; // Offsets for fourth corner in (x,y,z,w) coords
double y3 = y0 - j3 + 3.0*G4;
double z3 = z0 - k3 + 3.0*G4;
double w3 = w0 - l3 + 3.0*G4;
double x4 = x0 - 1.0 + 4.0*G4; // Offsets for last corner in (x,y,z,w) coords
double y4 = y0 - 1.0 + 4.0*G4;
double z4 = z0 - 1.0 + 4.0*G4;
double w4 = w0 - 1.0 + 4.0*G4;
// Work out the hashed gradient indices of the five simplex corners
int ii = i & 255;
int jj = j & 255;
int kk = k & 255;
int ll = l & 255;
int gi0 = perm[ii+perm[jj+perm[kk+perm[ll]]]] % 32;
int gi1 = perm[ii+i1+perm[jj+j1+perm[kk+k1+perm[ll+l1]]]] % 32;
int gi2 = perm[ii+i2+perm[jj+j2+perm[kk+k2+perm[ll+l2]]]] % 32;
int gi3 = perm[ii+i3+perm[jj+j3+perm[kk+k3+perm[ll+l3]]]] % 32;
int gi4 = perm[ii+1+perm[jj+1+perm[kk+1+perm[ll+1]]]] % 32;
// Calculate the contribution from the five corners
double t0 = 0.6 - x0*x0 - y0*y0 - z0*z0 - w0*w0;
if(t0<0) n0 = 0.0;
else {
t0 *= t0;
n0 = t0 * t0 * dot(grad4[gi0], x0, y0, z0, w0);
}
double t1 = 0.6 - x1*x1 - y1*y1 - z1*z1 - w1*w1;
if(t1<0) n1 = 0.0;
else {
t1 *= t1;
n1 = t1 * t1 * dot(grad4[gi1], x1, y1, z1, w1);
}
double t2 = 0.6 - x2*x2 - y2*y2 - z2*z2 - w2*w2;
if(t2<0) n2 = 0.0;
else {
t2 *= t2;
n2 = t2 * t2 * dot(grad4[gi2], x2, y2, z2, w2);
}
double t3 = 0.6 - x3*x3 - y3*y3 - z3*z3 - w3*w3;
if(t3<0) n3 = 0.0;
else {
t3 *= t3;
n3 = t3 * t3 * dot(grad4[gi3], x3, y3, z3, w3);
}
double t4 = 0.6 - x4*x4 - y4*y4 - z4*z4 - w4*w4;
if(t4<0) n4 = 0.0;
else {
t4 *= t4;
n4 = t4 * t4 * dot(grad4[gi4], x4, y4, z4, w4);
}
// Sum up and scale the result to cover the range [-1,1]
return 27.0 * (n0 + n1 + n2 + n3 + n4);
}
// Inner class to speed upp gradient computations
// (In Java, array access is a lot slower than member access)
private static class Grad
{
double x, y, z, w;
Grad(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
Grad(double x, double y, double z, double w)
{
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
}
}

View File

@ -0,0 +1,13 @@
package com.boydti.fawe.object.random;
public class SimplexRandom implements SimpleRandom {
private final double scale;
public SimplexRandom(double scale) {
this.scale = scale;
}
@Override
public double nextDouble(int x, int y, int z) {
return (SimplexNoise.noise(x * scale, y * scale, z * scale) + 1) * 0.5;
}
}

View File

@ -0,0 +1,21 @@
package com.boydti.fawe.object.random;
import java.util.SplittableRandom;
public class TrueRandom implements SimpleRandom {
private final SplittableRandom r;
public TrueRandom() {
this.r = new SplittableRandom();
}
@Override
public double nextDouble(int x, int y, int z) {
return r.nextDouble();
}
@Override
public int nextInt(int x, int y, int z, int len) {
return r.nextInt(len);
}
}

View File

@ -30,7 +30,9 @@ import com.sk89q.worldedit.command.ClipboardCommands;
import com.sk89q.worldedit.command.GeneralCommands;
import com.sk89q.worldedit.command.GenerationCommands;
import com.sk89q.worldedit.command.HistoryCommands;
import com.sk89q.worldedit.command.MaskCommands;
import com.sk89q.worldedit.command.NavigationCommands;
import com.sk89q.worldedit.command.PatternCommands;
import com.sk89q.worldedit.command.RegionCommands;
import com.sk89q.worldedit.command.SchematicCommands;
import com.sk89q.worldedit.command.ScriptingCommands;
@ -40,6 +42,7 @@ import com.sk89q.worldedit.command.SnapshotUtilCommands;
import com.sk89q.worldedit.command.SuperPickaxeCommands;
import com.sk89q.worldedit.command.ToolCommands;
import com.sk89q.worldedit.command.ToolUtilCommands;
import com.sk89q.worldedit.command.TransformCommands;
import com.sk89q.worldedit.command.UtilityCommands;
import com.sk89q.worldedit.command.WorldEditCommands;
import java.io.FileOutputStream;
@ -113,6 +116,9 @@ public final class DocumentationPrinter {
writePermissionsWikiTable(stream, builder, "/", SnapshotUtilCommands.class);
writePermissionsWikiTable(stream, builder, "/", ScriptingCommands.class);
writePermissionsWikiTable(stream, builder, "/", ChunkCommands.class);
writePermissionsWikiTable(stream, builder, "/masks ", MaskCommands.class);
writePermissionsWikiTable(stream, builder, "/patterns ", PatternCommands.class);
writePermissionsWikiTable(stream, builder, "/transforms ", TransformCommands.class);
stream.println();
stream.print("#### Uncategorized\n");
stream.append("| Aliases | Permission | flags | Usage |\n");

View File

@ -131,14 +131,16 @@ public class SetQueue {
e.printStackTrace();
}
if (pool.getQueuedSubmissionCount() != 0 || pool.getRunningThreadCount() != 0 || pool.getQueuedTaskCount() != 0) {
if (Fawe.get().isJava8()) {
// if (Fawe.get().isJava8())
{
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} else {
pool.shutdown();
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
pool = new ForkJoinPool();
completer = new ExecutorCompletionService(pool);
}
// else {
// pool.shutdown();
// pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
// pool = new ForkJoinPool();
// completer = new ExecutorCompletionService(pool);
// }
}
secondLast = System.currentTimeMillis();
queue.endSet(parallel);

View File

@ -32,6 +32,15 @@ public class StringMan {
return sb.toString();
}
public static int indexOf(String input, int start, char... values) {
for (int i = start; i < input.length(); i++){
for (char c : values) {
if (c == input.charAt(i)) return i;
}
}
return -1;
}
public static List<String> split(String input, char delim) {
List<String> result = new ArrayList<String>();
int start = 0;

View File

@ -6,7 +6,6 @@ import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.RunnableVal;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@ -61,20 +60,20 @@ public abstract class TaskManager {
* @param runnables
*/
public void parallel(Collection<Runnable> runnables) {
if (!Fawe.get().isJava8()) {
ExecutorCompletionService c = new ExecutorCompletionService(pool);
for (Runnable run : runnables) {
c.submit(run, null);
}
try {
for (int i = 0; i < runnables.size(); i++) {
c.take();
}
} catch (Exception e) {
e.printStackTrace();
}
return;
}
// if (!Fawe.get().isJava8()) {
// ExecutorCompletionService c = new ExecutorCompletionService(pool);
// for (Runnable run : runnables) {
// c.submit(run, null);
// }
// try {
// for (int i = 0; i < runnables.size(); i++) {
// c.take();
// }
// } catch (Exception e) {
// e.printStackTrace();
// }
// return;
// }
for (Runnable run : runnables) {
pool.submit(run);
}

View File

@ -25,6 +25,8 @@ import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.CuboidClipboard.FlipDirection;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.foundation.Block;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern;
@ -435,6 +437,11 @@ public class BaseBlock extends Block implements TileEntityBlock, Pattern {
return this;
}
@Override
public boolean apply(Extent extent, Vector setPosition, Vector getPosition) throws WorldEditException {
return extent.setBlock(setPosition, this);
}
public static Class<BaseBlock> inject() {
return BaseBlock.class;
}

View File

@ -20,6 +20,7 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FaweLimit;
@ -45,17 +46,8 @@ import com.boydti.fawe.object.brush.SplineBrush;
import com.boydti.fawe.object.brush.StencilBrush;
import com.boydti.fawe.object.brush.SurfaceSphereBrush;
import com.boydti.fawe.object.brush.SurfaceSpline;
import com.boydti.fawe.object.brush.TargetMode;
import com.boydti.fawe.object.brush.heightmap.ScalableHeightMap;
import com.boydti.fawe.object.brush.scroll.ScrollClipboard;
import com.boydti.fawe.object.brush.scroll.ScrollMask;
import com.boydti.fawe.object.brush.scroll.ScrollPattern;
import com.boydti.fawe.object.brush.scroll.ScrollRange;
import com.boydti.fawe.object.brush.scroll.ScrollSize;
import com.boydti.fawe.object.brush.scroll.ScrollTarget;
import com.boydti.fawe.object.brush.visualization.VisualMode;
import com.boydti.fawe.object.mask.IdMask;
import com.boydti.fawe.util.MathMan;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
@ -80,9 +72,7 @@ import com.sk89q.worldedit.command.tool.brush.SmoothBrush;
import com.sk89q.worldedit.command.tool.brush.SphereBrush;
import com.sk89q.worldedit.command.util.CreatureButcher;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.CommandManager;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.function.mask.BlockMask;
@ -91,6 +81,7 @@ import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.command.InvalidUsageException;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.command.parametric.Optional;
import java.io.File;
@ -103,9 +94,7 @@ import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
import javafx.scene.paint.Color;
/**
* Commands to set brush shape.
@ -113,177 +102,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
@Command(aliases = { "brush", "br" },
desc = "Commands to build and draw from far away. [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/Brushes)"
)
public class BrushCommands {
public class BrushCommands extends MethodCommands {
private final WorldEdit worldEdit;
/**
* Create a new instance.
*
* @param worldEdit reference to WorldEdit
*/
public BrushCommands(WorldEdit worldEdit) {
checkNotNull(worldEdit);
this.worldEdit = worldEdit;
}
@Command(
aliases = { "primary" },
usage = "[brush arguments]",
desc = "Set the right click brush",
help = "Set the right click brush",
min = 1
)
public void primary(Player player, LocalSession session, CommandContext args) throws WorldEditException {
BaseBlock item = player.getBlockInHand();
BrushTool tool = session.getBrushTool(player, false);
session.setTool(item.getId(), item.getData(), null, player);
String cmd = "brush " + args.getJoinedStrings(0);
CommandEvent event = new CommandEvent(player, cmd);
CommandManager.getInstance().handleCommandOnCurrentThread(event);
BrushTool newTool = session.getBrushTool(item.getId(), item.getData(), player, false);
if (newTool != null && tool != null) {
newTool.setSecondary(tool.getSecondary());
}
}
@Command(
aliases = { "secondary" },
usage = "[brush arguments]",
desc = "Set the left click brush",
help = "Set the left click brush",
min = 1
)
public void secondary(Player player, LocalSession session, CommandContext args) throws WorldEditException {
BaseBlock item = player.getBlockInHand();
BrushTool tool = session.getBrushTool(player, false);
session.setTool(item.getId(), item.getData(), null, player);
String cmd = "brush " + args.getJoinedStrings(0);
CommandEvent event = new CommandEvent(player, cmd);
CommandManager.getInstance().handleCommandOnCurrentThread(event);
BrushTool newTool = session.getBrushTool(item.getId(), item.getData(), player, false);
if (newTool != null && tool != null) {
newTool.setPrimary(tool.getPrimary());
}
}
@Command(
aliases = { "visualize", "visual", "vis" },
usage = "[mode]",
desc = "Toggle between different visualization modes",
min = 0,
max = 1
)
public void visual(Player player, LocalSession session, @Optional("0") int mode) throws WorldEditException {
BrushTool tool = session.getBrushTool(player, false);
if (tool == null) {
BBC.BRUSH_NONE.send(player);
return;
}
VisualMode[] modes = VisualMode.values();
VisualMode newMode = modes[MathMan.wrap(mode, 0, modes.length - 1)];
tool.setVisualMode(newMode);
BBC.BRUSH_VISUAL_MODE_SET.send(player, newMode);
}
@Command(
aliases = { "target", "tar" },
usage = "[mode]",
desc = "Toggle between different target modes",
min = 0,
max = 1
)
public void target(Player player, LocalSession session, @Optional("0") int mode) throws WorldEditException {
BrushTool tool = session.getBrushTool(player, false);
if (tool == null) {
BBC.BRUSH_NONE.send(player);
return;
}
TargetMode[] modes = TargetMode.values();
TargetMode newMode = modes[MathMan.wrap(mode, 0, modes.length - 1)];
tool.setTargetMode(newMode);
BBC.BRUSH_TARGET_MODE_SET.send(player, newMode);
}
@Command(
aliases = { "scroll" },
usage = "[none|clipboard|mask|pattern|range|size|visual|target]",
desc = "Toggle between different target modes",
min = 1,
max = -1
)
public void scroll(Player player, EditSession editSession, LocalSession session, CommandContext args) throws WorldEditException {
BrushTool tool = session.getBrushTool(player, false);
if (tool == null) {
BBC.BRUSH_NONE.send(player);
return;
}
ParserContext parserContext = new ParserContext();
parserContext.setActor(player);
parserContext.setWorld(player.getWorld());
parserContext.setSession(session);
parserContext.setExtent(editSession);
final LocalConfiguration config = this.worldEdit.getConfiguration();
switch (args.getString(0).toLowerCase()) {
case "none":
tool.setScrollAction(null);
break;
case "clipboard":
if (args.argsLength() != 2) {
BBC.COMMAND_SYNTAX.send(player, "clipboard [file]");
return;
}
String filename = args.getString(1);
try {
ClipboardHolder[] clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(player, player.getWorld().getWorldData(), filename, true);
if (clipboards == null) {
return;
}
tool.setScrollAction(new ScrollClipboard(tool, session, clipboards));
break;
} catch (IOException e) {
throw new RuntimeException(e);
}
case "mask":
if (args.argsLength() < 2) {
BBC.COMMAND_SYNTAX.send(player, "mask [mask 1] [mask 2] [mask 3]...");
return;
}
Mask[] masks = new Mask[args.argsLength() - 1];
for (int i = 1; i < args.argsLength(); i++) {
String arg = args.getString(i);
masks[i - 1] = worldEdit.getMaskFactory().parseFromInput(arg, parserContext);
}
tool.setScrollAction(new ScrollMask(tool, masks));
break;
case "pattern":
if (args.argsLength() < 2) {
BBC.COMMAND_SYNTAX.send(player, "pattern [pattern 1] [pattern 2] [pattern 3]...");
return;
}
Pattern[] patterns = new Pattern[args.argsLength() - 1];
for (int i = 1; i < args.argsLength(); i++) {
String arg = args.getString(i);
patterns[i - 1] = worldEdit.getPatternFactory().parseFromInput(arg, parserContext);
}
tool.setScrollAction(new ScrollPattern(tool, patterns));
break;
case "range":
tool.setScrollAction(new ScrollRange(tool));
break;
case "size":
tool.setScrollAction(new ScrollSize(tool));
break;
case "target":
tool.setScrollAction(new ScrollTarget(tool));
break;
default:
BBC.COMMAND_SYNTAX.send(player, "[none|clipboard|mask|pattern|range|size|visual|target]");
return;
}
BBC.BRUSH_SCROLL_ACTION_SET.send(player, args.getJoinedStrings(0));
super(worldEdit);
}
@Command(
@ -614,16 +436,16 @@ public class BrushCommands {
@Command(
aliases = { "layer" },
usage = "<radius> <pattern1> <patern2>...",
usage = "<radius> [color|<pattern1> <patern2>...]",
desc = "Replaces terrain with a layer.",
help = "Replaces terrain with a layer.\n" +
"Example: /br layer 5 95:1 95:2 35:15 - Places several layers on a surface\n" +
"Pic: https://i.imgur.com/XV0vYoX.png",
min = 3,
min = 0,
max = 999
)
@CommandPermissions("worldedit.brush.layer")
public void surfaceLayer(Player player, EditSession editSession, LocalSession session, double radius, CommandContext args) throws WorldEditException {
public void surfaceLayer(Player player, EditSession editSession, LocalSession session, double radius, CommandContext args) throws WorldEditException, InvalidUsageException {
worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player);
tool.setSize(radius);
@ -633,9 +455,21 @@ public class BrushCommands {
parserContext.setSession(session);
parserContext.setExtent(editSession);
List<BaseBlock> blocks = new ArrayList<>();
for (int i = 1; i < args.argsLength(); i++) {
String arg = args.getString(i);
blocks.add(worldEdit.getBlockFactory().parseFromInput(arg, parserContext));
if (args.argsLength() < 2) {
throw new InvalidUsageException(getCallable());
}
try {
Color color = Color.web(args.getString(1));
java.awt.Color awtColor = new java.awt.Color((float) color.getRed(), (float) color.getGreen(), (float) color.getBlue(), (float) color.getOpacity());
char[] glassLayers = Fawe.get().getTextureUtil().getNearestLayer(awtColor.getRGB());
for (char layer : glassLayers) {
blocks.add(FaweCache.CACHE_BLOCK[layer]);
}
} catch (IllegalArgumentException ignore) {
for (int i = 1; i < args.argsLength(); i++) {
String arg = args.getString(i);
blocks.add(worldEdit.getBlockFactory().parseFromInput(arg, parserContext));
}
}
tool.setBrush(new LayerBrush(blocks.toArray(new BaseBlock[blocks.size()])), "worldedit.brush.layer", player);
player.print(BBC.getPrefix() + BBC.BRUSH_LAYER.f(radius, args.getJoinedStrings(1)));

View File

@ -1,8 +1,8 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.extent.DefaultTransformParser;
import com.boydti.fawe.object.extent.ResettableExtent;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
@ -28,7 +28,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class GeneralCommands {
private final WorldEdit worldEdit;
private final DefaultTransformParser transformParser;
/**
* Create a new instance.
@ -38,7 +37,6 @@ public class GeneralCommands {
public GeneralCommands(WorldEdit worldEdit) {
checkNotNull(worldEdit);
this.worldEdit = worldEdit;
transformParser = new DefaultTransformParser(worldEdit);
}
@Command(
@ -87,6 +85,7 @@ public class GeneralCommands {
@Command(
aliases = { "/gmask", "gmask", "globalmask", "/globalmask" },
usage = "[mask]",
help = "The global destination mask applies to all edits you do and masks based on the destination blocks (i.e. the blocks in the world).",
desc = "Set the global mask",
min = 0,
max = -1
@ -112,6 +111,7 @@ public class GeneralCommands {
aliases = { "/gsmask", "gsmask", "globalsourcemask", "/globalsourcemask" },
usage = "[mask]",
desc = "Set the global source mask",
help = "The global source mask applies to all edits you do and masks based on the source blocks (e.g. the blocks in your clipboard)",
min = 0,
max = -1
)
@ -150,7 +150,7 @@ public class GeneralCommands {
parserContext.setWorld(player.getWorld());
parserContext.setSession(session);
parserContext.setExtent(editSession);
ResettableExtent transform = transformParser.parseFromInput(context.getJoinedStrings(0), parserContext);
ResettableExtent transform = Fawe.get().getTransformParser().parseFromInput(context.getJoinedStrings(0), parserContext);
session.setTransform(transform);
BBC.TRANSFORM.send(player);
}

View File

@ -0,0 +1,388 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.object.mask.AdjacentAnyMask;
import com.boydti.fawe.object.mask.AdjacentMask;
import com.boydti.fawe.object.mask.AngleMask;
import com.boydti.fawe.object.mask.BiomeMask;
import com.boydti.fawe.object.mask.BlockLightMask;
import com.boydti.fawe.object.mask.BrightnessMask;
import com.boydti.fawe.object.mask.DataMask;
import com.boydti.fawe.object.mask.IdDataMask;
import com.boydti.fawe.object.mask.IdMask;
import com.boydti.fawe.object.mask.LightMask;
import com.boydti.fawe.object.mask.OpacityMask;
import com.boydti.fawe.object.mask.RadiusMask;
import com.boydti.fawe.object.mask.RandomMask;
import com.boydti.fawe.object.mask.SimplexMask;
import com.boydti.fawe.object.mask.SkyLightMask;
import com.boydti.fawe.object.mask.WallMask;
import com.boydti.fawe.object.mask.XAxisMask;
import com.boydti.fawe.object.mask.YAxisMask;
import com.boydti.fawe.object.mask.ZAxisMask;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.mask.BlockMask;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.ExpressionMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.MaskIntersection;
import com.sk89q.worldedit.function.mask.MaskUnion;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.mask.OffsetMask;
import com.sk89q.worldedit.function.mask.RegionMask;
import com.sk89q.worldedit.function.mask.SolidBlockMask;
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.session.request.RequestSelection;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.world.biome.BaseBiome;
@Command(aliases = { "masks" },
desc = "Help for the various masks. [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/WorldEdit---FAWE-mask-list)"
)
public class MaskCommands extends MethodCommands {
public MaskCommands(WorldEdit worldEdit) {
super(worldEdit);
}
@Command(
aliases = {"#simplex"},
desc = "Use simplex noise as the mask",
usage = "<scale=10> <min=0> <max=100>",
min = 3,
max = 3
)
public Mask simplex(double scale, double min, double max) {
scale = (1d / Math.max(1, scale));
min = (min - 50) / 50;
max = (max - 50) / 50;
return new SimplexMask(scale, min, max);
}
@Command(
aliases = {"#light"},
desc = "Restrict to specific light levels",
usage = "<min> <max>",
min = 2,
max = 2
)
public Mask light(EditSession editSession, double min, double max) {
return new LightMask(editSession, (int) min, (int) max);
}
@Command(
aliases = {"#skylight"},
desc = "Restrict to specific sky light levels",
usage = "<min> <max>",
min = 2,
max = 2
)
public Mask skylight(EditSession editSession, double min, double max) {
return new SkyLightMask(editSession, (int) min, (int) max);
}
@Command(
aliases = {"#blocklight", "#emittedlight"},
desc = "Restrict to specific block light levels",
usage = "<min> <max>",
min = 2,
max = 2
)
public Mask blocklight(EditSession editSession, double min, double max) {
return new BlockLightMask(editSession, (int) min, (int) max);
}
@Command(
aliases = {"#opacity"},
desc = "Restrict to specific opacity levels",
usage = "<min> <max>",
min = 2,
max = 2
)
public Mask opacity(EditSession editSession, double min, double max) {
return new OpacityMask(editSession, (int) min, (int) max);
}
@Command(
aliases = {"#brightness"},
desc = "Restrict to specific block brightness",
usage = "<min> <max>",
min = 2,
max = 2
)
public Mask brightness(EditSession editSession, double min, double max) {
return new BrightnessMask(editSession, (int) min, (int) max);
}
@Command(
aliases = {"#offset"},
desc = "Offset a mask",
usage = "<dx> <dy> <dz> <mask>",
min = 4,
max = 4
)
public Mask offset(double x, double y, double z, Mask mask) {
return new OffsetMask(mask, new Vector(x, y, z));
}
@Command(
aliases = {"#haslight"},
desc = "Restricts to blocks with light (sky or emitted)"
)
public Mask haslight(EditSession extent) {
return new LightMask(extent, 1, Integer.MAX_VALUE);
}
@Command(
aliases = {"#nolight"},
desc = "Restrict to blocks without light (sky or emitted)"
)
public Mask nolight(EditSession extent) {
return new LightMask(extent, 0, 0);
}
@Command(
aliases = {"#existing"},
desc = "If there is a non air block"
)
public Mask existing(EditSession extent) {
return new ExistingBlockMask(extent);
}
@Command(
aliases = {"#existing"},
desc = "If there is a solid block"
)
public Mask solid(EditSession extent) {
return new SolidBlockMask(extent);
}
@Command(
aliases = {"#dregion", "#dselection", "#dsel"},
desc = "inside the player's selection"
)
public Mask dregion(EditSession extent) {
return new RegionMask(new RequestSelection());
}
@Command(
aliases = {"#region", "#selection", "#sel"},
desc = "inside the provided selection"
)
public Mask selection(Player player, LocalSession session) throws IncompleteRegionException {
return new RegionMask(session.getSelection(player.getWorld()).clone());
}
@Command(
aliases = {"#xaxis"},
desc = "Restrict to initial x axis"
)
public Mask xaxis() {
return new XAxisMask();
}
@Command(
aliases = {"#yaxis"},
desc = "Restrict to initial y axis"
)
public Mask yaxis() {
return new YAxisMask();
}
@Command(
aliases = {"#zaxis"},
desc = "Restrict to initial z axis"
)
public Mask zaxis() {
return new ZAxisMask();
}
@Command(
aliases = {"#id"},
desc = "Restrict to initial id"
)
public Mask id(EditSession editSession) {
return new IdMask(editSession);
}
@Command(
aliases = {"#data"},
desc = "Restrict to initial data"
)
public Mask data(EditSession editSession) {
return new DataMask(editSession);
}
@Command(
aliases = {"#iddata"},
desc = "Restrict to initial block id and data"
)
public Mask iddata(EditSession editSession) {
return new IdDataMask(editSession);
}
@Command(
aliases = {"#wall"},
desc = "Restrict to walls (any block n,e,s,w of air)"
)
public Mask wall(EditSession extent) {
BlockMask blockMask = new BlockMask(extent, new BaseBlock(0));
return new MaskUnion(new ExistingBlockMask(extent), new WallMask(blockMask, 1, 8));
}
@Command(
aliases = {"#surface"},
desc = "Restrict to surfaces (any solid block touching air)"
)
public Mask surface(EditSession extent) {
return new MaskUnion(new ExistingBlockMask(extent), new AdjacentAnyMask(new BlockMask(extent, new BaseBlock(0))));
}
@Command(
aliases = {"\\", "/"},
desc = "Restrict to specific terrain angle",
help = "Restrict to specific terrain angle\n" +
"The -o flag will only overlay" +
"Example: /[0d][45d]\n" +
"Explanation: Allows any block where the adjacent block is between 0 and 45 degrees.\n" +
"Example: /[3][20]\n" +
"Explanation: Allows any block where the adjacent block is between 3 and 20 blocks below",
usage = "<min> <max>",
min = 2,
max = 2
)
public Mask angle(EditSession extent, String min, String max, @Switch('o') boolean overlay) throws ExpressionException {
double y1,y2;
boolean override;
if (max.endsWith("d")) {
double y1d = Expression.compile(max.substring(0, max.length() - 1)).evaluate();
double y2d = Expression.compile(min.substring(0, min.length() - 1)).evaluate();
y1 = (Math.tan(y1d * (Math.PI / 180)));
y2 = (Math.tan(y2d * (Math.PI / 180)));
} else {
y1 = (Expression.compile(max).evaluate());
y2 = (Expression.compile(min).evaluate());
}
return new AngleMask(extent, y1, y2, overlay);
}
@Command(
aliases = {"{"},
desc = "Restricts blocks to within a specific radius range of the initial block",
usage = "<min> <max>",
min = 2,
max = 2
)
public Mask radius(double min, double max) throws ExpressionException {
return new RadiusMask((int) min, (int) max);
}
@Command(
aliases = {"|"},
desc = "sides with a specific number of other blocks",
usage = "<mask> <min> <max>",
min = 3,
max = 3
)
public Mask wall(Mask mask, double min, double max) throws ExpressionException {
return new WallMask(mask, (int) min, (int) max);
}
@Command(
aliases = {"~"},
desc = "Adjacent to a specific number of other blocks",
usage = "<mask> [min=1] [max=8]",
min = 1,
max = 3
)
public Mask adjacent(Mask mask, @Optional("-1") double min, @Optional("-1") double max) throws ExpressionException {
if (min == -1 && max == -1) { min = 1; max = 8; }
else if (max == -1) max = min;
if (max >= 8 && min == 1) {
return new AdjacentAnyMask(mask);
}
return new AdjacentMask(mask, (int) min, (int) max);
}
@Command(
aliases = {"<"},
desc = "below a specific block",
usage = "<mask>",
min = 1,
max = 1
)
public Mask below(Mask mask) throws ExpressionException {
OffsetMask offsetMask = new OffsetMask(mask, new Vector(0, 1, 0));
return new MaskIntersection(offsetMask, Masks.negate(mask));
}
@Command(
aliases = {">"},
desc = "above a specific block",
usage = "<mask>",
min = 1,
max = 1
)
public Mask above(Mask mask) throws ExpressionException {
OffsetMask offsetMask = new OffsetMask(mask, new Vector(0, -1, 0));
return new MaskIntersection(offsetMask, Masks.negate(mask));
}
@Command(
aliases = {"$", "#biome"},
desc = "in a specific biome",
help = "in a specific biome. For a list of biomes use //biomelist",
usage = "<biome>",
min = 1,
max = 1
)
public Mask biome(EditSession editSession, BaseBiome biome) throws ExpressionException {
return new BiomeMask(editSession, biome);
}
@Command(
aliases = {"%"},
desc = "percentage chance",
usage = "<chance>",
min = 1,
max = 1
)
public Mask random(double chance) throws ExpressionException {
chance = chance / 100;
return new RandomMask(chance);
}
@Command(
aliases = {"="},
desc = "expression mask",
usage = "<expression>",
min = 1,
max = 1
)
public Mask expression(EditSession editSession, String input) throws ExpressionException {
Expression exp = Expression.compile(input.substring(1), "x", "y", "z");
WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment(
editSession, Vector.ONE, Vector.ZERO);
exp.setEnvironment(env);
return new ExpressionMask(exp);
}
@Command(
aliases = {"!", "#not", "#negate"},
desc = "Negate another mask",
usage = "<mask>",
min = 1,
max = 1
)
public Mask expression(Mask mask) throws ExpressionException {
return Masks.negate(mask);
}
}

View File

@ -0,0 +1,70 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.config.Commands;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.util.command.CommandCallable;
import com.sk89q.worldedit.util.command.Dispatcher;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import static com.google.common.base.Preconditions.checkNotNull;
public class MethodCommands {
public final WorldEdit worldEdit;
private ConcurrentHashMap<Method, CommandCallable> callables;
private Dispatcher dispatcher;
public MethodCommands(WorldEdit worldEdit) {
checkNotNull(worldEdit);
this.worldEdit = worldEdit;
callables = new ConcurrentHashMap<>();
}
@Deprecated
public MethodCommands() {
this.worldEdit = WorldEdit.getInstance();
}
public void register(Method method, CommandCallable callable, Dispatcher dispatcher) {
this.dispatcher = dispatcher;
this.callables.put(method, callable);
}
public CommandCallable getCallable() {
try {
StackTraceElement[] stack = new Exception().getStackTrace();
for (StackTraceElement elem : stack) {
Class<?> clazz = Class.forName(elem.getClassName());
for (Method method : clazz.getMethods()) {
if (method.getName().equals(elem.getMethodName())) {
Command command = method.getAnnotation(Command.class);
if (command != null) return callables.get(method);
}
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return dispatcher;
}
public Command getCommand() {
try {
StackTraceElement[] stack = new Exception().getStackTrace();
for (StackTraceElement elem : stack) {
Class<?> clazz = Class.forName(elem.getClassName());
for (Method method : clazz.getMethods()) {
if (method.getName().equals(elem.getMethodName())) {
Command command = method.getAnnotation(Command.class);
if (command != null) return Commands.translate(clazz, command);
}
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,443 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.DataAngleMask;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.collection.RandomCollection;
import com.boydti.fawe.object.pattern.AngleColorPattern;
import com.boydti.fawe.object.pattern.AverageColorPattern;
import com.boydti.fawe.object.pattern.BiomePattern;
import com.boydti.fawe.object.pattern.BufferedPattern;
import com.boydti.fawe.object.pattern.BufferedPattern2D;
import com.boydti.fawe.object.pattern.DataPattern;
import com.boydti.fawe.object.pattern.DesaturatePattern;
import com.boydti.fawe.object.pattern.ExistingPattern;
import com.boydti.fawe.object.pattern.ExpressionPattern;
import com.boydti.fawe.object.pattern.FullClipboardPattern;
import com.boydti.fawe.object.pattern.IdDataMaskPattern;
import com.boydti.fawe.object.pattern.IdPattern;
import com.boydti.fawe.object.pattern.Linear3DBlockPattern;
import com.boydti.fawe.object.pattern.LinearBlockPattern;
import com.boydti.fawe.object.pattern.MaskedPattern;
import com.boydti.fawe.object.pattern.NoXPattern;
import com.boydti.fawe.object.pattern.NoYPattern;
import com.boydti.fawe.object.pattern.NoZPattern;
import com.boydti.fawe.object.pattern.OffsetPattern;
import com.boydti.fawe.object.pattern.PatternExtent;
import com.boydti.fawe.object.pattern.RandomFullClipboardPattern;
import com.boydti.fawe.object.pattern.RandomOffsetPattern;
import com.boydti.fawe.object.pattern.RelativePattern;
import com.boydti.fawe.object.pattern.SaturatePattern;
import com.boydti.fawe.object.pattern.ShadePattern;
import com.boydti.fawe.object.pattern.SolidRandomOffsetPattern;
import com.boydti.fawe.object.pattern.SurfaceRandomOffsetPattern;
import com.boydti.fawe.object.random.SimplexRandom;
import com.boydti.fawe.util.TextureUtil;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.EmptyClipboardException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.ClipboardPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
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.session.ClipboardHolder;
import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.io.IOException;
import java.util.Set;
import javafx.scene.paint.Color;
@Command(aliases = { "patterns" },
desc = "Help for the various patterns. [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/WorldEdit-and-FAWE-patterns)"
)
public class PatternCommands extends MethodCommands {
public PatternCommands(WorldEdit worldEdit) {
super(worldEdit);
}
@Command(
aliases = {"#existing", "#*"},
desc = "Use the block that is already there")
public Pattern existing(EditSession editSession) {
return new ExistingPattern(editSession);
}
@Command(
aliases = {"#clipboard", "#copy"},
desc = "Use the blocks in your clipboard as the pattern")
public Pattern clipboard(LocalSession session) throws EmptyClipboardException {
ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard();
return new ClipboardPattern(clipboard);
}
@Command(
aliases = {"#simplex"},
desc = "Use simplex noise to randomize blocks",
usage = "<scale=10> <pattern>",
min = 2,
max = 2
)
public Pattern simplex(double scale, Pattern other) {
if (other instanceof RandomPattern) {
scale = (1d / Math.max(1, scale));
RandomCollection<Pattern> collection = ((RandomPattern) other).getCollection();
collection.setRandom(new SimplexRandom(scale));
}
return other;
}
@Command(
aliases = {"#color"},
desc = "Use the block closest to a specific color",
usage = "<color>",
min = 1,
max = 1
)
public Pattern color(String arg) {
Color color = Color.web(arg);
java.awt.Color awtColor = new java.awt.Color((float) color.getRed(), (float) color.getGreen(), (float) color.getBlue(), (float) color.getOpacity());
return Fawe.get().getTextureUtil().getNearestBlock(awtColor.getRGB());
}
@Command(
aliases = {"#anglecolor"},
desc = "A darker block based on the existing terrain angle",
usage = "[randomize=true] [max-complexity=100]",
min = 0,
max = 2
)
public Pattern anglecolor(EditSession editSession, @Optional("true") boolean randomize, @Optional("100") double maxComplexity) {
TextureUtil util = Fawe.get().getCachedTextureUtil(randomize, 0, (int) maxComplexity);
return new AngleColorPattern(util, editSession);
}
@Command(
aliases = {"#angledata"},
desc = "Block data based on the existing terrain angle"
)
public Pattern angledata(EditSession editSession) {
return new DataAngleMask(editSession);
}
@Command(
aliases = {"#saturate"},
desc = "Saturate the existing block with a color",
usage = "<color> [randomize=true] [max-complexity=100]",
min = 1,
max = 3
)
public Pattern saturate(EditSession editSession, String arg, @Optional("true") boolean randomize, @Optional("100") double maxComplexity) {
TextureUtil util = Fawe.get().getCachedTextureUtil(randomize, 0, (int) maxComplexity);
Color color = Color.web(arg);
java.awt.Color awtColor = new java.awt.Color((float) color.getRed(), (float) color.getGreen(), (float) color.getBlue(), (float) color.getOpacity());
return new SaturatePattern(editSession, util, awtColor.getRGB());
}
@Command(
aliases = {"#averagecolor"},
desc = "Average between the existing block and a color",
usage = "<color> [randomize=true] [max-complexity=100]",
min = 1,
max = 3
)
public Pattern averagecolor(EditSession editSession, String arg, @Optional("true") boolean randomize, @Optional("100") double maxComplexity) {
TextureUtil util = Fawe.get().getCachedTextureUtil(randomize, 0, (int) maxComplexity);
Color color = Color.web(arg);
java.awt.Color awtColor = new java.awt.Color((float) color.getRed(), (float) color.getGreen(), (float) color.getBlue(), (float) color.getOpacity());
return new AverageColorPattern(editSession, util, awtColor.getRGB());
}
@Command(
aliases = {"#desaturate"},
desc = "Desaturated color of the existing block",
usage = "[percent=100] [randomize=true] [max-complexity=100]",
min = 0,
max = 3
)
public Pattern desaturate(EditSession editSession, @Optional("100") double percent, @Optional("true") boolean randomize, @Optional("100") double maxComplexity) {
TextureUtil util = Fawe.get().getCachedTextureUtil(randomize, 0, (int) maxComplexity);
return new DesaturatePattern(editSession, util, percent / 100d);
}
@Command(
aliases = {"#lighten"},
desc = "Lighten the existing block",
usage = "[randomize=true] [max-complexity=100]",
min = 0,
max = 2
)
public Pattern lighten(EditSession editSession, @Optional("true") boolean randomize, @Optional("100") double maxComplexity) {
TextureUtil util = Fawe.get().getCachedTextureUtil(randomize, 0, (int) maxComplexity);
return new ShadePattern(editSession, util, false);
}
@Command(
aliases = {"#darken"},
desc = "Darken the existing block",
usage = "[randomize=true] [max-complexity=100]",
min = 0,
max = 2
)
public Pattern darken(EditSession editSession, @Optional("true") boolean randomize, @Optional("100") double maxComplexity) {
TextureUtil util = Fawe.get().getCachedTextureUtil(randomize, 0, (int) maxComplexity);
return new ShadePattern(editSession, util, true);
}
@Command(
aliases = {"#fullcopy"},
desc = "Places your full clipboard at each block",
usage = "[schem|folder|url=#copy] [rotate=false] [flip=false]",
min = 0,
max = 2
)
public Pattern fullcopy(Actor actor, EditSession editSession, LocalSession session, @Optional("#copy") String location, @Optional("false") boolean rotate, @Optional("false") boolean flip) throws EmptyClipboardException, InputParseException, IOException {
ClipboardHolder[] clipboards;
switch (location.toLowerCase()) {
case "#copy":
case "#clipboard":
ClipboardHolder clipboard = session.getExistingClipboard();
if (clipboard == null) {
throw new InputParseException("To use #fullcopy, please first copy something to your clipboard");
}
if (!rotate && !flip) {
return new FullClipboardPattern(editSession, clipboard.getClipboard());
}
clipboards = new ClipboardHolder[]{clipboard};
break;
default:
clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(actor, editSession.getWorldData(), location, true);
break;
}
if (clipboards == null) {
throw new InputParseException("#fullcopy:<source>");
}
return new RandomFullClipboardPattern(editSession, editSession.getWorldData(), clipboards, rotate, flip);
}
@Command(
aliases = {"#buffer"},
desc = "Only place a block once while a pattern is in use",
help = "Only place a block once while a pattern is in use\n" +
"Use with a brush when you don't want to apply to the same spot twice",
usage = "<pattern>",
min = 1,
max = 1
)
public Pattern buffer(Actor actor, Pattern pattern) {
return new BufferedPattern(FawePlayer.wrap(actor), pattern);
}
@Command(
aliases = {"#buffer2d"},
desc = "Only place a block once in a column while a pattern is in use",
usage = "<pattern>",
min = 1,
max = 1
)
public Pattern buffer2d(Actor actor, Pattern pattern) {
return new BufferedPattern2D(FawePlayer.wrap(actor), pattern);
}
@Command(
aliases = {"#iddatamask"},
desc = "Use the pattern's id and the existing blocks data with the provided mask",
help = "Use the pattern's id and the existing blocks data with the provided mask\n" +
" - Use to replace slabs or where the data values needs to be shifted instead of set",
usage = "<bitmask=15> <pattern>",
min = 2,
max = 2
)
public Pattern iddatamask(Actor actor, LocalSession session, EditSession editSession, int bitmask, Pattern pattern) {
return new IdDataMaskPattern(editSession, pattern, bitmask);
}
@Command(
aliases = {"#id"},
desc = "Only change the block id",
usage = "<pattern>",
min = 1,
max = 1
)
public Pattern id(Actor actor, LocalSession session, EditSession editSession, Pattern pattern) {
return new IdPattern(editSession, pattern);
}
@Command(
aliases = {"#data"},
desc = "Only change the block data",
usage = "<pattern>",
min = 1,
max = 1
)
public Pattern data(Actor actor, LocalSession session, EditSession editSession, Pattern pattern) {
return new DataPattern(editSession, pattern);
}
@Command(
aliases = {"#biome", "$"},
desc = "Set the biome",
usage = "<biome>",
min = 1,
max = 1
)
public Pattern data(Actor actor, LocalSession session, EditSession editSession, BaseBiome biome) {
return new BiomePattern(editSession, biome);
}
@Command(
aliases = {"#relative", "#~", "#r", "#rel"},
desc = "Offset the pattern to where you click",
usage = "<pattern>",
min = 1,
max = 1
)
public Pattern relative(Actor actor, LocalSession session, EditSession editSession, Pattern pattern) {
return new RelativePattern(pattern);
}
@Command(
aliases = {"#!x", "#nx", "#nox"},
desc = "The pattern will not be provided the x axis info",
help = "The pattern will not be provided the z axis info.\n" +
"Example: #!x[#!z[#~[#l3d[pattern]]]]",
usage = "<pattern>",
min = 1,
max = 1
)
public Pattern nox(Actor actor, LocalSession session, EditSession editSession, Pattern pattern) {
return new NoXPattern(pattern);
}
@Command(
aliases = {"#!y", "#ny", "#noy"},
desc = "The pattern will not be provided the y axis info",
usage = "<pattern>",
min = 1,
max = 1
)
public Pattern noy(Actor actor, LocalSession session, EditSession editSession, Pattern pattern) {
return new NoYPattern(pattern);
}
@Command(
aliases = {"#!z", "#nz", "#noz"},
desc = "The pattern will not be provided the z axis info",
usage = "<pattern>",
min = 1,
max = 1
)
public Pattern noz(Actor actor, LocalSession session, EditSession editSession, Pattern pattern) {
return new NoZPattern(pattern);
}
@Command(
aliases = {"#mask"},
desc = "Apply a pattern depending on a mask",
usage = "<mask> <pattern-true> <pattern-false>",
min = 3,
max = 3
)
public Pattern mask(Actor actor, LocalSession session, Mask mask, Pattern pass, Pattern fail) {
PatternExtent extent = new PatternExtent(pass);
return new MaskedPattern(mask, extent, fail);
}
@Command(
aliases = {"#offset"},
desc = "Offset a pattern",
usage = "<dx> <dy> <dz> <pattern>",
min = 4,
max = 4
)
public Pattern offset(Actor actor, LocalSession session, double x, double y, double z, Pattern pattern) {
return new OffsetPattern(pattern, (int) x, (int) y, (int) z);
}
@Command(
aliases = {"#surfacespread"},
desc = "Randomly change the position to another block on the surface",
usage = "<distance> <pattern>",
min = 2,
max = 2
)
public Pattern surfacespread(Actor actor, LocalSession session, EditSession editSession, double distance, Pattern pattern) {
return new SurfaceRandomOffsetPattern(editSession, pattern, (int) distance);
}
@Command(
aliases = {"#solidspread"},
desc = "Randomly spread solid blocks",
usage = "<dx> <dy> <dz> <pattern>",
min = 4,
max = 4
)
public Pattern solidspread(Actor actor, LocalSession session, double x, double y, double z, Pattern pattern) {
return new SolidRandomOffsetPattern(pattern, (int) x, (int) y, (int) z);
}
@Command(
aliases = {"#spread", "#randomoffset"},
desc = "Randomly spread blocks",
usage = "<dx> <dy> <dz> <pattern>",
min = 4,
max = 4
)
public Pattern spread(Actor actor, LocalSession session, double x, double y, double z, Pattern pattern) {
return new RandomOffsetPattern(pattern, (int) x, (int) y, (int) z);
}
@Command(
aliases = {"#linear", "#l"},
desc = "Sequentially set blocks from a list of patterns",
usage = "<pattern>",
min = 1,
max = 1
)
public Pattern linear(Actor actor, LocalSession session, Pattern other) {
if (other instanceof RandomPattern) {
Set<Pattern> patterns = ((RandomPattern) other).getPatterns();
return new LinearBlockPattern(patterns.toArray(new Pattern[patterns.size()]));
}
return other;
}
@Command(
aliases = {"#linear3d", "#l3d"},
desc = "Use the x,y,z coordinate to pick a block from the list",
usage = "<pattern>",
min = 1,
max = 1
)
public Pattern linear3d(Actor actor, LocalSession session, Pattern other) {
if (other instanceof RandomPattern) {
Set<Pattern> patterns = ((RandomPattern) other).getPatterns();
return new Linear3DBlockPattern(patterns.toArray(new Pattern[patterns.size()]));
}
return other;
}
@Command(
aliases = {"="},
desc = "Expression pattern: http://wiki.sk89q.com/wiki/WorldEdit/Expression_syntax",
usage = "<expression>",
min = 1,
max = 1
)
public Pattern expression(Actor actor, LocalSession session, EditSession editSession, String input) throws ExpressionException {
Expression exp = Expression.compile(input, "x", "y", "z");
WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment(editSession, Vector.ONE, Vector.ZERO);
exp.setEnvironment(env);
return new ExpressionPattern(exp);
}
}

View File

@ -1,35 +1,52 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.extent.DefaultTransformParser;
import com.boydti.fawe.object.brush.TargetMode;
import com.boydti.fawe.object.brush.scroll.ScrollClipboard;
import com.boydti.fawe.object.brush.scroll.ScrollMask;
import com.boydti.fawe.object.brush.scroll.ScrollPattern;
import com.boydti.fawe.object.brush.scroll.ScrollRange;
import com.boydti.fawe.object.brush.scroll.ScrollSize;
import com.boydti.fawe.object.brush.scroll.ScrollTarget;
import com.boydti.fawe.object.brush.visualization.VisualMode;
import com.boydti.fawe.object.extent.ResettableExtent;
import com.boydti.fawe.util.MathMan;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.Tool;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.extension.factory.DefaultMaskParser;
import com.sk89q.worldedit.extension.factory.DefaultTransformParser;
import com.sk89q.worldedit.extension.factory.HashTagPatternParser;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.CommandManager;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.command.parametric.Optional;
import java.io.IOException;
/**
* Tool commands.
*/
@Command(aliases = {}, desc = "Tool commands")
public class ToolUtilCommands {
private final WorldEdit we;
private final DefaultTransformParser transformParser;
public class ToolUtilCommands extends MethodCommands {
public ToolUtilCommands(WorldEdit we) {
this.we = we;
this.transformParser = new DefaultTransformParser(we);
super(we);
}
@Command(
@ -52,19 +69,233 @@ public class ToolUtilCommands {
BBC.SUPERPICKAXE_DISABLED.send(player);
} else {
if ("off".equals(newState)) {
BBC.SUPERPICKAXE_DISABLED.send(player);
return;
}
session.enableSuperPickAxe();
BBC.SUPERPICKAXE_ENABLED.send(player);
}
}
@Command(
aliases = { "patterns" },
usage = "[page=1|search|pattern]",
desc = "View help about patterns",
help = "Patterns determine what blocks are placed\n" +
" - Use [brackets] for arguments\n" +
" - Use , to OR multiple\n" +
"e.g. #surfacespread[10][#existing],andesite\n" +
"More Info: https://git.io/vSPmA",
min = 1
)
public void patterns(Player player, LocalSession session, CommandContext args) throws WorldEditException {
HashTagPatternParser parser = FaweAPI.getParser(HashTagPatternParser.class);
if (parser != null) {
UtilityCommands.help(args, worldEdit, player, "/" + getCommand().aliases()[0] + " ", parser.getDispatcher());
}
}
@Command(
aliases = { "masks" },
usage = "[page=1|search|mask]",
desc = "View help about masks",
help = "Masks determine if a block can be placed\n" +
" - Use [brackets] for arguments\n" +
" - Use , to OR multiple\n" +
" - Use & to AND multiple\n" +
"e.g. >[stone,dirt],#light[0][5],$jungle\n" +
"More Info: https://git.io/v9r4K",
min = 1
)
public void masks(Player player, LocalSession session, CommandContext args) throws WorldEditException {
DefaultMaskParser parser = FaweAPI.getParser(DefaultMaskParser.class);
if (parser != null) {
UtilityCommands.help(args, worldEdit, player, "/" + getCommand().aliases()[0] + " ", parser.getDispatcher());
}
}
@Command(
aliases = { "transforms" },
usage = "[page=1|search|transform]",
desc = "View help about transforms",
help = "Masks modify how a block is placed\n" +
" - Use [brackets] for arguments\n" +
" - Use , to OR multiple\n" +
" - Use & to AND multiple\n" +
"More Info: https://git.io/v9KHO",
min = 1
)
public void transforms(Player player, LocalSession session, CommandContext args) throws WorldEditException {
DefaultTransformParser parser = Fawe.get().getTransformParser();
if (parser != null) {
UtilityCommands.help(args, worldEdit, player, "/" + getCommand().aliases()[0] + " ", parser.getDispatcher());
}
}
@Command(
aliases = { "primary" },
usage = "[brush arguments]",
desc = "Set the right click brush",
help = "Set the right click brush",
min = 1
)
public void primary(Player player, LocalSession session, CommandContext args) throws WorldEditException {
BaseBlock item = player.getBlockInHand();
BrushTool tool = session.getBrushTool(player, false);
session.setTool(item.getId(), item.getData(), null, player);
String cmd = "brush " + args.getJoinedStrings(0);
CommandEvent event = new CommandEvent(player, cmd);
CommandManager.getInstance().handleCommandOnCurrentThread(event);
BrushTool newTool = session.getBrushTool(item.getId(), item.getData(), player, false);
if (newTool != null && tool != null) {
newTool.setSecondary(tool.getSecondary());
}
}
@Command(
aliases = { "secondary" },
usage = "[brush arguments]",
desc = "Set the left click brush",
help = "Set the left click brush",
min = 1
)
public void secondary(Player player, LocalSession session, CommandContext args) throws WorldEditException {
BaseBlock item = player.getBlockInHand();
BrushTool tool = session.getBrushTool(player, false);
session.setTool(item.getId(), item.getData(), null, player);
String cmd = "brush " + args.getJoinedStrings(0);
CommandEvent event = new CommandEvent(player, cmd);
CommandManager.getInstance().handleCommandOnCurrentThread(event);
BrushTool newTool = session.getBrushTool(item.getId(), item.getData(), player, false);
if (newTool != null && tool != null) {
newTool.setPrimary(tool.getPrimary());
}
}
@Command(
aliases = { "visualize", "visual", "vis" },
usage = "[mode]",
desc = "Toggle between different visualization modes",
min = 0,
max = 1
)
public void visual(Player player, LocalSession session, @Optional("0") int mode) throws WorldEditException {
BrushTool tool = session.getBrushTool(player, false);
if (tool == null) {
BBC.BRUSH_NONE.send(player);
return;
}
VisualMode[] modes = VisualMode.values();
VisualMode newMode = modes[MathMan.wrap(mode, 0, modes.length - 1)];
tool.setVisualMode(newMode);
BBC.BRUSH_VISUAL_MODE_SET.send(player, newMode);
}
@Command(
aliases = { "target", "tar" },
usage = "[mode]",
desc = "Toggle between different target modes",
min = 0,
max = 1
)
public void target(Player player, LocalSession session, @Optional("0") int mode) throws WorldEditException {
BrushTool tool = session.getBrushTool(player, false);
if (tool == null) {
BBC.BRUSH_NONE.send(player);
return;
}
TargetMode[] modes = TargetMode.values();
TargetMode newMode = modes[MathMan.wrap(mode, 0, modes.length - 1)];
tool.setTargetMode(newMode);
BBC.BRUSH_TARGET_MODE_SET.send(player, newMode);
}
@Command(
aliases = { "scroll" },
usage = "[none|clipboard|mask|pattern|range|size|visual|target]",
desc = "Toggle between different target modes",
min = 1,
max = -1
)
public void scroll(Player player, EditSession editSession, LocalSession session, CommandContext args) throws WorldEditException {
BrushTool tool = session.getBrushTool(player, false);
if (tool == null) {
BBC.BRUSH_NONE.send(player);
return;
}
ParserContext parserContext = new ParserContext();
parserContext.setActor(player);
parserContext.setWorld(player.getWorld());
parserContext.setSession(session);
parserContext.setExtent(editSession);
final LocalConfiguration config = this.worldEdit.getConfiguration();
switch (args.getString(0).toLowerCase()) {
case "none":
tool.setScrollAction(null);
break;
case "clipboard":
if (args.argsLength() != 2) {
BBC.COMMAND_SYNTAX.send(player, "clipboard [file]");
return;
}
String filename = args.getString(1);
try {
ClipboardHolder[] clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(player, player.getWorld().getWorldData(), filename, true);
if (clipboards == null) {
return;
}
tool.setScrollAction(new ScrollClipboard(tool, session, clipboards));
break;
} catch (IOException e) {
throw new RuntimeException(e);
}
case "mask":
if (args.argsLength() < 2) {
BBC.COMMAND_SYNTAX.send(player, "mask [mask 1] [mask 2] [mask 3]...");
return;
}
Mask[] masks = new Mask[args.argsLength() - 1];
for (int i = 1; i < args.argsLength(); i++) {
String arg = args.getString(i);
masks[i - 1] = worldEdit.getMaskFactory().parseFromInput(arg, parserContext);
}
tool.setScrollAction(new ScrollMask(tool, masks));
break;
case "pattern":
if (args.argsLength() < 2) {
BBC.COMMAND_SYNTAX.send(player, "pattern [pattern 1] [pattern 2] [pattern 3]...");
return;
}
Pattern[] patterns = new Pattern[args.argsLength() - 1];
for (int i = 1; i < args.argsLength(); i++) {
String arg = args.getString(i);
patterns[i - 1] = worldEdit.getPatternFactory().parseFromInput(arg, parserContext);
}
tool.setScrollAction(new ScrollPattern(tool, patterns));
break;
case "range":
tool.setScrollAction(new ScrollRange(tool));
break;
case "size":
tool.setScrollAction(new ScrollSize(tool));
break;
case "target":
tool.setScrollAction(new ScrollTarget(tool));
break;
default:
BBC.COMMAND_SYNTAX.send(player, "[none|clipboard|mask|pattern|range|size|visual|target]");
return;
}
BBC.BRUSH_SCROLL_ACTION_SET.send(player, args.getJoinedStrings(0));
}
@Command(
aliases = { "mask", "/mask" },
usage = "[mask]",
desc = "Set the brush mask",
desc = "Set the brush destination mask",
min = 0,
max = -1
)
@ -84,7 +315,7 @@ public class ToolUtilCommands {
parserContext.setWorld(player.getWorld());
parserContext.setSession(session);
parserContext.setExtent(editSession);
mask = we.getMaskFactory().parseFromInput(context.getJoinedStrings(0), parserContext);
mask = worldEdit.getMaskFactory().parseFromInput(context.getJoinedStrings(0), parserContext);
}
if (tool instanceof BrushTool) {
BrushTool bt = (BrushTool) tool;
@ -104,7 +335,8 @@ public class ToolUtilCommands {
@Command(
aliases = { "smask", "/smask", "/sourcemask", "sourcemask" },
usage = "[mask]",
desc = "Set the brush mask",
desc = "Set the brush source mask",
help = "Set the brush source mask",
min = 0,
max = -1
)
@ -124,7 +356,7 @@ public class ToolUtilCommands {
parserContext.setWorld(player.getWorld());
parserContext.setSession(session);
parserContext.setExtent(editSession);
mask = we.getMaskFactory().parseFromInput(context.getJoinedStrings(0), parserContext);
mask = worldEdit.getMaskFactory().parseFromInput(context.getJoinedStrings(0), parserContext);
}
if (tool instanceof BrushTool) {
BrushTool bt = (BrushTool) tool;
@ -163,7 +395,7 @@ public class ToolUtilCommands {
parserContext.setWorld(player.getWorld());
parserContext.setSession(session);
parserContext.setExtent(editSession);
transform = transformParser.parseFromInput(context.getJoinedStrings(0), parserContext);
transform = Fawe.get().getTransformParser().parseFromInput(context.getJoinedStrings(0), parserContext);
}
if (tool instanceof BrushTool) {
BrushTool bt = (BrushTool) tool;
@ -230,7 +462,7 @@ public class ToolUtilCommands {
public void size(Player player, LocalSession session, CommandContext args, @Switch('h') boolean offHand) throws WorldEditException {
int radius = args.getInteger(0);
we.checkMaxBrushRadius(radius);
worldEdit.checkMaxBrushRadius(radius);
Tool tool = session.getTool(player);
if (tool instanceof BrushTool) {

View File

@ -0,0 +1,126 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.object.extent.Linear3DTransform;
import com.boydti.fawe.object.extent.LinearTransform;
import com.boydti.fawe.object.extent.OffsetExtent;
import com.boydti.fawe.object.extent.PatternTransform;
import com.boydti.fawe.object.extent.RandomOffsetTransform;
import com.boydti.fawe.object.extent.RandomTransform;
import com.boydti.fawe.object.extent.ResettableExtent;
import com.boydti.fawe.object.extent.ScaleTransform;
import com.boydti.fawe.object.extent.TransformExtent;
import com.boydti.fawe.util.ExtentTraverser;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.util.command.parametric.Optional;
import java.util.Set;
@Command(aliases = { "transforms" },
desc = "Help for the various transforms. [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/Transforms)"
)
public class TransformCommands extends MethodCommands {
public TransformCommands(WorldEdit worldEdit) {
super(worldEdit);
}
@Command(
aliases = {"#linear", "#l"},
desc = "Sequentially pick from a list of transform",
usage = "<transform>",
min = 1,
max = 2
)
public ResettableExtent linear(Actor actor, LocalSession session, @Optional("#null") ResettableExtent other) {
if (other instanceof RandomTransform) {
Set<ResettableExtent> extents = ((RandomTransform) other).getExtents();
return new LinearTransform(extents.toArray(new ResettableExtent[extents.size()]));
}
return other;
}
@Command(
aliases = {"#linear3d", "#l3d"},
desc = "Use the x,y,z coordinate to pick a transform from the list",
usage = "<transform>",
min = 1,
max = 2
)
public ResettableExtent linear3d(Actor actor, LocalSession session, @Optional("#null") ResettableExtent other) {
if (other instanceof RandomTransform) {
Set<ResettableExtent> extents = ((RandomTransform) other).getExtents();
return new Linear3DTransform(extents.toArray(new ResettableExtent[extents.size()]));
}
return other;
}
@Command(
aliases = {"#pattern"},
desc = "Always use a specific pattern",
usage = "<pattern> [transform]",
min = 1,
max = 2
)
public ResettableExtent pattern(Actor actor, LocalSession session, Pattern pattern, @Optional("#null") ResettableExtent other) {
return new PatternTransform(other, pattern);
}
@Command(
aliases = {"#offset"},
desc = "Offset transform",
usage = "<dx> <dy> <dz> [transform]",
min = 3,
max = 4
)
public ResettableExtent offset(Actor actor, LocalSession session, double x, double y, double z, @Optional("#null") ResettableExtent other) {
return new OffsetExtent(other, (int) x, (int) y, (int) z);
}
@Command(
aliases = {"#spread", "#randomoffset"},
desc = "Random offset transform",
usage = "<dx> <dy> <dz> [transform]",
min = 3,
max = 4
)
public ResettableExtent randomoffset(Actor actor, LocalSession session, double x, double y, double z, @Optional("#null") ResettableExtent other) {
return new RandomOffsetTransform(other, (int) x, (int) y, (int) z);
}
@Command(
aliases = {"#scale"},
desc = "All changes will be scaled",
usage = "<dx> <dy> <dz> [transform]",
min = 3,
max = 4
)
public ResettableExtent scale(Actor actor, LocalSession session, double x, double y, double z, @Optional("#null") ResettableExtent other) {
return new ScaleTransform(other, x, y, z);
}
@Command(
aliases = {"#rotate"},
desc = "All changes will be rotate around the initial position",
usage = "<rotateX> <rotateY> <rotateZ> [transform]",
min = 3,
max = 4
)
public ResettableExtent rotate(Player player, LocalSession session, double x, double y, double z, @Optional("#null") ResettableExtent other) {
ExtentTraverser traverser = new ExtentTraverser(other).find(TransformExtent.class);
BlockTransformExtent affine = (TransformExtent) (traverser != null ? traverser.get() : null);
if (affine == null) {
other = affine = new TransformExtent(other, player.getWorld().getWorldData().getBlockRegistry());
}
AffineTransform transform = (AffineTransform) affine.getTransform();
transform = transform.rotateX(x);
transform = transform.rotateY(y);
transform = transform.rotateZ(z);
affine.setTransform(transform);
return (ResettableExtent) other;
}
}

View File

@ -22,6 +22,7 @@ package com.sk89q.worldedit.command;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FaweLimit;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.util.StringMan;
import com.google.common.base.Joiner;
import com.google.common.util.concurrent.AtomicDouble;
import com.sk89q.minecraft.util.commands.Command;
@ -70,8 +71,10 @@ import com.sk89q.worldedit.world.World;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
@ -85,14 +88,13 @@ import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT;
* Utility commands.
*/
@Command(aliases = {}, desc = "Various utility commands: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Utilities)")
public class UtilityCommands {
private final WorldEdit we;
public class UtilityCommands extends MethodCommands {
public UtilityCommands(WorldEdit we) {
this.we = we;
super(we);
}
@Command(
aliases = { "/fill" },
usage = "<block> <radius> [depth]",
@ -103,7 +105,7 @@ public class UtilityCommands {
@CommandPermissions("worldedit.fill")
@Logging(PLACEMENT)
public void fill(Player player, LocalSession session, EditSession editSession, Pattern pattern, double radius, @Optional("1") double depth) throws WorldEditException {
we.checkMaxRadius(radius);
worldEdit.checkMaxRadius(radius);
Vector pos = session.getPlacementPosition(player);
int affected = 0;
if (pattern instanceof BlockPattern) {
@ -124,7 +126,7 @@ public class UtilityCommands {
@CommandPermissions("worldedit.fill.recursive")
@Logging(PLACEMENT)
public void fillr(Player player, LocalSession session, EditSession editSession, Pattern pattern, double radius, @Optional("1") double depth) throws WorldEditException {
we.checkMaxRadius(radius);
worldEdit.checkMaxRadius(radius);
Vector pos = session.getPlacementPosition(player);
int affected = 0;
if (pattern instanceof BlockPattern) {
@ -145,7 +147,7 @@ public class UtilityCommands {
@CommandPermissions("worldedit.drain")
@Logging(PLACEMENT)
public void drain(Player player, LocalSession session, EditSession editSession, double radius) throws WorldEditException {
we.checkMaxRadius(radius);
worldEdit.checkMaxRadius(radius);
int affected = editSession.drainArea(
session.getPlacementPosition(player), radius);
player.print(BBC.getPrefix() + affected + " block(s) have been changed.");
@ -161,7 +163,7 @@ public class UtilityCommands {
@CommandPermissions("worldedit.fixlava")
@Logging(PLACEMENT)
public void fixLava(Player player, LocalSession session, EditSession editSession, double radius) throws WorldEditException {
we.checkMaxRadius(radius);
worldEdit.checkMaxRadius(radius);
int affected = editSession.fixLiquid(
session.getPlacementPosition(player), radius, 10, 11);
player.print(BBC.getPrefix() + affected + " block(s) have been changed.");
@ -177,7 +179,7 @@ public class UtilityCommands {
@CommandPermissions("worldedit.fixwater")
@Logging(PLACEMENT)
public void fixWater(Player player, LocalSession session, EditSession editSession, double radius) throws WorldEditException {
we.checkMaxRadius(radius);
worldEdit.checkMaxRadius(radius);
int affected = editSession.fixLiquid(
session.getPlacementPosition(player), radius, 8, 9);
player.print(BBC.getPrefix() + affected + " block(s) have been changed.");
@ -193,7 +195,7 @@ public class UtilityCommands {
@CommandPermissions("worldedit.removeabove")
@Logging(PLACEMENT)
public void removeAbove(Player player, LocalSession session, EditSession editSession, @Optional("1") double size, @Optional("256") double height) throws WorldEditException {
we.checkMaxRadius(size);
worldEdit.checkMaxRadius(size);
int affected = editSession.removeAbove(session.getPlacementPosition(player), (int) size, (int) height);
player.print(BBC.getPrefix() + affected + " block(s) have been removed.");
}
@ -208,7 +210,7 @@ public class UtilityCommands {
@CommandPermissions("worldedit.removebelow")
@Logging(PLACEMENT)
public void removeBelow(Player player, LocalSession session, EditSession editSession, @Optional("1") double size, @Optional("256") double height) throws WorldEditException {
we.checkMaxRadius(size);
worldEdit.checkMaxRadius(size);
int affected = editSession.removeBelow(session.getPlacementPosition(player), (int) size, (int) height);
player.print(BBC.getPrefix() + affected + " block(s) have been removed.");
}
@ -223,7 +225,7 @@ public class UtilityCommands {
@CommandPermissions("worldedit.removenear")
@Logging(PLACEMENT)
public void removeNear(Player player, LocalSession session, EditSession editSession, BaseBlock block, @Optional("50") double size) throws WorldEditException {
we.checkMaxRadius(size);
worldEdit.checkMaxRadius(size);
int affected = editSession.removeNear(session.getPlacementPosition(player), block.getId(), (int) size);
player.print(BBC.getPrefix() + affected + " block(s) have been removed.");
}
@ -315,12 +317,12 @@ public class UtilityCommands {
@Logging(PLACEMENT)
public void extinguish(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
LocalConfiguration config = worldEdit.getConfiguration();
int defaultRadius = config.maxRadius != -1 ? Math.min(40, config.maxRadius) : 40;
int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0))
: defaultRadius;
we.checkMaxRadius(size);
worldEdit.checkMaxRadius(size);
int affected = editSession.removeNear(session.getPlacementPosition(player), 51, size);
player.print(BBC.getPrefix() + affected + " block(s) have been removed.");
@ -349,7 +351,7 @@ public class UtilityCommands {
@CommandPermissions("worldedit.butcher")
@Logging(PLACEMENT)
public void butcher(Actor actor, CommandContext args) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
LocalConfiguration config = worldEdit.getConfiguration();
Player player = actor instanceof Player ? (Player) actor : null;
// technically the default can be larger than the max, but that's not my problem
@ -379,7 +381,7 @@ public class UtilityCommands {
EditSession editSession = null;
if (player != null) {
session = we.getSessionManager().get(player);
session = worldEdit.getSessionManager().get(player);
Vector center = session.getPlacementPosition(player);
editSession = session.createEditSession(player);
List<? extends Entity> entities;
@ -391,7 +393,7 @@ public class UtilityCommands {
}
visitors.add(new EntityVisitor(entities.iterator(), flags.createFunction(editSession.getWorld().getWorldData().getEntityRegistry())));
} else {
Platform platform = we.getPlatformManager().queryCapability(Capability.WORLD_EDITING);
Platform platform = worldEdit.getPlatformManager().queryCapability(Capability.WORLD_EDITING);
for (World world : platform.getWorlds()) {
List<? extends Entity> entities = world.getEntities();
visitors.add(new EntityVisitor(entities.iterator(), flags.createFunction(world.getWorldData().getEntityRegistry())));
@ -439,7 +441,7 @@ public class UtilityCommands {
EditSession editSession = null;
if (player != null) {
session = we.getSessionManager().get(player);
session = worldEdit.getSessionManager().get(player);
Vector center = session.getPlacementPosition(player);
editSession = session.createEditSession(player);
List<? extends Entity> entities;
@ -451,7 +453,7 @@ public class UtilityCommands {
}
visitors.add(new EntityVisitor(entities.iterator(), remover.createFunction(editSession.getWorld().getWorldData().getEntityRegistry())));
} else {
Platform platform = we.getPlatformManager().queryCapability(Capability.WORLD_EDITING);
Platform platform = worldEdit.getPlatformManager().queryCapability(Capability.WORLD_EDITING);
for (World world : platform.getWorlds()) {
List<? extends Entity> entities = world.getEntities();
visitors.add(new EntityVisitor(entities.iterator(), remover.createFunction(world.getWorldData().getEntityRegistry())));
@ -515,7 +517,7 @@ public class UtilityCommands {
)
@CommandPermissions("worldedit.help")
public void help(Actor actor, CommandContext args) throws WorldEditException {
help(args, we, actor);
help(args, worldEdit, actor);
}
private static CommandMapping detectCommand(Dispatcher dispatcher, String command, boolean isRootLevel) {
@ -547,8 +549,13 @@ public class UtilityCommands {
}
public static void help(CommandContext args, WorldEdit we, Actor actor) {
CommandCallable callable = we.getPlatformManager().getCommandManager().getDispatcher();
help(args, we, actor, "/", null);
}
public static void help(CommandContext args, WorldEdit we, Actor actor, String prefix, CommandCallable callable) {
if (callable == null) {
callable = we.getPlatformManager().getCommandManager().getDispatcher();
}
CommandLocals locals = args.getLocals();
int page = -1;
@ -567,7 +574,8 @@ public class UtilityCommands {
}
effectiveLength--;
}
} catch (NumberFormatException ignored) {}
} catch (NumberFormatException ignored) {
}
boolean isRootLevel = true;
List<String> visited = new ArrayList<String>();
@ -616,7 +624,39 @@ public class UtilityCommands {
callable = mapping.getCallable();
} else {
if (isRootLevel) {
actor.printError(String.format("The command '%s' could not be found.", args.getString(i)));
Set<String> found = new HashSet<>();
String arg = args.getString(i).toLowerCase();
String closest = null;
int distance = Integer.MAX_VALUE;
for (CommandMapping map : aliases) {
String desc = map.getDescription().getDescription();
if (desc == null) desc = map.getDescription().getHelp();
if (desc == null) desc = "";
String[] descSplit = desc.replaceAll("[^A-Za-z0-9]", "").toLowerCase().split(" ");
for (String alias : map.getAllAliases()) {
if (alias.equals(arg)) {
closest = map.getPrimaryAlias();
distance = 0;
found.add(map.getPrimaryAlias());
} else if (alias.contains(arg)) {
closest = map.getPrimaryAlias();
distance = 1;
found.add(map.getPrimaryAlias());
} else if (StringMan.isEqualIgnoreCaseToAny(arg, descSplit)) {
closest = map.getPrimaryAlias();
distance = 1;
found.add(map.getPrimaryAlias());
} else {
int currentDist = StringMan.getLevenshteinDistance(alias, arg);
if (currentDist < distance) {
distance = currentDist;
closest = map.getPrimaryAlias();
}
}
}
}
found.add(closest);
BBC.HELP_SUGGEST.send(actor, arg, StringMan.join(found, ", "));
return;
} else {
actor.printError(String.format("The sub-command '%s' under '%s' could not be found.",
@ -642,9 +682,8 @@ public class UtilityCommands {
aliases = mappings;
}
page = Math.max(0, page);
} else {
} else if (grouped.size() > 1) {
StringBuilder message = new StringBuilder();
String cmd = args.getCommand();
message.append(BBC.getPrefix() + BBC.HELP_HEADER_CATEGORIES.s() + "\n");
StringBuilder builder = new StringBuilder();
boolean first = true;
@ -663,7 +702,7 @@ public class UtilityCommands {
Collections.sort(aliases, new PrimaryAliasComparator(CommandManager.COMMAND_CLEAN_PATTERN));
// Calculate pagination
int offset = perPage * page;
int offset = perPage * Math.max(0, page);
int pageTotal = (int) Math.ceil(aliases.size() / (double) perPage);
// Box
@ -673,14 +712,14 @@ public class UtilityCommands {
message.append("&c").append(String.format("There is no page %d (total number of pages is %d).", page + 1, pageTotal));
} else {
message.append(BBC.getPrefix() + BBC.HELP_HEADER.format(page + 1, pageTotal) + "\n");
List<CommandMapping> list = aliases.subList(offset, Math.min(offset + perPage, aliases.size()));
List<CommandMapping> list = aliases.subList(offset, Math.min(offset + perPage, aliases.size() - 1));
boolean first = true;
// Add each command
for (CommandMapping mapping : list) {
CommandCallable c = mapping.getCallable();
StringBuilder s1 = new StringBuilder();
s1.append("/");
s1.append(prefix);
if (!visited.isEmpty()) {
s1.append(Joiner.on(" ").join(visited));
s1.append(" ");

View File

@ -168,6 +168,9 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
blockType = BlockType.lookup(testId);
if (blockType == null) {
int t = worldEdit.getServer().resolveItem(testId);
if (t == 0 && !testId.contains("air")) {
throw new NoMatchException("Invalid block '" + input + "'.");
}
if (t >= 0) {
blockType = BlockType.fromID(t); // Could be null
blockId = t;

View File

@ -1,419 +1,170 @@
package com.sk89q.worldedit.extension.factory;
import com.boydti.fawe.command.FaweParser;
import com.boydti.fawe.command.SuggestInputParseException;
import com.boydti.fawe.object.mask.AdjacentAnyMask;
import com.boydti.fawe.object.mask.AdjacentMask;
import com.boydti.fawe.object.mask.AngleMask;
import com.boydti.fawe.object.mask.BlockLightMask;
import com.boydti.fawe.object.mask.BrightnessMask;
import com.boydti.fawe.object.mask.CustomMask;
import com.boydti.fawe.object.mask.DataMask;
import com.boydti.fawe.object.mask.IdDataMask;
import com.boydti.fawe.object.mask.IdMask;
import com.boydti.fawe.object.mask.LightMask;
import com.boydti.fawe.object.mask.OpacityMask;
import com.boydti.fawe.object.mask.RadiusMask;
import com.boydti.fawe.object.mask.SkyLightMask;
import com.boydti.fawe.object.mask.WallMask;
import com.boydti.fawe.object.mask.XAxisMask;
import com.boydti.fawe.object.mask.YAxisMask;
import com.boydti.fawe.object.mask.ZAxisMask;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.StringMan;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.Vector;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.command.MaskCommands;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.NoMatchException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.BiomeMask2D;
import com.sk89q.worldedit.function.mask.BlockMask;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.ExpressionMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.MaskIntersection;
import com.sk89q.worldedit.function.mask.MaskUnion;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.mask.NoiseFilter;
import com.sk89q.worldedit.function.mask.OffsetMask;
import com.sk89q.worldedit.function.mask.RegionMask;
import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.math.noise.RandomNoise;
import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment;
import com.sk89q.worldedit.internal.command.ActorAuthorizer;
import com.sk89q.worldedit.internal.command.WorldEditBinding;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.session.request.RequestSelection;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.biome.Biomes;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import java.lang.reflect.Constructor;
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.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Parses mask input strings.
*/
public class DefaultMaskParser extends FaweParser<Mask> {
public static final String[] EXPRESSION_MASK = new String[] { "=<expression>" };
public static final String[] BLOCK_MASK = new String[] { "<blocks>" };
public static final String[] SIMPLE_MASK = new String[] {
"#nolight", "#haslight", "#existing", "#solid", "#dregion", "#dselection", "#dsel", "#selection", "#region", "#sel", "#xaxis", "#yaxis", "#zaxis", "#id", "#data", "#wall", "#surface",
};
public static final String[] DELEGATE_MASKS = new String[] {
"#offset:", "#light:", "#blocklight:", "#skylight:", "#brightness:", "#opacity:"
};
public static final String[] CHARACTER_MASKS= new String[] {
"/", "{", "|", "~", ">", "<", "$", "%", "=", "!",
};
public static final String[] HASHTAG_MASKS = MainUtil.joinArrayGeneric(SIMPLE_MASK, DELEGATE_MASKS);
public static final String[] ALL_MASKS = MainUtil.joinArrayGeneric(EXPRESSION_MASK, BLOCK_MASK, SIMPLE_MASK, DELEGATE_MASKS, CHARACTER_MASKS);
private final Dispatcher dispatcher;
private final Pattern INTERSECTION_PATTERN = Pattern.compile("[&|;]+(?![^\\[]*\\])");
public DefaultMaskParser(WorldEdit worldEdit) {
super(worldEdit);
this.dispatcher = new SimpleDispatcher();
this.register(new MaskCommands(worldEdit));
}
private static Map<String, Class<? extends CustomMask>> customMasks = new ConcurrentHashMap<>();
/**
* Register a mask!
* @param id
* @param clazz
*/
public void addMask(String id, Class<? extends CustomMask> clazz) {
checkNotNull(clazz);
checkNotNull(id);
customMasks.put(id.toLowerCase(), clazz);
public Dispatcher getDispatcher() {
return dispatcher;
}
public static Map<String, Class<? extends CustomMask>> getCustomMasks() {
return customMasks;
public void register(Object clazz) {
ParametricBuilder builder = new ParametricBuilder();
builder.setAuthorizer(new ActorAuthorizer());
builder.addBinding(new WorldEditBinding(worldEdit));
builder.registerMethodsAsCommands(dispatcher, clazz);
}
@Override
public Mask parseFromInput(String input, ParserContext context) throws InputParseException {
List<Mask> masks = new ArrayList<Mask>();
for (String component : StringMan.split(input, ' ')) {
if (component.isEmpty()) {
continue;
}
HashSet<BaseBlock> blocks = new HashSet<BaseBlock>();
List<Mask> masksUnion = new ArrayList<Mask>();
for (String elem : StringMan.split(component, ',')) {
ArrayList<Mask> list = new ArrayList<Mask>();
list.add(catchSuggestion(input, list, elem, context));
if (list.size() == 1) {
Mask mask = list.get(0);
if (mask.getClass() == BlockMask.class) {
blocks.addAll(((BlockMask) mask).getBlocks());
} else {
masksUnion.add(mask);
}
} else {
masksUnion.add(new MaskIntersection(list));
}
}
if (!blocks.isEmpty()) {
masksUnion.add(new BlockMask(Request.request().getExtent(), blocks));
}
if (masksUnion.size() == 1) {
masks.add(masksUnion.get(0));
} else {
masks.add(new MaskUnion(masksUnion));
}
}
switch (masks.size()) {
case 0:
return null;
case 1:
return masks.get(0);
default:
return new MaskIntersection(masks);
}
}
public Mask catchSuggestion(String currentInput, List<Mask> masks, String nextInput, ParserContext context) throws InputParseException {
try {
return getBlockMaskComponent(masks, nextInput, context);
} catch (SuggestInputParseException e) {
e.prepend(currentInput.substring(0, currentInput.length() - nextInput.length()));
throw e;
}
}
private Mask getBlockMaskComponent(List<Mask> masks, String input, ParserContext context) throws InputParseException {
if (input.isEmpty()) return null;
Extent extent = Request.request().getExtent();
if (extent == null) extent = context.getExtent();
final char firstChar = input.charAt(0);
switch (firstChar) {
case '#':
int colon = input.indexOf(':');
String component = input;
if (colon != -1) {
component = component.substring(0, colon).toLowerCase();
String rest = input.substring(colon + 1);
Class<? extends CustomMask> customMask = customMasks.get(component);
if (customMask != null) {
try {
Constructor<? extends CustomMask> constructor = customMask.getDeclaredConstructor(List.class, String.class, ParserContext.class);
return constructor.newInstance(masks, rest, context);
} catch (Throwable e) {
throw new RuntimeException(e);
}
HashSet<BaseBlock> blocks = new HashSet<BaseBlock>();
List<Mask> intersection = new ArrayList<>();
List<Mask> union = 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;
Mask mask = null;
if (command.isEmpty()) {
mask = parseFromInput(StringMan.join(entry.getValue(), ','), context);
} if (dispatcher.get(command) == null) {
// Legacy patterns
char char0 = command.charAt(0);
boolean charMask = input.length() > 1 && input.charAt(1) != '[';
if (charMask && input.charAt(0) == '=') {
return parseFromInput(char0 + "[" + input.substring(1) + "]", context);
}
switch (component) {
case "#light":
case "#skylight":
case "#blocklight":
case "#emittedlight":
case "#opacity":
case "#brightness":
String[] split = rest.split(":");
if (split.length < 2) {
throw new SuggestInputParseException(input, component + ":<min>:<max>");
} else if (split.length > 2) {
masks.add(catchSuggestion(input, masks, StringMan.join(Arrays.copyOfRange(split, 2, split.length), ":"), context));
}
try {
int y1 = (int) Math.abs(Expression.compile(split[0]).evaluate());
int y2 = (int) Math.abs(Expression.compile(split[1]).evaluate());
switch (component) {
case "#light":
return new LightMask(extent, y1, y2);
case "#skylight":
return new SkyLightMask(extent, y1, y2);
case "#blocklight":
case "#emittedlight":
return new BlockLightMask(extent, y1, y2);
case "#opacity":
return new OpacityMask(extent, y1, y2);
case "#brightness":
return new BrightnessMask(extent, y1, y2);
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;
}
} catch (NumberFormatException | ExpressionException e) {
e.printStackTrace();
throw new SuggestInputParseException(input, component + ":<min>:<max>");
case '|':
case '~':
case '<':
case '>':
case '!':
input = input.substring(input.indexOf(char0) + 1);
mask = parseFromInput(char0 + "[" + input + "]", context);
if (actor != null) {
actor.print("&7Added clarifying bracket for: " + char0 + "&c[&7" + input + "&c]&7");
}
return mask;
}
case "#~":
case "#rel":
case "#relative":
case "#offset":
}
if (mask == null) {
try {
List<String> split3 = suggestRemaining(rest, "#offset", "<dx>", "<dy>", "<dz>", "<mask>");
int x = (int) Expression.compile(split3.get(0)).evaluate();
int y = (int) Expression.compile(split3.get(1)).evaluate();
int z = (int) Expression.compile(split3.get(2)).evaluate();
rest = StringMan.join(split3.subList(3, split3.size()), ":");
Mask mask = catchSuggestion(input, masks, rest, context);
return new OffsetMask(mask, new Vector(x, y, z));
} catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) {
throw new SuggestInputParseException(null, "#offset:<dx>:<dy>:<dz>:<mask>");
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");
}
}
}
Mask mask = catchSuggestion(input, masks, rest, context);
masks.add(mask);
} else {
Class<? extends CustomMask> customMask = customMasks.get(component);
if (customMask != null) {
try {
Constructor<? extends CustomMask> constructor = customMask.getDeclaredConstructor(List.class, String.class, ParserContext.class);
return constructor.newInstance(masks, "", context);
} catch (Throwable e) {
throw new RuntimeException(e);
}
List<String> args = entry.getValue();
if (!args.isEmpty()) {
command += " " + StringMan.join(args, " ");
}
mask = (Mask) dispatcher.call(command, locals, new String[0]);
}
switch (component.toLowerCase()) {
case "#haslight":
return new LightMask(extent, 1, Integer.MAX_VALUE);
case "#nolight":
return new LightMask(extent, 0, 0);
case "#existing":
return new ExistingBlockMask(extent);
case "#solid":
return new SolidBlockMask(extent);
case "#dregion":
case "#dselection":
case "#dsel":
return new RegionMask(new RequestSelection());
case "#selection":
case "#region":
case "#sel":
try {
return new RegionMask(context.requireSession().getSelection(context.requireWorld()).clone());
} catch (IncompleteRegionException e) {
throw new InputParseException("Please make a selection first.");
}
case "#xaxis":
return new XAxisMask();
case "#yaxis":
return new YAxisMask();
case "#zaxis":
return new ZAxisMask();
case "#id":
return new IdMask(extent);
case "#data":
return new DataMask(extent);
case "#iddata":
return new IdDataMask(extent);
case "#wall":
masks.add(new ExistingBlockMask(extent));
BlockMask matchAir = new BlockMask(extent, EditSession.nullBlock);
return new WallMask(extent, Arrays.asList(new BaseBlock(0)), 1, 8);
case "#surface":
masks.add(new ExistingBlockMask(extent));
return new AdjacentAnyMask(extent, Arrays.asList(new BaseBlock(0)));
default:
throw new SuggestInputParseException(input, HASHTAG_MASKS);
}
case '\\':
case '/': {
String[] split = input.substring(1).split(":");
if (split.length != 2) {
throw new SuggestInputParseException(input, "/<min-angle>:<max-angle>");
}
try {
double y1,y2;
boolean override;
if (split[1].endsWith("o")) {
override = true;
split[1] = split[1].substring(0, split[1].length() - 1);
} else {
override = false;
}
if (split[0].endsWith("d")) {
double y1d = Expression.compile(split[0].substring(0, split[0].length() - 1)).evaluate();
double y2d = Expression.compile(split[1].substring(0, split[1].length() - 1)).evaluate();
y1 = (Math.tan(y1d * (Math.PI / 180)));
y2 = (Math.tan(y2d * (Math.PI / 180)));
} else {
y1 = (Expression.compile(split[0]).evaluate());
y2 = (Expression.compile(split[1]).evaluate());
}
return new AngleMask(extent, y1, y2, override);
} catch (NumberFormatException | ExpressionException e) {
throw new SuggestInputParseException(input, "/<min-angle>:<max-angle>");
}
}
case '{': {
String[] split = input.substring(1).split(":");
if (split.length != 2) {
throw new SuggestInputParseException(input, "{<min-radius>:<max-radius>");
}
try {
int y1 = (int) Math.abs(Expression.compile(split[0]).evaluate());
int y2 = (int) Math.abs(Expression.compile(split[1]).evaluate());
return new RadiusMask(y1, y2);
} catch (NumberFormatException | ExpressionException e) {
throw new SuggestInputParseException(input, "{<min-radius>:<max-radius>");
}
}
case '|':
case '~': {
String[] split = input.substring(1).split("=");
ParserContext tempContext = new ParserContext(context);
tempContext.setRestricted(false);
tempContext.setPreferringWildcard(true);
try {
int requiredMin = 1;
int requiredMax = 8;
if (split.length == 2) {
String[] split2 = split[1].split("[:|,]");
requiredMin = (int) Math.abs(Expression.compile(split2[0]).evaluate());
if (split2.length >= 2) {
requiredMax = (int) Math.abs(Expression.compile(split2[1]).evaluate());
}
}
if (firstChar == '~') {
if (requiredMax >= 8 && requiredMin == 1) {
return new AdjacentAnyMask(extent, worldEdit.getBlockFactory().parseFromListInput(split[0], tempContext));
}
return new AdjacentMask(extent, worldEdit.getBlockFactory().parseFromListInput(split[0], tempContext), requiredMin, requiredMax);
} else {
return new WallMask(extent, worldEdit.getBlockFactory().parseFromListInput(input.substring(1), tempContext), requiredMin, requiredMax);
}
} catch (NumberFormatException | ExpressionException e) {
throw new SuggestInputParseException(input, "~<blocks>=<min>:<max>");
}
}
case '>':
case '<':
Mask submask;
if (input.length() > 1) {
submask = getBlockMaskComponent(masks, input.substring(1), context);
if (pe.and) { // &
intersection.add(mask);
} else {
submask = new ExistingBlockMask(extent);
}
OffsetMask offsetMask = new OffsetMask(submask, new Vector(0, firstChar == '>' ? -1 : 1, 0));
return new MaskIntersection(offsetMask, Masks.negate(submask));
case '$':
Set<BaseBiome> biomes = new HashSet<BaseBiome>();
String[] biomesList = input.substring(1).split(",");
BiomeRegistry biomeRegistry = context.requireWorld().getWorldData().getBiomeRegistry();
List<BaseBiome> knownBiomes = biomeRegistry.getBiomes();
for (String biomeName : biomesList) {
BaseBiome biome = Biomes.findBiomeByName(knownBiomes, biomeName, biomeRegistry);
if (biome == null) {
throw new SuggestInputParseException(input, "$<biome>");
if (!intersection.isEmpty()) {
if (intersection.size() == 1) {
throw new InputParseException("Error, floating &");
}
union.add(new MaskIntersection(intersection));
intersection.clear();
}
biomes.add(biome);
union.add(mask);
}
return Masks.asMask(new BiomeMask2D(context.requireExtent(), biomes));
case '%':
try {
double i = Math.abs(Expression.compile(input.substring(1)).evaluate());
return new NoiseFilter(new RandomNoise(), (i) / 100);
} catch (NumberFormatException | ExpressionException e) {
throw new SuggestInputParseException(input, "%<percent>");
}
case '=':
try {
Expression exp = Expression.compile(input.substring(1), "x", "y", "z");
WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment(
Request.request().getEditSession (), Vector.ONE, Vector.ZERO);
exp.setEnvironment(env);
return new ExpressionMask(exp);
} catch (ExpressionException e) {
throw new SuggestInputParseException(input, "=<expression>");
}
case '!':
if (input.length() > 1) {
return Masks.negate(getBlockMaskComponent(masks, input.substring(1), context));
}
throw new SuggestInputParseException(input, "!<mask>");
default:
ParserContext tempContext = new ParserContext(context);
tempContext.setRestricted(false);
tempContext.setPreferringWildcard(true);
return new BlockMask(extent, worldEdit.getBlockFactory().parseFromListInput(input, tempContext));
}
} catch (Throwable e) {
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 &");
}
union.add(new MaskIntersection(intersection));
intersection.clear();
}
if (union.isEmpty()) {
return null;
} else if (union.size() == 1) {
return union.get(0);
} else {
return new MaskUnion(union);
}
}
public static Class<?> inject() {
return DefaultMaskParser.class;
}
}
}

View File

@ -0,0 +1,151 @@
package com.sk89q.worldedit.extension.factory;
import com.boydti.fawe.command.FaweParser;
import com.boydti.fawe.object.extent.MultiTransform;
import com.boydti.fawe.object.extent.RandomTransform;
import com.boydti.fawe.object.extent.ResettableExtent;
import com.boydti.fawe.object.random.TrueRandom;
import com.boydti.fawe.util.StringMan;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.TransformCommands;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.NoMatchException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Actor;
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.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.regex.Pattern;
public class DefaultTransformParser extends FaweParser<ResettableExtent> {
private final Pattern INTERSECTION_PATTERN = Pattern.compile("[&|;]+(?![^\\[]*\\])");
private final Dispatcher dispatcher;
public DefaultTransformParser(WorldEdit worldEdit) {
super(worldEdit);
this.dispatcher = new SimpleDispatcher();
this.register(new TransformCommands(worldEdit));
}
public Dispatcher getDispatcher() {
return dispatcher;
}
public void register(Object clazz) {
ParametricBuilder builder = new ParametricBuilder();
builder.setAuthorizer(new ActorAuthorizer());
builder.addBinding(new WorldEditBinding(worldEdit));
builder.registerMethodsAsCommands(dispatcher, clazz);
}
@Override
public ResettableExtent parseFromInput(String input, ParserContext context) throws InputParseException {
if (input.isEmpty()) return null;
List<Double> unionChances = new ArrayList<>();
List<Double> intersectionChances = new ArrayList<>();
List<ResettableExtent> intersection = new ArrayList<>();
List<ResettableExtent> union = 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;
ResettableExtent transform = null;
double chance = 1;
if (command.isEmpty()) {
transform = parseFromInput(StringMan.join(entry.getValue(), ','), context);
} if (dispatcher.get(command) == null) {
// Legacy syntax
int percentIndex = command.indexOf('%');
if (percentIndex != -1) { // Legacy percent pattern
chance = Expression.compile(command.substring(0, percentIndex)).evaluate();
command = command.substring(percentIndex + 1);
if (!entry.getValue().isEmpty()) {
if (!command.isEmpty()) command += " ";
command += StringMan.join(entry.getValue(), " ");
}
transform = parseFromInput(command, context);
} else {
throw new NoMatchException("See: //transforms");
}
} else {
List<String> args = entry.getValue();
if (!args.isEmpty()) {
command += " " + StringMan.join(args, " ");
}
transform = (ResettableExtent) dispatcher.call(command, locals, new String[0]);
}
if (pe.and) { // &
intersectionChances.add(chance);
intersection.add(transform);
} else {
if (!intersection.isEmpty()) {
if (intersection.size() == 1) {
throw new InputParseException("Error, floating &");
}
MultiTransform multi = new MultiTransform();
double total = 0;
for (int i = 0; i < intersection.size(); i++) {
Double value = intersectionChances.get(i);
total += value;
multi.add(intersection.get(i), value);
}
union.add(multi);
unionChances.add(total);
intersection.clear();
intersectionChances.clear();
}
unionChances.add(chance);
union.add(transform);
}
}
} catch (Throwable e) {
throw new InputParseException(e.getMessage(), e);
}
if (!intersection.isEmpty()) {
if (intersection.size() == 1) {
throw new InputParseException("Error, floating &");
}
MultiTransform multi = new MultiTransform();
double total = 0;
for (int i = 0; i < intersection.size(); i++) {
Double value = intersectionChances.get(i);
total += value;
multi.add(intersection.get(i), value);
}
union.add(multi);
unionChances.add(total);
intersection.clear();
intersectionChances.clear();
}
if (union.isEmpty()) {
throw new NoMatchException("See: //transforms");
} else if (union.size() == 1) {
return union.get(0);
} else {
RandomTransform random = new RandomTransform(new TrueRandom());
for (int i = 0; i < union.size(); i++) {
random.add(union.get(i), unionChances.get(i));
}
return random;
}
}
public static Class<?> inject() {
return HashTagPatternParser.class;
}
}

View File

@ -1,453 +1,135 @@
package com.sk89q.worldedit.extension.factory;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.command.FaweParser;
import com.boydti.fawe.command.SuggestInputParseException;
import com.boydti.fawe.object.DataAngleMask;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.pattern.AngleColorPattern;
import com.boydti.fawe.object.pattern.AverageColorPattern;
import com.boydti.fawe.object.pattern.BiomePattern;
import com.boydti.fawe.object.pattern.BufferedPattern;
import com.boydti.fawe.object.pattern.DataPattern;
import com.boydti.fawe.object.pattern.DesaturatePattern;
import com.boydti.fawe.object.pattern.ExistingPattern;
import com.boydti.fawe.object.pattern.ExpressionPattern;
import com.boydti.fawe.object.pattern.FullClipboardPattern;
import com.boydti.fawe.object.pattern.IdDataMaskPattern;
import com.boydti.fawe.object.pattern.IdPattern;
import com.boydti.fawe.object.pattern.Linear3DBlockPattern;
import com.boydti.fawe.object.pattern.LinearBlockPattern;
import com.boydti.fawe.object.pattern.MaskedPattern;
import com.boydti.fawe.object.pattern.NoXPattern;
import com.boydti.fawe.object.pattern.NoYPattern;
import com.boydti.fawe.object.pattern.NoZPattern;
import com.boydti.fawe.object.pattern.OffsetPattern;
import com.boydti.fawe.object.pattern.PatternExtent;
import com.boydti.fawe.object.pattern.RandomFullClipboardPattern;
import com.boydti.fawe.object.pattern.RandomOffsetPattern;
import com.boydti.fawe.object.pattern.RelativePattern;
import com.boydti.fawe.object.pattern.SaturatePattern;
import com.boydti.fawe.object.pattern.ShadePattern;
import com.boydti.fawe.object.pattern.SolidRandomOffsetPattern;
import com.boydti.fawe.object.pattern.SurfaceRandomOffsetPattern;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.object.random.TrueRandom;
import com.boydti.fawe.util.StringMan;
import com.boydti.fawe.util.TextureUtil;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.EmptyClipboardException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.command.PatternCommands;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.NoMatchException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.ClipboardPattern;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.function.pattern.Pattern;
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.regions.shape.WorldEditExpressionEnvironment;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.biome.Biomes;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import com.sk89q.worldedit.world.registry.BundledBlockData;
import java.io.IOException;
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 javafx.scene.paint.Color;
import java.util.Map;
public class HashTagPatternParser extends FaweParser<Pattern> {
public static final String[] EXPRESSION_PATTERN = new String[] { "=<expression>" };
public static final String[] BLOCK_PATTERN = new String[] { "<block>" };
public static final String[] SIMPLE_PATTERNS = new String[] {
"#existing", "#fullcopy", "#clipboard",
};
public static final String[] DELEGATE_PATTERNS = new String[] {
"#linear3d:", "#linear:", "#spread:", "#solidspread:", "#surfacespread:", "#offset:", "#mask:", "#!x:", "#!y:", "#!z:", "#relative:", "#id:", "#data:",
};
public static final String[] MISC_PATTERNS = new String[] {
"hand", "pos1",
};
public static final String[] ALL_PATTERNS = MainUtil.joinArrayGeneric(BLOCK_PATTERN, SIMPLE_PATTERNS, DELEGATE_PATTERNS, MISC_PATTERNS);
private final Dispatcher dispatcher;
public HashTagPatternParser(WorldEdit worldEdit) {
super(worldEdit);
this.dispatcher = new SimpleDispatcher();
this.register(new PatternCommands(worldEdit));
}
public Dispatcher getDispatcher() {
return dispatcher;
}
public void register(Object clazz) {
ParametricBuilder builder = new ParametricBuilder();
builder.setAuthorizer(new ActorAuthorizer());
builder.addBinding(new WorldEditBinding(worldEdit));
builder.registerMethodsAsCommands(dispatcher, clazz);
}
@Override
public Pattern parseFromInput(String input, ParserContext context) throws InputParseException {
if (input.isEmpty()) {
throw new SuggestInputParseException(input, ALL_PATTERNS);
if (input.isEmpty()) return null;
List<Double> chances = new ArrayList<>();
List<Pattern> patterns = new ArrayList<>();
final CommandLocals locals = new CommandLocals();
Actor actor = context != null ? context.getActor() : null;
if (actor != null) {
locals.put(Actor.class, actor);
}
List<String> items = StringMan.split(input, ',');
if (items.size() == 1) {
return parseSinglePatternFromInput(items.get(0), context);
}
RandomPattern randomPattern = new RandomPattern();
try {
for (String token : items) {
Pattern pattern;
double chance;
// Parse special percentage syntax
if (token.matches("[0-9]+(\\.[0-9]*)?%.*")) {
String[] p = token.split("%");
if (p.length < 2) {
throw new InputParseException("Missing the pattern after the % symbol for '" + input + "'");
} else {
chance = Expression.compile(p[0]).evaluate();
pattern = catchSuggestion(input, p[1], context);
}
for (Map.Entry<ParseEntry, List<String>> entry : parse(input)) {
ParseEntry pe = entry.getKey();
String command = pe.input;
Pattern pattern = null;
double chance = 1;
if (command.isEmpty()) {
pattern = parseFromInput(StringMan.join(entry.getValue(), ','), context);
} else {
chance = 1;
pattern = catchSuggestion(input, token, context);
}
randomPattern.add(pattern, chance);
}
} catch (NumberFormatException | ExpressionException e) {
throw new InputParseException("Invalid, see: https://github.com/boy0001/FastAsyncWorldedit/wiki/WorldEdit-and-FAWE-patterns");
}
return randomPattern;
}
public Pattern parseSinglePatternFromInput(String input, ParserContext context) throws InputParseException {
if (input.isEmpty()) {
throw new SuggestInputParseException(input, ALL_PATTERNS);
}
switch (input.toLowerCase().charAt(0)) {
case '#': {
String[] split2 = input.split(":");
String rest = split2.length > 1 ? input.substring(split2[0].length() + 1) : "";
String arg = split2[0].toLowerCase();
switch (arg) {
case "#*":
case "#existing": {
return new ExistingPattern(Request.request().getExtent());
}
case "#clipboard":
case "#copy": {
LocalSession session = context.requireSession();
if (session != null) {
try {
ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard();
return new ClipboardPattern(clipboard);
} catch (EmptyClipboardException e) {
throw new InputParseException("To use #clipboard, please first copy something to your clipboard");
}
} else {
throw new InputParseException("No session is available, so no clipboard is available");
if (dispatcher.get(command) == null) {
// Legacy patterns
char char0 = command.charAt(0);
boolean charMask = input.length() > 1 && input.charAt(1) != '[';
if (charMask && input.charAt(0) == '=') {
return parseFromInput(char0 + "[" + input.substring(1) + "]", context);
}
}
case "#color": {
if (split2.length > 1) {
Color color = Color.web(split2[1]);
java.awt.Color awtColor = new java.awt.Color((float) color.getRed(), (float) color.getGreen(), (float) color.getBlue(), (float) color.getOpacity());
BaseBlock block = Fawe.get().getTextureUtil().getNearestBlock(awtColor.getRGB());
return new BlockPattern(block);
} else {
throw new InputParseException("#color:<hex>");
}
}
case "#anglecolor": {
TextureUtil util = Fawe.get().getCachedTextureUtil(split2.length < 2 ? true : Boolean.parseBoolean(split2[1]), 0, split2.length < 3 ? 100 : Integer.parseInt(split2[2]));
return new AngleColorPattern(util, Request.request().getExtent());
}
case "#angledata": {
return new DataAngleMask(Request.request().getExtent());
}
case "#saturate":
case "#averagecolor": {
try {
TextureUtil util = Fawe.get().getCachedTextureUtil(split2.length < 3 ? true : Boolean.parseBoolean(split2[2]), 0, split2.length < 4 ? 100 : Integer.parseInt(split2[3]));
Color color = Color.web(split2[1]);
java.awt.Color awtColor = new java.awt.Color((float) color.getRed(), (float) color.getGreen(), (float) color.getBlue(), (float) color.getOpacity());
if (arg.equals("#saturate"))
return new SaturatePattern(Request.request().getExtent(), util, awtColor.getRGB());
else return new AverageColorPattern(Request.request().getExtent(), util, awtColor.getRGB());
} catch (NumberFormatException | IndexOutOfBoundsException e) {
throw new SuggestInputParseException(null, "#" + arg + "[:<color>:<randomize=true>:<complexity=100>]");
}
}
case "#desaturate": {
try {
TextureUtil util = Fawe.get().getCachedTextureUtil(split2.length < 3 ? true : Boolean.parseBoolean(split2[2]), 0, split2.length < 4 ? 100 : Integer.parseInt(split2[3]));
double chance = split2.length < 2 ? 100 : Expression.compile(split2[1]).evaluate();
return new DesaturatePattern(Request.request().getExtent(), util, chance / 100d);
} catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) {
throw new SuggestInputParseException(null, "#desaturate[:<percent=100>:<randomize=true>:<complexity=100>]");
}
}
case "#lighten":
case "#darken": {
TextureUtil util = Fawe.get().getCachedTextureUtil(split2.length < 2 ? true : Boolean.parseBoolean(split2[1]), 0, split2.length < 3 ? 100 : Integer.parseInt(split2[2]));
return new ShadePattern(Request.request().getExtent(), util, arg.equals("#darken"));
}
case "#fullcopy": {
LocalSession session = context.requireSession();
if (session != null) {
try {
if (split2.length > 1) {
String location = split2[1];
try {
ClipboardHolder[] clipboards;
switch (location.toLowerCase()) {
case "#copy":
case "#clipboard":
ClipboardHolder clipboard = session.getExistingClipboard();
if (clipboard == null) {
throw new InputParseException("To use #fullcopy, please first copy something to your clipboard");
}
clipboards = new ClipboardHolder[] {clipboard};
break;
default:
clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(context.getActor(), context.requireWorld().getWorldData(), location, true);
break;
}
if (clipboards == null) {
throw new InputParseException("#fullcopy:<source>");
}
boolean randomRotate = split2.length >= 3 && split2[2].equalsIgnoreCase("true");
boolean randomFlip = split2.length >= 4 && split2[3].equalsIgnoreCase("true");
return new RandomFullClipboardPattern(Request.request().getExtent(), context.requireWorld().getWorldData(), clipboards, randomRotate, randomFlip);
} catch (IOException e) {
throw new RuntimeException(e);
if (charMask) {
switch (char0) {
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(":", "][");
}
pattern = parseFromInput(char0 + "[" + value + "]", context);
break;
}
ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard();
return new FullClipboardPattern(Request.request().getExtent(), clipboard);
} catch (EmptyClipboardException e) {
throw new InputParseException("To use #fullcopy, please first copy something to your clipboard");
}
} else {
throw new InputParseException("No session is available, so no clipboard is available");
}
}
case "#buffer": {
return new BufferedPattern(FawePlayer.wrap(context.requireActor()), catchSuggestion(input, rest, context));
}
case "#iddatamask": {
String[] split = rest.split(":", 1);
if (split.length != 2) {
throw new InputParseException("#iddatamask:<mask>:<pattern>");
}
int mask = Integer.parseInt(split[0]);
return new IdDataMaskPattern(Request.request().getExtent(), catchSuggestion(input, split[1], context), mask);
}
case "#id": {
return new IdPattern(Request.request().getExtent(), catchSuggestion(input, rest, context));
}
case "#data": {
return new DataPattern(Request.request().getExtent(), catchSuggestion(input, rest, context));
}
case "#biome": {
if (MathMan.isInteger(rest)) {
return new BiomePattern(Request.request().getExtent(), new BaseBiome(Integer.parseInt(rest)));
}
World world = context.requireWorld();
BiomeRegistry biomeRegistry = world.getWorldData().getBiomeRegistry();
List<BaseBiome> knownBiomes = biomeRegistry.getBiomes();
BaseBiome biome = Biomes.findBiomeByName(knownBiomes, rest, biomeRegistry);
return new BiomePattern(Request.request().getExtent(), biome);
}
case "#~":
case "#r":
case "#relative":
case "#rel": {
return new RelativePattern(catchSuggestion(input, rest, context));
}
case "#!x":
case "#nx":
case "#nox": {
return new NoXPattern(catchSuggestion(input, rest, context));
}
case "#!y":
case "#ny":
case "#noy": {
return new NoYPattern(catchSuggestion(input, rest, context));
}
case "#!z":
case "#nz":
case "#noz": {
return new NoZPattern(catchSuggestion(input, rest, context));
}
case "#mask": {
List<String> split3 = suggestRemaining(rest, "#mask", "<mask>", "<pattern-if>", "<pattern-else>");
Pattern primary = catchSuggestion(input, split3.get(1), context);
Pattern secondary = catchSuggestion(input, split3.get(2), context);
PatternExtent extent = new PatternExtent(primary);
Request request = Request.request();
request.setExtent(extent);
request.setSession(context.getSession());
request.setWorld(context.getWorld());
context.setExtent(extent);
MaskFactory factory = worldEdit.getMaskFactory();
Mask mask = factory.parseFromInput(split3.get(0), context);
if (mask == null | primary == null || secondary == null) {
throw new SuggestInputParseException(null, "#mask:<mask>:<pattern-if>:<pattern-else>");
}
return new MaskedPattern(mask, extent, secondary);
}
case "#offset":
try {
List<String> split3 = suggestRemaining(rest, "#offset", "<dx>", "<dy>", "<dz>", "<pattern>");
int x = (int) Expression.compile(split3.get(0)).evaluate();
int y = (int) Expression.compile(split3.get(1)).evaluate();
int z = (int) Expression.compile(split3.get(2)).evaluate();
rest = StringMan.join(split3.subList(3, split3.size()), ":");
Pattern pattern = catchSuggestion(input, rest, context);
return new OffsetPattern(pattern, x, y, z);
} catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) {
throw new SuggestInputParseException(null, "#offset:<dx>:<dy>:<dz>:<pattern>");
}
case "#surfacespread": {
try {
List<String> split3 = suggestRemaining(rest, "#surfacespread", "<distance>", "<pattern>");
int dist = (int) Math.abs(Expression.compile(split3.get(0)).evaluate());
rest = StringMan.join(split3.subList(1, split3.size()), ":");
Pattern pattern = catchSuggestion(input, rest, context);
return new SurfaceRandomOffsetPattern(Request.request().getExtent(), pattern, dist);
} catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) {
throw new SuggestInputParseException(null, "#surfacespread:<distance>:<pattern>");
}
}
case "#solidspread": {
try {
List<String> split3 = suggestRemaining(rest, "#solidspread", "<dx>", "<dy>", "<dz>", "<pattern>");
int x = (int) Math.abs(Expression.compile(split3.get(0)).evaluate());
int y = (int) Math.abs(Expression.compile(split3.get(1)).evaluate());
int z = (int) Math.abs(Expression.compile(split3.get(2)).evaluate());
rest = StringMan.join(split3.subList(3, split3.size()), ":");
Pattern pattern = catchSuggestion(input, rest, context);
return new SolidRandomOffsetPattern(pattern, x, y, z);
} catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) {
throw new SuggestInputParseException(null, "#solidspread:<dx>:<dy>:<dz>:<pattern>");
}
}
case "#randomoffset":
case "#spread": {
try {
List<String> split3 = suggestRemaining(rest, "#spread", "<dx>", "<dy>", "<dz>", "<pattern>");
int x = (int) Math.abs(Expression.compile(split3.get(0)).evaluate());
int y = (int) Math.abs(Expression.compile(split3.get(1)).evaluate());
int z = (int) Math.abs(Expression.compile(split3.get(2)).evaluate());
rest = StringMan.join(split3.subList(3, split3.size()), ":");
Pattern pattern = catchSuggestion(input, rest, context);
return new RandomOffsetPattern(pattern, x, y, z);
} catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) {
throw new SuggestInputParseException(null, "#spread:<dx>:<dy>:<dz>:<pattern>");
}
}
case "#l":
case "#linear": {
if (rest.startsWith("\"") && rest.endsWith("\"")) {
rest = rest.substring(1, rest.length() - 1);
}
ArrayList<Pattern> patterns = new ArrayList<>();
for (String token : StringMan.split(rest, ',')) {
patterns.add(catchSuggestion(input, token, context));
}
if (patterns.isEmpty()) {
throw new SuggestInputParseException(null, ALL_PATTERNS).prepend(input);
}
return new LinearBlockPattern(patterns.toArray(new Pattern[patterns.size()]));
}
case "#l3d":
case "#linear3d": {
if (rest.startsWith("\"") && rest.endsWith("\"")) {
rest = rest.substring(1, rest.length() - 1);
}
ArrayList<Pattern> patterns = new ArrayList<>();
for (String token : StringMan.split(rest, ',')) {
patterns.add(catchSuggestion(input, token, context));
}
if (patterns.isEmpty()) {
throw new SuggestInputParseException(null, ALL_PATTERNS).prepend(input);
}
return new Linear3DBlockPattern(patterns.toArray(new Pattern[patterns.size()]));
}
default:
throw new SuggestInputParseException(input, MainUtil.joinArrayGeneric(SIMPLE_PATTERNS, DELEGATE_PATTERNS));
}
}
case '=': {
try {
Expression exp = Expression.compile(input.substring(1), "x", "y", "z");
EditSession editSession = Request.request().getEditSession();
if (editSession == null) {
editSession = context.requireSession().createEditSession((Player) context.getActor());
}
WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment(
editSession, Vector.ONE, Vector.ZERO);
exp.setEnvironment(env);
return new ExpressionPattern(exp);
} catch (ExpressionException e) {
throw new SuggestInputParseException("=http://wiki.sk89q.com/wiki/WorldEdit/Expression_syntax");
}
}
default:
switch (input) {
case "<dx>":
case "<dy>":
case "<dz>":
throw new SuggestInputParseException(input, "0", "-3", "7");
case "<pattern>":
case "<pattern-if>":
case "<pattern-else>":
throw new SuggestInputParseException(input, ALL_PATTERNS);
case "<block>":
throw new SuggestInputParseException(input, BundledBlockData.getInstance().getBlockNames());
}
List<String> items = StringMan.split(input, ',');
if (items.size() == 1) {
return new BlockPattern(worldEdit.getBlockFactory().parseFromInput(items.get(0), context));
}
BlockFactory blockRegistry = worldEdit.getBlockFactory();
RandomPattern randomPattern = new RandomPattern();
try {
for (String token : items) {
Pattern pattern;
double chance;
// Parse special percentage syntax
if (token.matches("[0-9]+(\\.[0-9]*)?%.*")) {
String[] p = token.split("%");
if (p.length < 2) {
throw new InputParseException("Missing the pattern after the % symbol for '" + input + "'");
} else {
chance = Expression.compile(p[0]).evaluate();
pattern = catchSuggestion(input, p[1], context);
if (pattern == null) {
int percentIndex = command.indexOf('%');
if (percentIndex != -1) { // Legacy percent pattern
chance = Expression.compile(command.substring(0, percentIndex)).evaluate();
command = command.substring(percentIndex + 1);
if (!entry.getValue().isEmpty()) {
if (!command.isEmpty()) command += " ";
command += StringMan.join(entry.getValue(), " ");
}
pattern = parseFromInput(command, context);
} else { // legacy block pattern
try {
pattern = worldEdit.getBlockFactory().parseFromInput(command, context);
} catch (NoMatchException e) {
throw new NoMatchException(e.getMessage() + " See: //patterns");
}
}
} else {
chance = 1;
pattern = catchSuggestion(input, token, context);
}
randomPattern.add(pattern, chance);
} else {
List<String> args = entry.getValue();
if (!args.isEmpty()) {
command += " " + StringMan.join(args, " ");
}
pattern = (Pattern) dispatcher.call(command, locals, new String[0]);
}
} catch (NumberFormatException | ExpressionException e) {
throw new InputParseException("Invalid, see: https://github.com/boy0001/FastAsyncWorldedit/wiki/WorldEdit-and-FAWE-patterns");
}
return randomPattern;
patterns.add(pattern);
chances.add(chance);
}
} catch (CommandException | ExpressionException e) {
throw new RuntimeException(e);
}
if (patterns.isEmpty()) {
return null;
} else if (patterns.size() == 1) {
return patterns.get(0);
} else {
RandomPattern random = new RandomPattern(new TrueRandom());
for (int i = 0; i < patterns.size(); i++) {
random.add(patterns.get(i), chances.get(i));
}
return random;
}
}
public static Class<?> inject() {
return HashTagPatternParser.class;
}
}
}

View File

@ -375,8 +375,11 @@ 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 {
dispatcher.call(Joiner.on(" ").join(split), locals, new String[0]);
Object result = dispatcher.call(Joiner.on(" ").join(split), locals, new String[0]);
} catch (Throwable t) {
while (t.getCause() != null) {
t = t.getCause();
}
// Use the exception converter to convert the exception if any of its causes
// can be converted, otherwise throw the original exception
Throwable next = t;
@ -391,7 +394,7 @@ public final class CommandManager {
BBC.NO_PERM.send(finalActor, StringMan.join(failedPermissions, " "));
} catch (InvalidUsageException e) {
if (e.isFullHelpSuggested()) {
finalActor.print(BBC.getPrefix() + ColorCodeBuilder.asColorCodes(new CommandUsageBox(e.getCommand(), e.getCommandUsed("/", ""), locals)));
finalActor.printRaw(BBC.getPrefix() + ColorCodeBuilder.asColorCodes(new CommandUsageBox(e.getCommand(), e.getCommandUsed("", ""), locals)));
String message = e.getMessage();
if (message != null) {
finalActor.printError(message);
@ -414,7 +417,7 @@ public final class CommandManager {
finalActor.printRaw(t.getClass().getName() + ": " + t.getMessage());
log.log(Level.SEVERE, "An unexpected error occurred while handling a FAWE command", t);
}
} catch (CommandException e) {
} catch (Throwable e) {
String message = e.getMessage();
if (message != null) {
finalActor.printError(e.getMessage());

View File

@ -43,7 +43,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* A base class for {@link Extent}s that merely passes extents onto another.
*/
public abstract class AbstractDelegateExtent implements LightingExtent {
public class AbstractDelegateExtent implements LightingExtent {
private final Extent extent;
@ -52,7 +52,7 @@ public abstract class AbstractDelegateExtent implements LightingExtent {
*
* @param extent the extent
*/
protected AbstractDelegateExtent(Extent extent) {
public AbstractDelegateExtent(Extent extent) {
checkNotNull(extent);
this.extent = extent;
}

View File

@ -1,6 +1,8 @@
package com.sk89q.worldedit.function.pattern;
import com.boydti.fawe.object.collection.RandomCollection;
import com.boydti.fawe.object.random.SimpleRandom;
import com.boydti.fawe.object.random.TrueRandom;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
@ -18,10 +20,19 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public class RandomPattern extends AbstractPattern {
private final SimpleRandom random;
private Map<Pattern, Double> weights = new HashMap<>();
private RandomCollection<Pattern> collection;
private LinkedHashSet<Pattern> patterns = new LinkedHashSet<>();
public RandomPattern() {
this(new TrueRandom());
}
public RandomPattern(SimpleRandom random) {
this.random = random;
}
/**
* Add a pattern to the weight list of patterns.
*
@ -34,7 +45,7 @@ public class RandomPattern extends AbstractPattern {
public void add(Pattern pattern, double chance) {
checkNotNull(pattern);
weights.put(pattern, chance);
collection = RandomCollection.of(weights);
collection = RandomCollection.of(weights, random);
this.patterns.add(pattern);
}
@ -42,32 +53,18 @@ public class RandomPattern extends AbstractPattern {
return patterns;
}
public RandomCollection<Pattern> getCollection() {
return collection;
}
@Override
public BaseBlock apply(Vector position) {
return collection.next().apply(position);
public BaseBlock apply(Vector get) {
return collection.next(get.getBlockX(), get.getBlockY(), get.getBlockZ()).apply(get);
}
@Override
public boolean apply(Extent extent, Vector set, Vector get) throws WorldEditException {
return collection.next().apply(extent, set, get);
}
private static class Chance {
private Pattern pattern;
private double chance;
private Chance(Pattern pattern, double chance) {
this.pattern = pattern;
this.chance = chance;
}
public Pattern getPattern() {
return pattern;
}
public double getChance() {
return chance;
}
return collection.next(get.getBlockX(), get.getBlockY(), get.getBlockZ()).apply(extent, set, get);
}
public static Class<?> inject() {

View File

@ -26,6 +26,7 @@ import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.command.MethodCommands;
import com.sk89q.worldedit.util.auth.Authorizer;
import com.sk89q.worldedit.util.auth.NullAuthorizer;
import com.sk89q.worldedit.util.command.CommandCallable;
@ -156,8 +157,11 @@ public class ParametricBuilder {
for (Method method : object.getClass().getDeclaredMethods()) {
Command definition = method.getAnnotation(Command.class);
if (definition != null) {
definition = Commands.translate(definition);
definition = Commands.translate(method.getDeclaringClass(), definition);
CommandCallable callable = build(object, method, definition);
if (object instanceof MethodCommands) {
((MethodCommands) object).register(method, callable, dispatcher);
}
dispatcher.registerCommand(callable, definition.aliases());
}
}

View File

@ -241,21 +241,22 @@ public class ParametricCallable implements CommandCallable {
}
// Execute!
method.invoke(object, args);
Object result = method.invoke(object, args);
// postInvoke handlers
for (InvokeHandler handler : handlers) {
handler.postInvoke(handler, method, parameters, args, context);
}
return result;
} catch (MissingParameterException e) {
throw new InvalidUsageException("Too few parameters!", this);
throw new InvalidUsageException("Too few parameters!", this, true);
} catch (UnconsumedParameterException e) {
throw new InvalidUsageException("Too many parameters! Unused parameters: " + e.getUnconsumed(), this);
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);
throw new InvalidUsageException("For parameter '" + name + "': " + e.getMessage(), this, true);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof CommandException) {
throw (CommandException) e.getCause();
@ -264,8 +265,6 @@ public class ParametricCallable implements CommandCallable {
} catch (Throwable t) {
throw new WrappedCommandException(t);
}
return true;
}
public Object getObject() {