Various command (use es6 if java9 + nashorn)

This commit is contained in:
Jesse Boyd 2018-08-22 03:22:37 +10:00
parent 43531a0da0
commit c55353e5b1
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
59 changed files with 1799 additions and 612 deletions

View File

@ -68,6 +68,8 @@ subprojects {
version = rootProject.version
group = 'com.boydti.fawe'
compileJava { options.compilerArgs += ["-parameters"] }
repositories {
mavenCentral()
maven { url "http://ci.athion.net/job/FAWE-WorldGuard-1.13/ws/mvn/" }

View File

@ -3,10 +3,7 @@ package com.boydti.fawe.bukkit;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.IFawe;
import com.boydti.fawe.bukkit.chat.BukkitChatManager;
import com.boydti.fawe.bukkit.listener.BrushListener;
import com.boydti.fawe.bukkit.listener.BukkitImageListener;
import com.boydti.fawe.bukkit.listener.CFIPacketListener;
import com.boydti.fawe.bukkit.listener.RenderListener;
import com.boydti.fawe.bukkit.listener.*;
import com.boydti.fawe.bukkit.regions.*;
import com.boydti.fawe.bukkit.util.BukkitReflectionUtils;
import com.boydti.fawe.bukkit.util.BukkitTaskMan;
@ -32,7 +29,6 @@ import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.cui.CUI;
import com.boydti.fawe.util.image.ImageViewer;
import com.boydti.fawe.util.metrics.BStats;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.world.World;
import org.bukkit.Bukkit;
@ -123,6 +119,13 @@ public class FaweBukkit implements IFawe, Listener {
} catch (ClassNotFoundException e) {
new ChunkListener_9();
}
try {
new AsyncTabCompleteListener(WorldEditPlugin.getInstance());
} catch (Throwable ignore)
{
Bukkit.getPluginManager().registerEvents(new SyncTabCompleteListener(WorldEditPlugin.getInstance()), plugin);
}
}
});
}

View File

@ -0,0 +1,39 @@
package com.boydti.fawe.bukkit.listener;
import com.boydti.fawe.object.string.MutableCharSequence;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
import com.sk89q.worldedit.extension.platform.CommandManager;
import com.sk89q.worldedit.util.command.CommandMapping;
import com.sk89q.worldedit.util.command.Dispatcher;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Listener;
import java.util.List;
public class ATabCompleteListener implements Listener {
private final WorldEditPlugin worldEdit;
public ATabCompleteListener(WorldEditPlugin worldEdit) {
this.worldEdit = worldEdit;
}
public List<String> onTab(String buffer, CommandSender sender) {
int firstSpace = buffer.indexOf(' ');
if (firstSpace == -1) return null;
MutableCharSequence mBuffer = MutableCharSequence.getTemporal();
mBuffer.setString(buffer);
mBuffer.setSubstring(0, firstSpace);
String label = buffer.substring(mBuffer.indexOf(':') + 1, firstSpace);
Dispatcher dispatcher = CommandManager.getInstance().getDispatcher();
CommandMapping weCommand = dispatcher.get(label);
if (weCommand != null) {
CommandSuggestionEvent event = new CommandSuggestionEvent(worldEdit.wrapCommandSender(sender), buffer);
worldEdit.getWorldEdit().getEventBus().post(event);
List<String> suggestions = event.getSuggestions();
if (suggestions != null) {
return suggestions;
}
}
return null;
}
}

View File

@ -0,0 +1,48 @@
package com.boydti.fawe.bukkit.listener;
import com.boydti.fawe.util.TaskManager;
import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.event.EventHandler;
import org.bukkit.event.server.TabCompleteEvent;
import java.util.Collections;
import java.util.List;
public class AsyncTabCompleteListener extends ATabCompleteListener {
public AsyncTabCompleteListener(WorldEditPlugin worldEdit) {
super(worldEdit);
Bukkit.getPluginManager().registerEvents(this, worldEdit);
}
@EventHandler
public void onTabComplete(AsyncTabCompleteEvent event) {
if (event.isCommand()) {
List<String> result = this.onTab(event.getBuffer(), event.getSender());
if (result != null) {
event.setCompletions(result);
event.setHandled(true); // Doesn't work
}
}
}
// Fix for the event being borked with paper
private List<String> completions = null;
private CommandSender sender;
@EventHandler
public void onTabComplete(TabCompleteEvent event) {
if (event.isCommand()) {
if (sender == event.getSender()) {
event.setCompletions(completions);
sender = null;
} else {
sender = event.getSender();
completions = event.getCompletions();
event.setCompletions(Collections.emptyList());
}
}
}
}

View File

@ -0,0 +1,23 @@
package com.boydti.fawe.bukkit.listener;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import org.bukkit.event.EventHandler;
import org.bukkit.event.server.TabCompleteEvent;
import java.util.List;
public class SyncTabCompleteListener extends ATabCompleteListener {
public SyncTabCompleteListener(WorldEditPlugin worldEdit) {
super(worldEdit);
}
@EventHandler
public void onTabComplete(TabCompleteEvent event) {
if (event.isCommand()) {
List<String> result = this.onTab(event.getBuffer(), event.getSender());
if (result != null) {
event.setCompletions(result);
}
}
}
}

View File

@ -78,14 +78,14 @@ public class DynamicPluginCommand extends org.bukkit.command.Command implements
return owningPlugin;
}
@Override
public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
if (registeredWith instanceof CommandInspector) {
return ((TabCompleter) owner).onTabComplete(sender, this, alias, args);
} else {
return super.tabComplete(sender, alias, args);
}
}
// @Override
// public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
// if (registeredWith instanceof CommandInspector) {
// return ((TabCompleter) owner).onTabComplete(sender, this, alias, args);
// } else {
// return super.tabComplete(sender, alias, args);
// }
// }
@SuppressWarnings("unchecked")
@Override

View File

@ -25,8 +25,6 @@ import com.sk89q.util.StringUtil;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extension.platform.AbstractPlayerActor;
@ -35,9 +33,9 @@ import com.sk89q.worldedit.internal.cui.CUIEvent;
import com.sk89q.worldedit.session.SessionKey;
import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldedit.world.gamemode.GameModes;
import jdk.nashorn.internal.ir.Block;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
@ -47,12 +45,11 @@ import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.annotation.Nullable;
public class BukkitPlayer extends AbstractPlayerActor {
private Player player;

View File

@ -71,7 +71,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* Plugin for Bukkit.
*/
public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
public class WorldEditPlugin extends JavaPlugin //implements TabCompleter
{
private static final Logger log = Logger.getLogger("FastAsyncWorldEdit");
public static final String CUI_PLUGIN_CHANNEL = "worldedit:cui";
@ -390,18 +391,20 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
return true;
}
@Override
public List<String> onTabComplete(CommandSender sender, Command cmd, String commandLabel, String[] args) {
// Add the command to the array because the underlying command handling
// code of WorldEdit expects it
String[] split = new String[args.length + 1];
System.arraycopy(args, 0, split, 1, args.length);
split[0] = cmd.getName();
CommandSuggestionEvent event = new CommandSuggestionEvent(wrapCommandSender(sender), Joiner.on(" ").join(split));
getWorldEdit().getEventBus().post(event);
return event.getSuggestions();
}
// @Deprecated Using Async tab complete (rather than main thread)
// @Override
// public List<String> onTabComplete(CommandSender sender, Command cmd, String commandLabel, String[] args) {
// // Add the command to the array because the underlying command handling
// // code of WorldEdit expects it
// String[] split = new String[args.length + 1];
// System.arraycopy(args, 0, split, 1, args.length);
// split[0] = cmd.getName();
//
// CommandSuggestionEvent event = new CommandSuggestionEvent(wrapCommandSender(sender), Joiner.on(" ").join(split));
// getWorldEdit().getEventBus().post(event);
//
// return event.getSuggestions();
// }
/**
* Gets the session for the player.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,79 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.scripting;
import com.boydti.fawe.Fawe;
import com.sk89q.worldedit.WorldEditException;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
import java.util.Map;
public class NashornCraftScriptEngine implements CraftScriptEngine {
private static NashornScriptEngineFactory FACTORY;
private int timeLimit;
@Override
public void setTimeLimit(int milliseconds) {
timeLimit = milliseconds;
}
@Override
public int getTimeLimit() {
return timeLimit;
}
@Override
public Object evaluate(String script, String filename, Map<String, Object> args) throws Throwable {
ClassLoader cl = Fawe.get().getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(cl);
synchronized (NashornCraftScriptEngine.class) {
if (FACTORY == null) FACTORY = new NashornScriptEngineFactory();
}
;
ScriptEngine engine = FACTORY.getScriptEngine("--language=es6");
SimpleBindings bindings = new SimpleBindings();
for (Map.Entry<String, Object> entry : args.entrySet()) {
bindings.put(entry.getKey(), entry.getValue());
}
try {
Object result = engine.eval(script, bindings);
return result;
} catch (Error e) {
e.printStackTrace();
throw new ScriptException(e.getMessage());
} catch (Throwable e) {
e.printStackTrace();
while (e.getCause() != null) {
e = e.getCause();
}
if (e instanceof WorldEditException) {
throw e;
}
throw e;
} finally {
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -311,8 +311,8 @@
"44:14": "minecraft:nether_brick_slab[type=top]",
"44:15": "minecraft:quartz_slab[type=top]",
"45:0": "minecraft:bricks",
"46:0": "minecraft:tnt[unstable=false]",
"46:1": "minecraft:tnt[unstable=true]",
"46:0": "minecraft:tnt",
"46:1": "minecraft:tnt",
"47:0": "minecraft:bookshelf",
"48:0": "minecraft:mossy_cobblestone",
"49:0": "minecraft:obsidian",
@ -321,11 +321,11 @@
"50:2": "minecraft:wall_torch[facing=west]",
"50:3": "minecraft:wall_torch[facing=south]",
"50:4": "minecraft:wall_torch[facing=north]",
"50:9": "minecraft:torch[facing=east]",
"50:10": "minecraft:torch[facing=west]",
"50:11": "minecraft:torch[facing=south]",
"50:12": "minecraft:torch[facing=north]",
"50:13": "minecraft:torch[facing=up]",
"50:9": "minecraft:wall_torch[facing=east]",
"50:10": "minecraft:wall_torch[facing=west]",
"50:11": "minecraft:wall_torch[facing=south]",
"50:12": "minecraft:wall_torch[facing=north]",
"50:13": "minecraft:torch",
"51:0": "minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=0]",
"51:1": "minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=1]",
"51:2": "minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=2]",

View File

@ -0,0 +1,49 @@
{
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var ARGUMENT_NAMES = /([^\s,]+)/g;
function getParamNames(func) {
var a = func.toString().replace(STRIP_COMMENTS, '');
var r = a.slice(a.indexOf('(')+1, a.indexOf(')')).match(ARGUMENT_NAMES);
var l = new java.util.ArrayList();
if(r !== null) {
for (var i = 0; i < r.length; i++) {
l.add(r[i]);
}
}
return l;
}
function getAllFunctions(){
var a = new java.util.ArrayList();
for (var f in this){
if (this.hasOwnProperty(f) && this[f] instanceof Function && !/a/i.test(f)){
a.add(this[f]);
}
}
return a;
}
var functions = getAllFunctions();
var commands = new java.util.ArrayList()
for (var i = 0; i < functions.length; i++) {
var f = functions[i];
if (f.hasOwnProperty('desc'))
{
if (!f.hasOwnProperty('aliases')) f.aliases = [f.name];
var cmd = com.boydti.fawe.config.Commands.fromArgs(f.aliases, f.usage, f.desc, f.min, f.max, f.flags, f.help);
var man = com.sk89q.worldedit.extension.platform.CommandManager.getInstance();
var builder = man.getBuilder();
var args = getParamNames(f);
var wrap = Java.extend(java.util.function.Function, {
apply: function(a) {
return f.apply(null, a);
}
});
var w2 = new wrap();
var callable = new com.sk89q.worldedit.util.command.parametric.FunctionParametricCallable(builder, "", cmd, "fawe.use", args, w2);
commands.add(callable);
}
}
commands;
}

View File

@ -0,0 +1,356 @@
info:
prefix: '&8(&4&lFAWE&8)&r&7'
file_deleted: '%s0 a été supprimé.'
schematic_pasting: '&7La schematic est en train d''être collée. Cette action ne
peut pas être annulée.'
lighting_propogate_selection: '&7L''éclairage a été propagé dans %s0 chunks. (Info
: Pour supprimer l''éclairage, faites //removelight)'
updated_lighting_selection: '&7L''éclairage a été mis à jour dans %s0 chunks. (Cela
devraît prendre quelques secondes pour que ce soit à jour)'
set_region: '&7La sélection a été mise pour votre région actuellement autorisée'
worldedit_command_limit: '&7Veuillez patienter le temps que vos actions en cours
soient terminées'
worldedit_delayed: '&7Veuillez patienter pendant que votre action soit terminée.'
worldedit_run: '&7Désolé du délai. Exécution en cours: %s'
worldedit_complete: '&7Modification terminée.'
require_selection_in_mask: '&7%s de vos sélections ne sont pas dans votre masque.
Vous ne pouvez effectuer des modifications que dans vos régions autorisées.'
worldedit_volume: '&7Vous ne pouvez pas sélectionner un volume de %current% blocs.
Le volume maximal que vous pouvez éditer est de %max% blocs.'
worldedit_iterations: '&7Vous ne pouvez pas faire %current% itérations. Votre nombre
maximal d''itérations est de %max%.'
worldedit_unsafe: '&7L''accès à cette commande est restreint.'
worldedit_dangerous_worldedit: '&cModification non sécurisée complétée à %s0 par
%s1'
worldedit_toggle_tips_on: '&7Conseils désactivés.'
worldedit_toggle_tips_off: '&7Conseils activés.'
worldedit_bypassed: '&7Bypass de la restriction du plugin.'
worldedit_unmasked: '&6Vos éditions ne sont désormais plus restreintes.'
worldedit_restricted: '&6Vos éditions sont désormais restreintes.'
worldedit_oom_admin: |-
&cOptions possibles:
&8 - &7//fast
&8 - &7Faites de petites modifications
&8 - &7Allouez plus de mémoire
&8 - &7Désactivez `max-memory-percent`
compressed: Historique compressé. Sauvegardé ~ %s0b (%s1x plus petit)
action_complete: Action complétée en %s0 secondes.
error:
worldedit_extend: '&cVotre modification a peut-être été étendue en dehors de votre
région autorisée.'
web_unauthorized: 'Seuls les liens suivants sont autorisés : %s0'
command_syntax: '&cUtilisation : &7%s0'
no_perm: '&cIl vous manque la permission %s0'
setting_disable: '&cOption manquante : %s0'
brush_not_found: '&cBrosses disponibles : %s0'
brush_incompatible: '&cBrosse non compatible avec cette version'
schematic_not_found: '&cSchematic non trouvée : &7%s0'
no_region: '&cVous n''avez pas de région actuellement autorisée'
no_mask: '&cVous n''avez pas de masque actuel'
not_player: '&cVous devez être un joueur pour effectuer cette action !'
player_not_found: '&cJoueur non trouvé :&7 %s0'
oom: |-
&8[&cAttention&8] &cMémoire faible détectée (< 1%). Nous allons :
&8 - &7Terminer le placement des blocs
&8 - &7Supprimer les historiques de blocs
&8 - &7Décharger les chunks non essentiels
&8 - &7Tuer les entités
&8 - &7Vider la mémoire
&cIgnorez ceci si vous essayez de faire crash le serveur.
&7Info : La mémoire faible est causé par WE (mais pas nécessairement)
worldedit_some_fails: '&c%s0 blocs ne peuvent pas être posés car ils sont en dehors
de votre région autorisée.'
worldedit_some_fails_blockbag: '&cBlocs manquants : %s0'
web:
generating_link: Téléversement de %s, veuillez patienter...
generating_link_failed: '&cImpossible de générer le lien.'
download_link: '%s'
worldedit:
general:
mask_disabled: Masque global désactivé
mask: Masque global défini
texture_disabled: Remise à zéro de la texture
texture_set: Texture mise à %s1
source_mask_disabled: Masque source global désactivé
source_mask: Masque source global défini
transform_disabled: Transformation globale désactivée
transform: Transformation globale définie
fast_enabled: Mode rapide activé. Les modifications et les historiques vont être
bypass.
fast_disabled: Mode rapide désactivé.
place_enabled: 'Pose de blocs en #1.'
place_disabled: Pose de blocs à l'endroit où vous vous situez.
copy:
command_copy: '%s0 blocs copiés.'
cut:
command_cut_slow: '%s0 blocs supprimés.'
command_cut_lazy: '%s0 blocs vont être supprimés lors du collage.'
paste:
command_paste: Blocs dans le presse-papier collés à %s0
rotate:
command_rotate: Le presse-papier a subit une rotation
flip:
command_flipped: Le presse-papier a été retourné
regen:
command_regen_0: Région regénérée.
command_regen_1: Région regénérée.
command_regen_2: Région regénérée.
tree:
command_tree: '%s0 arbres créés.'
command_pumpkin: '%s0 patchs de citrouilles créés.'
flora:
command_flora: '%s0 végétations créés.'
history:
command_history_clear: Historique supprimé
command_redo_error: Rien à refaire. (Tapez `/inspect` et `/frb`)
command_history_other_error: Impossible de trouver une session pour %s0.
command_redo_success: Opération refaite.
command_undo_error: Rien à défaire. (Tapez `/inspect` et `/frb`)
command_undo_success: Annulation réussie.
operation:
operation: Opération en attente (%s0)
selection:
selection_wand: 'Clic gauche: sélection position #1; Clic droit: sélection position
#2'
selection_wand_disable: Baguette d'édition désactivée.
selection_wand_enable: Baguette d'édition activée.
selection_chunk: Chunk sélectionné (%s0)
selection_chunks: Chunks sélectionnés (%s0) - (%s1)
selection_contract: blocs (%s0) contractés dans la région.
selection_count: blocs (%s0) dans le compte.
selection_distr: '# blocs au total : %s0'
selection_expand: Sélection étendue de %s0 blocs
selection_expand_vert: Sélection étendue de %s0 blocs (de bas en haut)
selection_inset: Région en médaillon
selection_outset: Début de la région
selection_shift: Région déplacée
selection_cleared: Sélection effacée
navigation:
navigation_wand_error: '&cIl n''y a rien à traverser.'
anvil:
world_is_loaded: Le monde ne devrait pas être utilisé lors de l'exécution. Décharger
le monde, ou utilisez -f pour passer outre (sauvegarder d'abord)
brush:
brush_reset: Réinitialisez votre brosse. (SHIFT + Clic)
brush_none: Tu ne tiens pas une brosse !
brush_scroll_action_set: Régler l'action de défilement sur %s0
brush_scroll_action_unset: Suppression de l'action de défilement
brush_visual_mode_set: Mode visuel mis sur %s0
brush_target_mode_set: Mode cible mis sur %s0
brush_target_mask_set: Masque cible mis sur %s0
brush_target_offset_set: Définir le décalage de la cible à%s0
brush_equipped: Brosse équipée de %s0
brush_try_other: |-
&cIl existe d'autres brosses plus appropriées, par ex.
&8 - &7//br height [radius=5] [#clipboard|file=null] [rotation=0] [yscale=1.00]
brush_copy: Clic gauche sur la base d'un objet à copier, clic droit pour coller.
Augmentez le rayon de la brosse si nécessaire.
brush_height_invalid: Hauteur de la carte invalide (%s0)
brush_smooth: 'Note : Utilisez la brosse de mélange si vous voulez lisser les
porte-à-faux ou les grottes.'
brush_spline: Cliquez pour ajouter un point, cliquez sur le même point pour terminer.
brush_line_primary: Ajout du point %s0, cliquez sur une autre position pour créer
la ligne.
brush_catenary_direction: Ajout du point %s0, cliquez à la direction que vous
souhaitez pour créer la languette.
brush_line_secondary: Languette créée
brush_spline_primary_2: Position ajoutée, cliquez sur le même point pour les rejoindre
!
brush_spline_secondary_error: Pas assez de positions insérées !
brush_spline_secondary: Languette créée
brush_size: Taille de brosse définie
brush_range: Taille de brosse dfinie
brush_mask_disabled: Masque de la brosse désactivé
brush_mask: Masque de la brosse défini
brush_source_mask_disabled: Masque source de la brosse désactivé
brush_source_mask: Masque de la brosse source défini
brush_transform_disabled: Transformation de brosse désactivée
brush_transform: Transformation de brosse défini
brush_material: Type de bloc de la brosse défini
rollback:
rollback_element: Rollback de %s0
tool:
tool_inspect: Outil d'inspection lié à %s0.
tool_inspect_info: '&7%s0 a changé %s1 à %s2 il y a %s3'
tool_inspect_info_footer: '&6Total : &7%s0 modifications'
tool_none: L'outil plus reliée à l'élément courant.
tool_info: Outil d'information lié à %s0.
tool_tree: Outil d'arbres lié à %s0.
tool_tree_error: Type de l'arbre %s0 inconnu.
tool_repl: Outil de remplacement des blocs lié à %s0.
tool_cycler: Outil de type de cycleur de bloc lié à %s0.
tool_flood_fill: Outil de remplissage des blocs lié à %s0.
tool_range_error: 'Portée maximale : %s0.'
tool_radius_error: 'Rayon de brosse maximum autorisé : %s0.'
tool_deltree: Outil flottant d'abattage d'arbres lié à %s0.
tool_farwand: Outil de baguette lointain lié à%s0.
tool_lrbuild_bound: Outil de construction à longue portée lié à %s0.
tool_lrbuild_info: Clic gauche défini sur %s0; Clic droit défini sur %s1.
superpickaxe_enabled: Super pioche activée.
superpickaxe_disabled: Super pioche désactivée.
superpickaxe_area_enabled: Mode modifié. Clique gauche avec la pioche. // pour
désactiver.
snapshot:
snapshot_loaded: Instantané '%s0' chargé; restauration en cours...
snapshot_set: 'Instantané mis sur : %s0'
snapshot_newest: Utilisation du dernier instantané désormais.
snapshot_list_header: 'Instantanés du monde (%s0):'
snapshot_list_footer: Utilisez /snap use [instantané] our /snap use latest.
biome:
biome_list_header: 'Biomes (page %s0/%s1):'
biome_changed: Les biomes ont été modifiés dans %s0 colonnes.
utility:
kill_success: entitées (%s0) tuées dans une portée de %s1 blocs.
nothing_confirmed: Vous n'avez aucune action en attente de confirmation.
page_footer: Utilisez %s0 pour aller à la page suivante.
schematic:
schematic_prompt_clear: '&7Vous voudriez peut-être utiliser &c%s0 &7pour effacer
votre actuel presse-papier'
schematic_show: |-
&7Affichage de &a%s0&7 schématiques depuis &a%s1&7:
&8 - &aClic gauche &7> une structure à mettre dans le presse-papier
&8 - &aClic droit &7> pour mettre une structure dans le presse-papier multiple
&8 - &7Utilisez &a%s2&7 pour revenir au monde
schematic_format: 'Formats disponibles (nom: Noms de recherche)'
schematic_move_exists: '&c%s0 existe déjà'
schematic_move_success: '&a%s0 -> %s1'
schematic_move_failed: '&a%s0 non déplacé : %s1'
schematic_loaded: '%s0 chargé. Collez-le avec //paste'
schematic_saved: '%s0 sauvegardé.'
schematic_page: La page doit-être %s
schematic_none: Aucun fichier trouvé.
schematic_list: 'Fichiers disponibles (nom du fichier: Format) [%s0/%s1]:'
schematic_list_elem: '&8 - &a%s0 &8- &7%s1'
clipboard:
clipboard_uri_not_found: Vous n'avez pas %s0 chargé.
clipboard_cleared: Presse-papier effacé
clipboard_invalid_format: 'Format de presse-papier inconnu : %s0'
visitor:
visitor_block: '%s0 blocs affectés'
visitor_entity: '%s0 entitées affectés'
visitor_flat: '%s0 colonnes affectées'
selector:
selector_fuzzy_pos1: Région définie et étendue depuis %s0 %s1.
selector_fuzzy_pos2: Ajout de l'étendue de %s0 %s1.
selector_pos: position %s0 définie sur %s1 (%s2).
selector_center: Milieu définie sur %s0 (%s1).
selector_radius: Rayon défini sur %s0 (%s1).
selector_expanded: Région étendue sur %s0 (%s1)
selector_invalid_coordinates: Cordonnées invalides !
selector_already_set: Position déjà définie.
selector_set_default: Votre sélecteur de région par défaut est désormais %s0.
timezone:
timezone_set: Fuseau horaire fixé pour cette session sur %s0
timezone_display: 'Le temps actuel pour ce fuseau horaire est : %s0'
command:
command_invalid_syntax: La commande n'a pas été utilisée correctement. (aucune
aide disponible).
help:
command_clarifying_bracket: '&7Ajout d''un crochet de clarification pour &c%s0'
help_suggest: '&7Impossible de trouver %s0. Essayez une des &c%s1 &7?'
help_header_categories: Types de commandes
help_header_subcommands: Sous commandes
help_header_command: '&cAide pour : &7%s0'
help_item_allowed: '&a%s0&8 - &7%s1'
help_item_denied: '&c%s0&8 - &7%s1'
help_header: 'Aide : page %s0/%s1'
help_footer: '&7Wiki anglais : https://git.io/vSKE5'
progress:
progress_message: '%s1/%s0 (%s2%) @%s3bps %s4s restants'
progress_finished: '[ Terminé ! ]'
cancel:
worldedit_cancel_count: '&cModifications %s0 annulées.'
worldedit_cancel_reason_confirm: '&7Votre sélection est large (&c%s0 &7-> &c%s1&7,
contenant &c%s3&7 blocs). Faites &c//confirm &7pour exécuter &c%s2'
worldedit_cancel_reason: '&cVotre action a été annulée :&7 %s0&c.'
worldedit_cancel_reason_manual: Annulation humaine
worldedit_cancel_reason_low_memory: Mémoire trop faible
worldedit_cancel_reason_max_changes: Trop de blocs modifiés
worldedit_cancel_reason_max_checks: Trop de vérifications
worldedit_cancel_reason_max_tiles: Trop de types de blocs
worldedit_cancel_reason_max_entities: Entités trop élevées
worldedit_cancel_reason_max_iterations: Itérations trop élevées
worldedit_cancel_reason_outside_level: En dehors du monde
worldedit_cancel_reason_outside_region: En dehors de la région autorisée (bypass
avec /wea, ou désactivez `region-restrictions` dans la configuration)
worldedit_cancel_reason_no_region: Région non autorisée (bypass avec /wea, ou désactivez
`region-restrictions` dans la configuration)
worldedit_failed_load_chunk: '&cChargement du chunk ignoré : &7%s0;%s1&c. Essayez
d''augmenter chunk-wait.'
navigation:
ascend_fail: Aucune place libre au-dessus de vous n'a été trouvée
ascended_plural: Montée de %s0 couche.
ascended_singular: Montée de 1 couche.
unstuck: Et voilà !
descend_fail: Aucune place libre en dessous de vous n'a été trouvée.
descend_plural: Descendu de %s0 couches.
descend_singular: Descendu de 1 couche.
whoosh: Waouh !
poof: Pouf !
thru_fail: Aucune place libre devant vous n'a été trouvée.
no_block: Pas de bloc en vue ! (ou trop loin)
up_fail: ' Tu frapperais quelque chose au-dessus de toi.'
selection:
sel_cuboid: 'Cuboïde : clic gauche pour point 1, clic droit pour point 2'
sel_cuboid_extend: 'Cuboïde : clic gauche pour le point de départ, clic droit pour
étendre'
sel_2d_polygon: 'Sélecteur de polygone 2D : Clic gauche/droit pour ajouter un point.'
sel_ellipsiod: 'Sélecteur ellipsoïde : clic gauche=centre, clic droit pour agrandir.'
sel_sphere: 'Sélecteur de sphère : clic gauche=centre, clic droit pour définir le
rayon.'
sel_cylindrical: 'Sélecteur cylindrique : Clic gauche=centre, clic droit pour étendre.'
sel_max: '%s0 points maximum.'
sel_fuzzy: 'Sélecteur flou : Clic gauche pour sélectionner tous les blocs contingents,
clic droit. à ajouter. Pour sélectionner une cavité d''air, utilisez //pos1.'
sel_convex_polyhedral: 'Sélecteur polyédrique convexe : Clic gauche=Premier sommet,
droite, droite cliquez pour en ajouter d''autres.'
sel_list: Pour une liste de types de sélection, faites &c //sel list
sel_modes: 'Sélectionnez un des modes en dessous :'
tips:
tip_sel_list: 'Astuce : Voir les différents modes de sélection avec &c//sel list'
tip_select_connected: Astuce, Sélectionner tous les blocs connectés avec //sel fuzzy'
tip_set_pos1: Astuce, Utilisez pos1 comme motif avec &c//set pos1
tip_farwand: Astuce, Sélectionnez les points distants avec &c//farwand.'
tip_discord: 'Besoin d''aide ? Aide en anglais disponible : https://discord.gg/ngZCzbU'
tip_lazycut: '&7Conseil, Il est plus sûr d''utiliser &c//lazycut'
tip_fast: '&7Astuce, Définir rapidement et sans défaire en utilisant &c//fas'
tip_cancel: '&7Astuce, Vous pouvez &c//cancel &7et éditer en cours de traitement.'
tip_mask: '&7Astuce, Définir un masque de destination globale avec &c/gmask'
tip_mask_angle: '&7Astuce, Remplacer les pentes ascendantes de 3-20 blocs en faisant&c
//replace /[-20][-3] bedrock'
tip_set_linear: '&7Conseil, Définissez les blocs de manière linéaire avec&c //set
#l3d[wood,bedrock]'
tip_surface_spread: '&7Conseil, Étendez une surface plane à l''aide de&c //set #surfacespread[5][0][5][#existing]'
tip_set_hand: '&7Astuce, Utilisez votre main actuelle avec &c//set hand'
tip_replace_regex: '&7Tip, Remplacer à l''aide de regex :&c //replace .*_log <pattern>'
tip_replace_regex_2: '&7Tip, Remplacer à l''aide de regex :&c //replace .*stairs[facing=(north|south)]
<pattern>'
tip_replace_regex_3: '&7Tip, Remplacer à l''aide des opérateurs :&c //replace water[level>2]
sand'
tip_replace_regex_4: '&7Tip, Remplacer à l''aide des opérateurs :&c //replace true
*[waterlogged=false]'
tip_replace_regex_5: '&7Tip, Remplacer à l''aide des opérateurs :&c //replace true
*[level-=1]'
tip_replace_id: '&7Tip, Remplacez seulement l''ID du bloc :&c //replace woodenstair
#id[cobblestair]'
tip_replace_light: 'Tip, Remplacez seulement les sources de lumière :&c //replace
#brightness[1][15] 0'
tip_tab_complete: Tip, La commande de remplacement prend en charge la complétion
du tab.
tip_flip: Tip, Flip avec &c//flip
tip_deform: Tip, Remodeler avec &c//deform
tip_transform: Tip, Sélectionnez une transformation avec &c//gtransform
tip_copypaste: Tip, Collez en cliquant avec &c//br copypaste
tip_source_mask: Tip, Sélectionnez un masque source avec &c/gsmask <mask>&7
tip_replace_marker: 'Tip, Remplacez un bloc avec votre presse-papier entier avec
&c//replace wool #fullcopy'
tip_paste: Tip, Collez avec &c//paste
tip_lazycopy: Tip, LazyCopy est plus rapide
tip_download: Tip, Essayez &c//download
tip_rotate: Tip, Orientez vos sélections avec &c//rotate
tip_copy_pattern: Tip, Utilisez un type de pattern avec &c#copy
tip_regen_0: Tip, Utilisez un biome avec /regen [biome]
tip_regen_1: Tip, Utilisez un seed avec /regen [biome] [seed]
tip_biome_pattern: Tip, Le pattern &c#biome[forest]&7 peut être utilisé dans une
quelconque commande
tip_biome_mask: Tip, Mettez une restriction de biome en utilisant le masque `$jungle`

View File

@ -0,0 +1,331 @@
#Published by NotMyFault
info:
prefix: '&8(&4&lFAWE&8)&r&7'
file_deleted: '%s0 Is verwijderd.'
schematic_pasting: '&7Het schematic wordt geplaatst. dit kan niet veranderd worden.'
lighting_propogate_selection: '&7Het licht heeft zich verspreid in %s0 chunks. (Note:
om het licht te verwijderen, doe //removelight)'
updated_lighting_selection: '&7Lighting is geüpdatet in %s0 chunks.
(het kan even duren voordat de packets worden verstuurd)'
set_region: '&7Toegestaande regio geselecteerd'
worldedit_command_limit: '&7U kunt weer verder gaan wanneer uw vorige actie voltooid is'
worldedit_delayed: '&7U kunt weer verder gaan wanneer wij uw FAWE action voltooien...'
worldedit_run: '&7Sorry voor het ongemak. huidige uitvoerende actie: %s'
worldedit_complete: '&7Verandering voldaan.'
require_selection_in_mask: '&7%s Van je selectie is niet binnen je mask.
Je kan alleen veranderingen uitvoeren in de toegestaande regio.'
worldedit_volume: '&7Je kan niet een volume van %current% toepassen.
Het maximum volume dat je kan toepassen is %max%.'
worldedit_iterations: '&7Je kan %current% niet zoveel keer herhalen. het maximale
wat toegestaan is, is %max%.'
worldedit_unsafe: '&7Toegang tot deze command is geblokkeerd'
worldedit_dangerous_worldedit: '&cNnveilige edits zijn verwerkt op %s0 by %s1'
worldedit_toggle_tips_on: '&7Disabled FAWE tips.'
worldedit_toggle_tips_off: '&7De FAWE tips staan nu aan.'
worldedit_bypassed: '&7De restrictie of FAWE wordt nu overscheiden.'
worldedit_unmasked: '&6Je FAWE edits hebben nu geen restrictie meer.'
worldedit_restricted: '&6Je FAWE edits hebben nu een restrictie.'
worldedit_oom_admin: |-
&cMogelijke opties:
&8 - &7//fast
&8 - &7Voer kleinere bewerkingen uit
&8 - &7Wijs meer geheugen toe
&8 - &7Disable `max-memory-percent`
compressed: Geschiedenis gecomprimeerd. Saved ~ %s0b (%s1x kleiner)
action_complete: Action completed in %s0 seconds
error:
worldedit_extend: '&cje edit is waarschijnlijk buiten het toegestaande gebied gekomen.'
web_unauthorized: 'alleen links van de configureerde webhost zijn toegestaan: %s0'
command_syntax: '&cGebruik: &7%s0'
no_perm: '&cje hebt hier geen permission node voor: %s0'
setting_disable: '&cSetting ontbreekt: %s0'
brush_not_found: '&cBruikbare brushes: %s0'
brush_incompatible: '&cDeze brush kan niet in deze versie gebruikt worden'
schematic_not_found: '&cSchematic niet gevonden: &7%s0'
no_region: '&cJe hebt momenteel geen toegestaand gebied'
no_mask: '&cJe hebt momenteel geen brush geselecteerd'
not_player: '&cJe moet een speler zijn om dit te doen!'
player_not_found: '&cSpeler niet gevonden:&7 %s0'
oom: |-
&8[&cCritical&8] &cGedetecteerd laag geheugen i.e. < 1%. We zullen de volgende acties ondernemen:
&8 - &7Verwijder de huidige WE blok plaatsing
&8 - &7Clear WE history
&8 - &7Unload non essential chunks
&8 - &7Dood de entities
&8 - &7Onnodige data collecteren
&cNegeer dit als je de server wilt laten crashen.
&7Note: Een laag opslagvermogen kan door WE veroorzaakt worden (dit hoeft niet)
worldedit_some_fails: '&c%s0 Blokken zijn niet geplaats omdat ze uit je
toegestaande gebied werden geplaatst.'
worldedit_some_fails_blockbag: '&coOntbrekende blokken: %s0'
web:
generating_link: Uploading %s, even geduld A.U.B...
generating_link_failed: '&cDe donwload link kon niet worden gemaakt!'
download_link: '%s'
worldedit:
general:
mask_disabled: Global mask uitgeschakeld
mask: Global mask is gezet
texture_disabled: Texturing reset
texture_set: Texturing tot %s1 gezet
source_mask_disabled: Global source mask uitgeschakeld
source_mask: Global source mask geszet
transform_disabled: Global transform uitgeschakeld
transform: Global transform gezet
fast_enabled: Fast mode aangezet. History en edit restrictions zullen worden negeerd.
fast_disabled: Fast mode uitgeschakeld
place_enabled: 'Wordt nu geplaats op locatie #1.'
place_disabled: Het wordt nu geplaatst op het blok waar je op staat.
copy:
command_copy: '%s0 blokken zijn gekopieerd.'
cut:
command_cut_slow: '%s0 Blocks were cut.'
command_cut_lazy: '%s0 Blokken zullen verwijderd worden bij plaatsing'
paste:
command_paste: Het klipbord is geplaatst op %s0
rotate:
command_rotate: Het klipbord is omgedraaid
flip:
command_flipped: Het klipbord is omgedraaid
regen:
command_regen_0: Regio gegenereerd.
command_regen_1: Regio gegenereerd.
command_regen_2: Regio gegenereerd.
tree:
command_tree: '%s0 Bomen gecreëerd.'
command_pumpkin: '%s0 Pompoenen gecreëerd.'
flora:
command_flora: '%s0 Flora gecreëerd.'
history:
command_history_clear: Geschiedenis verwijderd
command_redo_error: Er is niks om te ontdaan. (See also `/inspect` and `/frb`)
command_history_other_error: We kunnen geen sessie voor %s0 vinden.
command_redo_success: Herdaan succesvol.
command_undo_error: Er is niet om te ontdaan. (See also `/inspect` and `/frb`)
command_undo_success: Herdaan succesvol.
operation:
operation: Operaties die in de wacht staan (%s0)
selection:
selection_wand: 'Links klikken: selecteer pos #1; Rechts klikken: selecteer pos #2'
selection_wand_disable: Edit wand uitgeschakeld.
selection_wand_enable: Edit wand ingeschakeld.
selection_chunk: Chunk geselecteerd (%s0)
selection_chunks: Chunks geselecteerd (%s0) - (%s1)
selection_contract: Region contracted %s0 blokken.
selection_count: %s0 Blokken geteld.
selection_distr: '# Totaal aantal blokken: %s0'
selection_expand: Regio vergroot met %s0 blokken.
selection_expand_vert: Regio vergroot met %s0 blokken (van boven naar beneden)
selection_inset: Region inset
selection_outset: Region outset
selection_shift: Region verzet
selection_cleared: Selectie verwijderd
navigation:
navigation_wand_error: '&cNergens om door heen te gaan'
anvil:
world_is_loaded: de wereld zou niet in gebruik moeten zijn wanneer er een uitvoering wordt gedaan. onlaad de wereld,
of gebruik -f om het te overschrijden (save first)
brush:
brush_reset: Reset je brush. (SHIFT + Click)
brush_none: Je houdt hebt geen brush vast!
brush_scroll_action_set: Scroll action gezet naar %s0
brush_scroll_action_unset: Scroll action uitgeschakeld.
brush_visual_mode_set: Visuele mode gezet naar %s0
brush_target_mode_set: Target mode gezet naar %s0
brush_target_mask_set: Target mode gezet naar %s0
brush_target_offset_set: Uitschietting van de target gezet tot %s0
brush_equipped: Brush in gebruik: %s0
brush_try_other: |-
&cEr zijn betere brushes hier voor te gebruiken e.g.
&8 - &7//br height [radius=5] [#clipboard|file=null] [rotation=0] [yscale=1.00]
brush_copy: Links klik de fundering van de constructie om te kopieëren, rechts klik om te plakken. verhoog
de brush Settings als dat mogelijk is.
brush_height_invalid: Onvalide hoogte map file (%s0)
brush_smooth: 'Note: Gebruik de blend brush om caves en hangende dingen glad te krijgen.'
brush_spline: Klik Om een bevestigingspunt te zetten, klik hetzelfde punt om het af te ronden.
brush_line_primary: Punt %s0 toegevoegt, klik op een andere locatie om de lijn te creëeren.
brush_catenary_direction: Punt %s0 toegevoegt, klik naar de directie waar je
krommen wilt.
brush_line_secondary: Kromme lijn gecreëerd
brush_spline_primary_2: Positie toegevoegt, klik hetzelfde punt om mee te doen!
brush_spline_secondary_error: Niet genoeg posities gezet!
brush_spline_secondary: Kromme lijn gecreërd
brush_size: Brush grootte gezet
brush_range: Brush bereik gezet
brush_mask_disabled: Brush mask disabled
brush_mask: Brush mask gezet
brush_source_mask_disabled: Brush source mask uitgeschakeld
brush_source_mask: Brush source mask gezet
brush_transform_disabled: Brush transform uitgeschakeld
brush_transform: Brush transform gezet
brush_material: Brush material gezet
rollback:
rollback_element: %s0 aan het ontdaan maken.
tool:
tool_inspect: Inspect tool gebonden aan %s0.
tool_inspect_info: '&7%s0 veranderd %s1 to %s2 %s3 geleden'
tool_inspect_info_footer: '&6Totaal: &7%s0 veranderingen'
tool_none: De tool is niet meer gebonden aan je item.
tool_info: Info tool gebonden aan %s0.
tool_tree: Tree tool gebonden aan %s0.
tool_tree_error: Tree type %s0 is niet gevonden.
tool_repl: Block replacer tool gebonden aan %s0.
tool_cycler: Block data cycler tool gebonden aan %s0.
tool_flood_fill: Block flood fill tool gebonden aan %s0.
tool_range_error: 'Maximale bereik: %s0.'
tool_radius_error: 'Maximum toegestaande brush radius: %s0.'
tool_deltree: Floating tree remover tool gebonden aan %s0.
tool_farwand: Far wand tool gebonden aan %s0.
tool_lrbuild_bound: Long-range building tool gebonden aan %s0.
tool_lrbuild_info: links-klik gebonden aan %s0; rechts-klik gebonden aan %s1.
superpickaxe_enabled: Super Pickaxe ingeschakeld.
superpickaxe_disabled: Super Pickaxe uitgeschakeld.
superpickaxe_area_enabled: Mode veranderd. Links klik met een pickaxe. // om uit te schakelen.
snapshot:
snapshot_loaded: Snapshot '%s0' geladen; nu aan het herstellen...
snapshot_set: 'Snapshot gezet tot: %s0'
snapshot_newest: Je gebruikt de nieuwste snapshot.
snapshot_list_header: 'Snapshots voor wereld (%s0):'
snapshot_list_footer: Gebruik /snap use [snapshot] of /snap use latest.
biome:
biome_list_header: 'Biomes (page %s0/%s1):'
biome_changed: Biotopen zijn veranderd in %s0 columns.
utility:
kill_success: %s0 entities zijn vermoord in een radius van %s1.
nothing_confirmed: Je hebt geen acties die bevestigt moeten worden.
page_footer: Gebruik %s0 om naar de volgende pagina te gaan
schematic:
schematic_prompt_clear: '&7we raden je aan &c%s0 &7 te gebruiken om je klipbord te verwijderen
first'
schematic_show: |-
&7scematics &a%s0&7 aan het wergeven &a%s1&7:
&8 - &aLinks klik &7a het gebouw om er een klipbord van de maken
&8 - &aRechts klik &7a om een gebouw toe te voegen aan je multi-klipbord
&8 - &7Gebruik &a%s2&7 om terug naar de wereld te gaan
schematic_format: 'Beschikbare formats (Name: Lookup names)'
schematic_move_exists: '&c%s0 bestaat al'
schematic_move_success: '&a%s0 -> %s1'
schematic_move_failed: '&a%s0 aantal verplaatst: %s1'
schematic_loaded: '%s0 gelanden. plak met //paste'
schematic_saved: '%s0 opgeslagen.'
schematic_page: Pagina moet %s zijn
schematic_none: Niks gevonden.
schematic_list: 'Beschikbare files (Filename: Format) [%s0/%s1]:'
schematic_list_elem: '&8 - &a%s0 &8- &7%s1'
clipboard:
clipboard_uri_not_found: Je hebt %s0 niet geladen
clipboard_cleared: Jlikbord verwijderd
clipboard_invalid_format: 'Niet bestaand clipboard format: %s0'
visitor:
visitor_block: '%s0 blocks aangetast'
visitor_entity: '%s0 entities aangetast'
visitor_flat: '%s0 columns aangetast'
selector:
selector_fuzzy_pos1: Regio gezet en verwijd van/naar %s0 %s1.
selector_fuzzy_pos2: Verwijding van %s0 %s1 toegevoegt.
selector_pos: pos%s0 gezet naar %s1 (%s2).
selector_center: Center gezet naar %s0 (%s1).
selector_radius: Radius gezet naar %s0 (%s1).
selector_expanded: Regio uitgebreid naar %s0 (%s1)
selector_invalid_coordinates: non-valid coördinaten %s0
selector_already_set: Positie al gezet.
selector_set_default: Your normale regio selector is nu %s0.
timezone:
timezone_set: 'Timezone gezet voor deze sessie naar: %s0'
timezone_display: 'De actuele tijd in die tijdzone is: %s0'
command:
command_invalid_syntax: De command was niet goed gebruikt (no more help available).
help:
command_clarifying_bracket: '&7 clarifying bracket toegevoegt aan &c%s0'
help_suggest: '&7kon %s0 niet binden. misschien één van deze proberen &c%s1 &7?'
help_header_categories: Command Types
help_header_subcommands: Subcommands
help_header_command: '&cHelp voor: &7%s0'
help_item_allowed: '&a%s0&8 - &7%s1'
help_item_denied: '&c%s0&8 - &7%s1'
help_header: 'Help: pagina %s0/%s1'
help_footer: '&7Wiki: https://git.io/vSKE5'
progress:
progress_message: '%s1/%s0 (%s2%) @%s3cps %s4s left'
progress_finished: '[ Klaar! ]'
cancel:
worldedit_cancel_count: '&czoveel edits: %s0 ontdaan.'
worldedit_cancel_reason_confirm: '&7Het geselecteerde gebied is groot (&c%s0 &7-> &c%s1&7,
containing &c%s3&7 blocks). Gebruik &c//confirm &7om te bevestigen &c%s2'
worldedit_cancel_reason: '&cYour WorldEdit actie was opgeheven:&7 %s0&c.'
worldedit_cancel_reason_manual: manuele opheffing
worldedit_cancel_reason_low_memory: Lage memory
worldedit_cancel_reason_max_changes: Teveel blokken verandered
worldedit_cancel_reason_max_checks: Teveel block checks
worldedit_cancel_reason_max_tiles: Teveel blockstates
worldedit_cancel_reason_max_entities: Teveel entities
worldedit_cancel_reason_max_iterations: Maximum herhaling
worldedit_cancel_reason_outside_level: Buiten de bebouwde kom
worldedit_cancel_reason_outside_region: Buiten het toegestaande gebied (bypass with /wea,
or disable `region-restrictions` in config.yml)
worldedit_cancel_reason_no_region: geen toegestaand gebied (bypass with /wea, or disable
`region-restrictions` in config.yml)
worldedit_failed_load_chunk: '&cChunks laden overgeslaan: &7%s0;%s1&c. probeer het
chunk-wait op te krikken.'
navigation:
ascend_fail: Geen vrije plekken boven je gesignaleerd.
ascended_plural: %s0 levels verlaagt.
ascended_singular: Ascended a level.
unstuck: There you go!
descend_fail: geen vrije plekken onder je gesignaleerd.
descend_plural: %s0 levels gedaald.
descend_singular: Een level gedaald.
whoosh: Whoosh!
poof: Poof!
thru_fail: Geen vrije plekken voor je.
no_block: Geen blokken in zicht! (of te ver)
up_fail: Er hangt helaas iets boven je.
selection:
sel_cuboid: 'Cuboid: links klik voor punt 1, rechts klik voor punt 2'
sel_cuboid_extend: 'Cuboid: links klik voor een begin punt, rechts klik om te verbreden'
sel_2d_polygon: '2D polygon selector: links/rechts klik om een punt toe te voegen.'
sel_ellipsiod: 'Ellipsoid selector: links klik=center, rechts klik om te verbreden'
sel_sphere: 'Sphere selector: Links klik=center, rechts klik om de radius te zetten'
sel_cylindrical: 'Cylindrical selector: links klik+center, right click to extend.'
sel_max: '%s0 points maximum.'
sel_fuzzy: 'Fuzzy selector: links klik om alle bestaande blokken te plaatsen, rechts klik
om toe te voegen. om een lucht holte te selecteren, doe //pos1.'
sel_convex_polyhedral: 'Convex polyhedral selector: Links klik=First vertex, rechts
klik om meer toe te voegen.'
sel_list: Voor een lijst met selecties doe:&c //sel list
sel_modes: 'Selecteer één van de modes hier:'
tips:
tip_sel_list: 'Tip: Zie de verschillende selectie modes met &c//sel list'
tip_select_connected: 'Tip: Selecteer alle verbonden blokken met //sel fuzzy'
tip_set_pos1: 'Tip: Gebruik pos1 als een punt met &c//set pos1'
tip_farwand: 'Tip: Selecteer punten van ver weg met &c//farwand'
tip_lazycut: '&7Tip: Het is veiliger om &c//lazycut te gebruiken'
tip_fast: '&7Tip: Set fast and without undo using &c//fast'
tip_cancel: '&7Tip: gebruik &c//cancel &7 om een edit stop te zetten'
tip_mask: '&7Tip: Zet een globale bestemmings mask met &c/gmask'
tip_mask_angle: 'Tip: Vervang opwaartse hellingen van 3-20 blocks met&c //replace /[-20][-3]
bedrock'
tip_set_linear: '&7Tip: Zet een blok lineaire met &c//set #l3d[wood,bedrock]'
tip_surface_spread: '&7Tip: Verpsreid een oppervlakte met &c//set #surfacespread[5][0][5][#existing]'
tip_set_hand: '&7Tip: Gebruik je huide hand met &c//set hand'
tip_replace_id: '&7Tip: Vervang alleen het blok id:&c//replace woodenstair #id[cobblestair]'
tip_replace_light: 'Tip: Verwijder licht met with&c//replace #brightness[1][15]
0
tip_tab_complete: 'Tip: The replace command supports tab completion'
tip_flip: 'Tip: Mirror met &c//flip'
tip_deform: 'Tip: Verander het van vorm met &c//deform'
tip_transform: 'Tip: Zet een transform met &c//gtransform'
tip_copypaste: 'Tip: Plaats bij klikken met &c//br copypaste'
tip_source_mask: 'Tip: Zet een source mask met
&c/gsmask <mask>&7'
tip_replace_marker: 'Tip: verander een blok in je volle klipbord met &c//replace
wool #fullcopy'
tip_paste: 'Tip: Plaats met &c//paste'
tip_lazycopy: 'Tip: lazycopy is sneller'
tip_download: 'Tip: probeer &c//download'
tip_rotate: 'Tip: orïenteer met &c//rotate'
tip_copy_pattern: 'Tip: Om een pattern te gebruiken, probeer &c#copy'
tip_regen_0: 'Tip: Gebruik een biome met /regen [biome]'
tip_regen_1: 'Tip: gebruik een seed met /regen [biome] [seed]'
tip_biome_pattern: 'Tip: Dee &c#biome[forest]&7 pattern kan ik elke opdracht gebruikt worden'
tip_biome_mask: 'Tip: Er wordt een restrictie geplaatst op de biome met `$jungle` mask'