Fix some merge issues

This commit is contained in:
Jesse Boyd 2019-11-20 00:11:54 +00:00
parent 0e22d4718a
commit 60759934a3
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
54 changed files with 1403 additions and 1180 deletions

View File

@ -21,6 +21,7 @@ repositories {
maven { url = uri("http://repo.dmulloy2.net/content/groups/public/") } maven { url = uri("http://repo.dmulloy2.net/content/groups/public/") }
maven { url = uri("http://ci.ender.zone/plugin/repository/everything/") } maven { url = uri("http://ci.ender.zone/plugin/repository/everything/") }
maven { url = uri("https://repo.inventivetalent.org/content/groups/public/")} maven { url = uri("https://repo.inventivetalent.org/content/groups/public/")}
flatDir {dir(File("lib"))}
} }
configurations.all { configurations.all {
@ -34,6 +35,7 @@ dependencies {
"api"(project(":worldedit-core")) "api"(project(":worldedit-core"))
"api"(project(":worldedit-libs:core")) "api"(project(":worldedit-libs:core"))
"api"(project(":worldedit-libs:bukkit")) "api"(project(":worldedit-libs:bukkit"))
"compile"(":worldedit-adapters:")
"compile"("it.unimi.dsi:fastutil:8.2.1") "compile"("it.unimi.dsi:fastutil:8.2.1")
"api"("com.destroystokyo.paper:paper-api:1.14.4-R0.1-SNAPSHOT") { "api"("com.destroystokyo.paper:paper-api:1.14.4-R0.1-SNAPSHOT") {
exclude("junit", "junit") exclude("junit", "junit")

View File

@ -230,16 +230,6 @@ public class BukkitPlayer extends AbstractPlayerActor {
|| plugin.getPermissionsResolver().hasPermission(player.getWorld().getName(), player, perm); || plugin.getPermissionsResolver().hasPermission(player.getWorld().getName(), player, perm);
} }
@Override public boolean togglePermission(String permission) {
if (this.hasPermission(permission)) {
player.addAttachment(plugin).setPermission(permission, false);
return false;
} else {
player.addAttachment(plugin).setPermission(permission, true);
return true;
}
}
@Override @Override
public boolean isAllowedToFly() { public boolean isAllowedToFly() {
return player.getAllowFlight(); return player.getAllowFlight();
@ -257,13 +247,13 @@ public class BukkitPlayer extends AbstractPlayerActor {
* - The `/wea` command will give/remove the required bypass permission * - The `/wea` command will give/remove the required bypass permission
*/ */
if (Fawe.<FaweBukkit>imp().getVault() == null || Fawe.<FaweBukkit> imp().getVault().permission == null) { if (Fawe.<FaweBukkit>imp().getVault() == null || Fawe.<FaweBukkit> imp().getVault().permission == null) {
player.addAttachment(Fawe.<FaweBukkit> imp().getPlugin()).setPermission(permission, value); player.addAttachment(plugin).setPermission(permission, value);
} else if (value) { } else if (value) {
if (!Fawe.<FaweBukkit> imp().getVault().permission.playerAdd(player, permission)) { if (!Fawe.<FaweBukkit> imp().getVault().permission.playerAdd(player, permission)) {
player.addAttachment(Fawe.<FaweBukkit> imp().getPlugin()).setPermission(permission, value); player.addAttachment(plugin).setPermission(permission, value);
} }
} else if (!Fawe.<FaweBukkit>imp().getVault().permission.playerRemove(player, permission)) { } else if (!Fawe.<FaweBukkit>imp().getVault().permission.playerRemove(player, permission)) {
player.addAttachment(Fawe.<FaweBukkit>imp().getPlugin()).setPermission(permission, value); player.addAttachment(plugin).setPermission(permission, value);
} }
} }

View File

@ -10,6 +10,7 @@ plugins {
repositories { repositories {
maven { url = uri("http://ci.athion.net/job/PlotSquared-breaking/ws/mvn/") } maven { url = uri("http://ci.athion.net/job/PlotSquared-breaking/ws/mvn/") }
} }
applyPlatformAndCoreConfiguration() applyPlatformAndCoreConfiguration()
@ -23,7 +24,7 @@ configurations.all {
dependencies { dependencies {
"compile"(project(":worldedit-libs:core")) "compile"(project(":worldedit-libs:core"))
"compile"("de.schlichtherle:truezip:6.8.3") "compile"("de.schlichtherle:truezip:6.8.3")
"compile"("rhino:js:1.7.11") "compile"("org.mozilla:rhino:1.7.11")
"compile"("org.yaml:snakeyaml:1.23") "compile"("org.yaml:snakeyaml:1.23")
"compile"("com.google.guava:guava:21.0") "compile"("com.google.guava:guava:21.0")
"compile"("com.google.code.findbugs:jsr305:3.0.2") "compile"("com.google.code.findbugs:jsr305:3.0.2")

View File

@ -16,10 +16,9 @@ import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.PlatformCommandManager; import com.sk89q.worldedit.extension.platform.PlatformCommandManager;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.expression.EvaluationException;
import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.internal.expression.runtime.Constant;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
@ -39,6 +38,8 @@ public class BrushSettings {
SCROLL_ACTION, SCROLL_ACTION,
} }
private static final Expression DEFAULT_SIZE = Expression.compile("1");
private final Map<SettingType, Object> constructor = new ConcurrentHashMap<>(); private final Map<SettingType, Object> constructor = new ConcurrentHashMap<>();
private Brush brush; private Brush brush;
@ -46,7 +47,7 @@ public class BrushSettings {
private Mask sourceMask; private Mask sourceMask;
private ResettableExtent transform; private ResettableExtent transform;
private Pattern material; private Pattern material;
private Expression size = new Expression(1); private Expression size = DEFAULT_SIZE;
private Set<String> permissions; private Set<String> permissions;
private Scroll scrollAction; private Scroll scrollAction;
private String lastWorld; private String lastWorld;
@ -135,7 +136,7 @@ public class BrushSettings {
transform = null; transform = null;
material = null; material = null;
scrollAction = null; scrollAction = null;
size = new Expression(1); size = DEFAULT_SIZE;
permissions.clear(); permissions.clear();
constructor.clear(); constructor.clear();
return this; return this;
@ -182,7 +183,7 @@ public class BrushSettings {
public BrushSettings setSize(Expression size) { public BrushSettings setSize(Expression size) {
checkNotNull(size); checkNotNull(size);
this.size = size; this.size = size;
if (size.getRoot() instanceof Constant && ((Constant) size.getRoot()).getValue() == -1) { if (size == DEFAULT_SIZE) {
constructor.remove(SettingType.SIZE); constructor.remove(SettingType.SIZE);
} else { } else {
constructor.put(SettingType.SIZE, size.toString()); constructor.put(SettingType.SIZE, size.toString());
@ -191,7 +192,7 @@ public class BrushSettings {
} }
public BrushSettings setSize(double size) { public BrushSettings setSize(double size) {
return setSize(new Expression(size)); return setSize(Expression.compile(Double.toString(size)));
} }
public BrushSettings setScrollAction(Scroll scrollAction) { public BrushSettings setScrollAction(Scroll scrollAction) {

View File

@ -3,9 +3,9 @@ package com.boydti.fawe.object.pattern;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.function.pattern.AbstractPattern; import com.sk89q.worldedit.function.pattern.AbstractPattern;
import com.sk89q.worldedit.internal.expression.EvaluationException;
import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
@ -49,7 +49,7 @@ public class ExpressionPattern extends AbstractPattern {
((WorldEditExpressionEnvironment) expression.getEnvironment()).setCurrentBlock(vector.toVector3()); ((WorldEditExpressionEnvironment) expression.getEnvironment()).setCurrentBlock(vector.toVector3());
} }
double combined = expression.evaluate(vector.getX(), vector.getY(), vector.getZ()); double combined = expression.evaluate(vector.getX(), vector.getY(), vector.getZ());
return BlockState.getFromInternalId((int) combined).toBaseBlock(); return BlockState.getFromOrdinal((int) combined).toBaseBlock();
} catch (EvaluationException e) { } catch (EvaluationException e) {
e.printStackTrace(); e.printStackTrace();
return BlockTypes.AIR.getDefaultState().toBaseBlock(); return BlockTypes.AIR.getDefaultState().toBaseBlock();

View File

@ -22,7 +22,7 @@ import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.SpongeSchematicWriter; import com.sk89q.worldedit.extent.clipboard.io.FastSchematicWriter;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CuboidRegion;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
@ -78,7 +78,7 @@ public class FaweSchematicHandler extends SchematicHandler {
if (cTag instanceof CompressedSchematicTag) { if (cTag instanceof CompressedSchematicTag) {
Clipboard clipboard = (Clipboard) cTag.getSource(); Clipboard clipboard = (Clipboard) cTag.getSource();
try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new BufferedOutputStream(new PGZIPOutputStream(stream)))) { try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new BufferedOutputStream(new PGZIPOutputStream(stream)))) {
new SpongeSchematicWriter(output).write(clipboard); new FastSchematicWriter(output).write(clipboard);
} }
} else { } else {
try (OutputStream stream = new FileOutputStream(tmp); BufferedOutputStream output = new BufferedOutputStream(new PGZIPOutputStream(stream))) { try (OutputStream stream = new FileOutputStream(tmp); BufferedOutputStream output = new BufferedOutputStream(new PGZIPOutputStream(stream))) {

View File

@ -1,287 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.boydti.fawe.util;
import com.boydti.fawe.command.AnvilCommands;
import com.boydti.fawe.command.CFICommands;
import com.sk89q.minecraft.util.commands.Step;
import com.sk89q.worldedit.command.ToolUtilCommands;
import com.sk89q.worldedit.internal.annotation.Range;
import org.enginehub.piston.annotation.Command;
import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.minecraft.util.commands.NestedCommand;
import com.sk89q.worldedit.command.BiomeCommands;
import com.sk89q.worldedit.command.BrushCommands;
import com.sk89q.worldedit.command.ChunkCommands;
import com.sk89q.worldedit.command.ClipboardCommands;
import com.sk89q.worldedit.command.GenerationCommands;
import com.sk89q.worldedit.command.HistoryCommands;
//import com.sk89q.worldedit.command.MaskCommands;
import com.sk89q.worldedit.command.NavigationCommands;
//import com.sk89q.worldedit.command.PatternCommands;
import com.sk89q.worldedit.command.RegionCommands;
import com.sk89q.worldedit.command.SchematicCommands;
import com.sk89q.worldedit.command.ScriptingCommands;
import com.sk89q.worldedit.command.SelectionCommands;
import com.sk89q.worldedit.command.SnapshotCommands;
import com.sk89q.worldedit.command.SnapshotUtilCommands;
import com.sk89q.worldedit.command.SuperPickaxeCommands;
import com.sk89q.worldedit.command.ToolCommands;
//import com.sk89q.worldedit.command.TransformCommands;
import com.sk89q.worldedit.command.UtilityCommands;
import com.sk89q.worldedit.command.WorldEditCommands;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.annotation.param.Switch;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public final class DocumentationPrinter {
private DocumentationPrinter() {
}
/**
* Generates documentation.
*
* @param args arguments
* @throws IOException thrown on I/O error
*/
public static void main(String[] args) throws IOException {
writePermissionsWikiTable();
}
private static void writePermissionsWikiTable()
throws IOException {
try (FileOutputStream fos = new FileOutputStream("wiki_permissions.md")) {
PrintStream stream = new PrintStream(fos);
stream.print("## Overview\n");
stream.print("This page is generated from the source. " +
"Click one of the edit buttons below to modify a command class. " +
"You will need to find the parts which correspond to the documentation. " +
"Command documentation will be consistent with what is available ingame");
stream.println();
stream.println();
stream.print("To view this information ingame use `//help [category|command]`\n");
stream.print("## Command Syntax \n");
stream.print(" - `<arg>` - A required parameter \n");
stream.print(" - `[arg]` - An optional parameter \n");
stream.print(" - `<arg1|arg2>` - Multiple parameters options \n");
stream.print(" - `<arg=value>` - Default or suggested value \n");
stream.print(" - `-a` - A command flag e.g., `//<command> -a [flag-value]`");
stream.println();
stream.print("## See also\n");
stream.print(" - [Masks](https://github.com/boy0001/FastAsyncWorldedit/wiki/WorldEdit---FAWE-mask-list)\n");
stream.print(" - [Patterns](https://github.com/boy0001/FastAsyncWorldedit/wiki/WorldEdit-and-FAWE-patterns)\n");
stream.print(" - [Transforms](https://github.com/boy0001/FastAsyncWorldedit/wiki/Transforms)\n");
stream.println();
stream.print("## Content");
stream.println();
stream.print("Click on a category to go to the list of commands, or `More Info` for detailed descriptions ");
stream.println();
StringBuilder builder = new StringBuilder();
writePermissionsWikiTable(stream, builder, "/we ", WorldEditCommands.class);
writePermissionsWikiTable(stream, builder, "/", UtilityCommands.class);
writePermissionsWikiTable(stream, builder, "/", RegionCommands.class);
writePermissionsWikiTable(stream, builder, "/", SelectionCommands.class);
writePermissionsWikiTable(stream, builder, "/", HistoryCommands.class);
writePermissionsWikiTable(stream, builder, "/schematic ", SchematicCommands.class);
writePermissionsWikiTable(stream, builder, "/", ClipboardCommands.class);
writePermissionsWikiTable(stream, builder, "/", GenerationCommands.class);
writePermissionsWikiTable(stream, builder, "/", BiomeCommands.class);
writePermissionsWikiTable(stream, builder, "/anvil ", AnvilCommands.class);
writePermissionsWikiTable(stream, builder, "/sp ", SuperPickaxeCommands.class);
writePermissionsWikiTable(stream, builder, "/", NavigationCommands.class);
writePermissionsWikiTable(stream, builder, "/snapshot", SnapshotCommands.class);
writePermissionsWikiTable(stream, builder, "/", SnapshotUtilCommands.class);
writePermissionsWikiTable(stream, builder, "/", ScriptingCommands.class);
writePermissionsWikiTable(stream, builder, "/", ChunkCommands.class);
writePermissionsWikiTable(stream, builder, "/", ToolUtilCommands.class);
writePermissionsWikiTable(stream, builder, "/tool ", ToolCommands.class);
writePermissionsWikiTable(stream, builder, "/brush ", BrushCommands.class);
//writePermissionsWikiTable(stream, builder, "", MaskCommands.class, "/Masks");
//writePermissionsWikiTable(stream, builder, "", PatternCommands.class, "/Patterns");
//writePermissionsWikiTable(stream, builder, "", TransformCommands.class, "/Transforms");
writePermissionsWikiTable(stream, builder, "/cfi ", CFICommands.class, "Create From Image");
stream.println();
stream.print("#### Uncategorized\n");
stream.append("| Aliases | Permission | flags | Usage |\n");
stream.append("| --- | --- | --- | --- |\n");
stream.append("| //cancel | fawe.cancel | | Cancels your current operations |\n");
stream.append("| /plot replaceall | plots.replaceall | | Replace all blocks in the plot world |\n");
// stream.append("| /plot createfromimage | plots.createfromimage | | Starts world creation from a heightmap image: [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/CreateFromImage) |\n");
stream.print("\n---\n");
stream.print(builder);
}
}
private static void writePermissionsWikiTable(PrintStream stream, StringBuilder content, String prefix, Class<?> cls) {
writePermissionsWikiTable(stream, content, prefix, cls, getName(cls));
}
public static String getName(Class cls) {
return cls.getSimpleName().replaceAll("(\\p{Ll})(\\p{Lu})", "$1 $2");
}
private static void writePermissionsWikiTable(PrintStream stream, StringBuilder content, String prefix, Class<?> cls, String name) {
stream.print(" - [`" + name + "`](#" + name.replaceAll(" ", "-").replaceAll("/", "").toLowerCase() + "-edittop) ");
Command cmd = cls.getAnnotation(Command.class);
if (cmd != null) {
stream.print(" (" + cmd.desc() + ")");
}
stream.println();
writePermissionsWikiTable(content, prefix, cls, name, true);
}
private static void writePermissionsWikiTable(StringBuilder stream, String prefix, Class<?> cls, String name, boolean title) {
if (title) {
String path = "https://github.com/boy0001/FastAsyncWorldedit/edit/master/core/src/main/java/" + cls.getName().replaceAll("\\.", "/") + ".java";
stream.append("### **" + name + "** `[`[`edit`](" + path + ")`|`[`top`](#overview)`]`");
stream.append("\n");
Command cmd = cls.getAnnotation(Command.class);
if (cmd != null) {
if (!cmd.desc().isEmpty()) {
stream.append("> (" + (cmd.desc()) + ") \n");
}
if (!cmd.descFooter().isEmpty()) {
stream.append("" + (cmd.descFooter()) + " \n");
}
}
stream.append("\n");
stream.append("---");
stream.append("\n");
stream.append("\n");
}
for (Method method : cls.getMethods()) {
if (!method.isAnnotationPresent(Command.class)) {
continue;
}
Command cmd = method.getAnnotation(Command.class);
String[] aliases = cmd.aliases();
String usage = prefix + aliases[0] + " " + getUsage(cmd, method);
stream.append("#### `" + usage + "`\n");
if (method.isAnnotationPresent(CommandPermissions.class)) {
CommandPermissions perms = method.getAnnotation(CommandPermissions.class);
stream.append("**Perm**: `" + StringMan.join(perms.value(), "`, `") + "` \n");
}
String help = getDesc(cmd, method);
stream.append("**Desc**: " + help.trim().replaceAll("\n", "<br />") + " \n");
if (method.isAnnotationPresent(NestedCommand.class)) {
NestedCommand nested =
method.getAnnotation(NestedCommand.class);
Class<?>[] nestedClasses = nested.value();
for (Class clazz : nestedClasses) {
writePermissionsWikiTable(stream, prefix + cmd.aliases()[0] + " ", clazz, getName(clazz), false);
}
}
}
stream.append("\n");
if (title) stream.append("---");
stream.append("\n");
stream.append("\n");
}
public static String getDesc(Command command, Method method) {
Parameter[] params = method.getParameters();
List<String> desc = new ArrayList<>();
for (Parameter param : params) {
String[] info = getParamInfo(param);
if (info != null) {
desc.add(info[0].replace("%s0", info[1]) + " - " + info[2] + ": " + info[3]);
}
}
String footer = command.descFooter();
if (!footer.isEmpty()) footer += "\n";
return footer + StringMan.join(desc, "\n");
}
public static String getUsage(Command command, Method method) {
Parameter[] params = method.getParameters();
List<String> usage = new ArrayList<>();
for (Parameter param : params) {
String[] info = getParamInfo(param);
if (info != null) {
usage.add(info[0].replace("%s0", info[1]));
}
}
return StringMan.join(usage, " ");
}
/*
Return format, name, type, description
*/
public static String[] getParamInfo(Parameter param) {
Switch switchAnn = param.getAnnotation(Switch.class);
Arg argAnn = param.getAnnotation(Arg.class);
Range rangeAnn = param.getAnnotation(Range.class);
Step stepAnn = param.getAnnotation(Step.class);
if (switchAnn != null || argAnn != null || rangeAnn != null || stepAnn != null) {
String[] result = new String[] { "[%s0]", param.getName(), param.getType().getSimpleName(), ""};
boolean optional = argAnn != null && argAnn.def().length != 0;
if (optional) {
result[0] = "<%s0>";
}
if (argAnn != null) result[1] = argAnn.name();
if (argAnn != null) {
if (argAnn.def().length != 0) {
result[0] = result[0].replace("%s0", "%s0=" + argAnn.def());
}
result[3] = argAnn.desc();
} else if (switchAnn != null) {
result[0] = result[0].replace("%s0", "-" + switchAnn.name() + " %s0");
}
if (switchAnn != null) result[3] = switchAnn.desc();
if (rangeAnn != null) {
String step;
String min = rangeAnn.min() == Double.MIN_VALUE ? "(-∞" : ("[" + rangeAnn.min());
String max = rangeAnn.max() == Double.MAX_VALUE ? "∞)" : (rangeAnn.max() + "]");
result[0] += min + "," + max;
}
if (stepAnn != null) {
result[0] += "" + stepAnn.value();
}
return result;
}
return null;
}
public static Collection<ArgFlag> getFlags(Command command, Method method) {
Parameter[] params = method.getParameters();
List<ArgFlag> flags = new ArrayList<>();
for (Parameter param : params) {
ArgFlag flagAnn = param.getAnnotation(ArgFlag.class);
if (flagAnn != null) flags.add(flagAnn);
}
return flags;
}
}

View File

@ -3,7 +3,7 @@ package com.sk89q.jnbt;
import com.boydti.fawe.object.io.FastByteArrayOutputStream; import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.boydti.fawe.object.io.FastByteArraysInputStream; import com.boydti.fawe.object.io.FastByteArraysInputStream;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.SpongeSchematicWriter; import com.sk89q.worldedit.extent.clipboard.io.FastSchematicWriter;
import net.jpountz.lz4.LZ4BlockInputStream; import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream; import net.jpountz.lz4.LZ4BlockOutputStream;
@ -19,7 +19,7 @@ public class CompressedSchematicTag extends CompressedCompoundTag<Clipboard> {
FastByteArrayOutputStream blocksOut = new FastByteArrayOutputStream(); FastByteArrayOutputStream blocksOut = new FastByteArrayOutputStream();
try (LZ4BlockOutputStream lz4out = new LZ4BlockOutputStream(blocksOut)) { try (LZ4BlockOutputStream lz4out = new LZ4BlockOutputStream(blocksOut)) {
NBTOutputStream nbtOut = new NBTOutputStream(lz4out); NBTOutputStream nbtOut = new NBTOutputStream(lz4out);
new SpongeSchematicWriter(nbtOut).write(getSource()); new FastSchematicWriter(nbtOut).write(getSource());
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@ -135,6 +135,7 @@ import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.registry.LegacyMapper;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -1427,8 +1428,22 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
} }
/** /**
* Stack a cuboid region. For compatibility, entities are copied but biomes are not. * Stack a cuboid region. For compatibility, entities are copied by biomes are not.
* Use {@link #stackCuboidRegion(Region, BlockVector3, int, boolean, boolean, boolean)} to fine tune. * Use {@link #stackCuboidRegion(Region, BlockVector3, int, boolean, boolean, Mask)} to fine tune.
*
* @param region the region to stack
* @param dir the direction to stack
* @param count the number of times to stack
* @param copyAir true to also copy air blocks
* @return number of blocks affected
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int stackCuboidRegion(Region region, BlockVector3 dir, int count, boolean copyAir) throws MaxChangedBlocksException {
return stackCuboidRegion(region, dir, count, true, false, copyAir ? null : new ExistingBlockMask(this));
}
/**
* Stack a cuboid region.
* *
* @param region the region to stack * @param region the region to stack
* @param dir the direction to stack * @param dir the direction to stack
@ -1439,7 +1454,8 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* @return number of blocks affected * @return number of blocks affected
* @throws MaxChangedBlocksException thrown if too many blocks are changed * @throws MaxChangedBlocksException thrown if too many blocks are changed
*/ */
public int stackCuboidRegion(Region region, BlockVector3 dir, int count, boolean copyAir, boolean copyEntities, boolean copyBiomes) throws MaxChangedBlocksException { public int stackCuboidRegion(Region region, BlockVector3 dir, int count,
boolean copyEntities, boolean copyBiomes, Mask mask) throws MaxChangedBlocksException {
checkNotNull(region); checkNotNull(region);
checkNotNull(dir); checkNotNull(dir);
checkArgument(count >= 1, "count >= 1 required"); checkArgument(count >= 1, "count >= 1 required");
@ -1451,14 +1467,10 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
copy.setCopyingBiomes(copyBiomes); copy.setCopyingBiomes(copyBiomes);
copy.setRepetitions(count); copy.setRepetitions(count);
copy.setTransform(new AffineTransform().translate(dir.multiply(size))); copy.setTransform(new AffineTransform().translate(dir.multiply(size)));
Mask sourceMask = getSourceMask(); mask = MaskIntersection.of(getSourceMask(), mask).optimize();
if (sourceMask != null) { if (mask != Masks.alwaysTrue()) {
new MaskTraverser(sourceMask).reset(EditSession.this);
copy.setSourceMask(sourceMask);
setSourceMask(null); setSourceMask(null);
} copy.setSourceMask(mask);
if (!copyAir) {
copy.setSourceMask(new ExistingBlockMask(this));
} }
Operations.completeBlindly(copy); Operations.completeBlindly(copy);
return this.changes = copy.getAffected(); return this.changes = copy.getAffected();
@ -2327,15 +2339,15 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* @throws MaxChangedBlocksException * @throws MaxChangedBlocksException
*/ */
public int makeShape(final Region region, final Vector3 zero, final Vector3 unit, public int makeShape(final Region region, final Vector3 zero, final Vector3 unit,
final Pattern pattern, final String expressionString, final boolean hollow, final int timeout) final Pattern pattern, final String expressionString, final boolean hollow, final int timeout)
throws ExpressionException, MaxChangedBlocksException { throws ExpressionException, MaxChangedBlocksException {
final Expression expression = Expression.compile(expressionString, "x", "y", "z", "type", "data"); final Expression expression = Expression.compile(expressionString, "x", "y", "z", "type", "data");
expression.optimize(); expression.optimize();
final Variable typeVariable = expression.getSlots().getVariable("type") final Variable typeVariable = expression.getSlots().getVariable("type")
.orElseThrow(IllegalStateException::new); .orElseThrow(IllegalStateException::new);
final Variable dataVariable = expression.getSlots().getVariable("data") final Variable dataVariable = expression.getSlots().getVariable("data")
.orElseThrow(IllegalStateException::new); .orElseThrow(IllegalStateException::new);
final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero); final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero);
expression.setEnvironment(environment); expression.setEnvironment(environment);
@ -2349,12 +2361,26 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
final Vector3 scaled = current.subtract(zero).divide(unit); final Vector3 scaled = current.subtract(zero).divide(unit);
try { try {
if (expression.evaluateTimeout(timeout, scaled.getX(), scaled.getY(), scaled.getZ(), defaultMaterial.getBlockType().getInternalId(), defaultMaterial.getInternalPropertiesId()) <= 0) { int[] legacy = LegacyMapper.getInstance().getLegacyFromBlock(defaultMaterial.toImmutableState());
// TODO data int typeVar = 0;
int dataVar = 0;
if (legacy != null) {
typeVar = legacy[0];
if (legacy.length > 1) {
dataVar = legacy[1];
}
}
if (expression.evaluate(new double[]{scaled.getX(), scaled.getY(), scaled.getZ(), typeVar, dataVar}, timeout) <= 0) {
return null; return null;
} }
int newType = (int) typeVariable.getValue();
return BlockTypes.get((int) typeVariable.getValue()).withPropertyId((int) dataVariable.getValue()).toBaseBlock(); int newData = (int) dataVariable.getValue();
if (newType != typeVar || newData != dataVar) {
BlockState state = LegacyMapper.getInstance().getBlockFromLegacy(newType, newData);
return state == null ? defaultMaterial : state.toBaseBlock();
} else {
return defaultMaterial;
}
} catch (ExpressionTimeoutException e) { } catch (ExpressionTimeoutException e) {
timedOut[0] = timedOut[0] + 1; timedOut[0] = timedOut[0] + 1;
return null; return null;
@ -2404,7 +2430,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
final Vector3 scaled = position.toVector3().subtract(zero).divide(unit); final Vector3 scaled = position.toVector3().subtract(zero).divide(unit);
// transform // transform
expression.evaluateTimeout(timeout, scaled.getX(), scaled.getY(), scaled.getZ()); expression.evaluate(new double[]{scaled.getX(), scaled.getY(), scaled.getZ()}, timeout);
int xv = (int) (x.getValue() * unit.getX() + zero2.getX()); int xv = (int) (x.getValue() * unit.getX() + zero2.getX());
int yv = (int) (y.getValue() * unit.getY() + zero2.getY()); int yv = (int) (y.getValue() * unit.getY() + zero2.getY());
int zv = (int) (z.getValue() * unit.getZ() + zero2.getZ()); int zv = (int) (z.getValue() * unit.getZ() + zero2.getZ());

View File

@ -78,6 +78,7 @@ import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.snapshot.Snapshot; import com.sk89q.worldedit.world.snapshot.Snapshot;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.io.File; import java.io.File;
@ -147,7 +148,6 @@ public class LocalSession implements TextureHolder {
private transient ResettableExtent transform = null; private transient ResettableExtent transform = null;
private transient ZoneId timezone = ZoneId.systemDefault(); private transient ZoneId timezone = ZoneId.systemDefault();
private transient World currentWorld; private transient World currentWorld;
private transient boolean tickingWatchdog = false;
private transient UUID uuid; private transient UUID uuid;
private transient volatile long historySize = 0; private transient volatile long historySize = 0;
@ -992,6 +992,8 @@ public class LocalSession implements TextureHolder {
return getTool(item, player); return getTool(item, player);
} }
private transient boolean loadDefaults = true;
public Tool getTool(BaseItem item, Player player) { public Tool getTool(BaseItem item, Player player) {
if (Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES && item.getNativeItem() != null) { if (Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES && item.getNativeItem() != null) {
BrushTool tool = BrushCache.getTool(player, this, item); BrushTool tool = BrushCache.getTool(player, this, item);
@ -1612,7 +1614,9 @@ public class LocalSession implements TextureHolder {
private void prepareEditingExtents(EditSession editSession, Actor actor) { private void prepareEditingExtents(EditSession editSession, Actor actor) {
editSession.setFastMode(fastMode); editSession.setFastMode(fastMode);
/*
editSession.setReorderMode(reorderMode); editSession.setReorderMode(reorderMode);
*/
if (editSession.getSurvivalExtent() != null) { if (editSession.getSurvivalExtent() != null) {
editSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt")); editSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt"));
} }

View File

@ -43,8 +43,6 @@ import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.runtime.Constant;
import com.sk89q.worldedit.internal.expression.runtime.RValue;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.scripting.CraftScriptContext; import com.sk89q.worldedit.scripting.CraftScriptContext;
import com.sk89q.worldedit.scripting.CraftScriptEngine; import com.sk89q.worldedit.scripting.CraftScriptEngine;
@ -397,8 +395,8 @@ public final class WorldEdit {
public void checkMaxBrushRadius(Expression radius) throws MaxBrushRadiusException { public void checkMaxBrushRadius(Expression radius) throws MaxBrushRadiusException {
if (getConfiguration().maxBrushRadius > 0) { if (getConfiguration().maxBrushRadius > 0) {
RValue r = radius.getRoot(); double val = radius.evaluate();
if (r instanceof Constant && ((Constant) r).getValue() > getConfiguration().maxBrushRadius) { if (val > getConfiguration().maxBrushRadius) {
throw new MaxBrushRadiusException(); throw new MaxBrushRadiusException();
} }
} }

View File

@ -97,7 +97,7 @@ public class ApplyBrushCommands {
Contextual<? extends RegionFunction> generatorFactory) throws WorldEditException { Contextual<? extends RegionFunction> generatorFactory) throws WorldEditException {
double radius = requireNonNull(RADIUS.value(parameters).asSingle(double.class)); double radius = requireNonNull(RADIUS.value(parameters).asSingle(double.class));
RegionFactory regionFactory = REGION_FACTORY.value(parameters).asSingle(RegionFactory.class); RegionFactory regionFactory = REGION_FACTORY.value(parameters).asSingle(RegionFactory.class);
BrushCommands.setOperationBasedBrush(player, localSession, new Expression(radius), BrushCommands.setOperationBasedBrush(player, localSession, Expression.compile(Double.toString(radius)),
new Apply(generatorFactory), regionFactory, "worldedit.brush.apply"); new Apply(generatorFactory), regionFactory, "worldedit.brush.apply");
} }

View File

@ -42,6 +42,7 @@ import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.visitor.FlatRegionVisitor; import com.sk89q.worldedit.function.visitor.FlatRegionVisitor;
import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.FlatRegion; import com.sk89q.worldedit.regions.FlatRegion;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;

View File

@ -98,9 +98,8 @@ import com.sk89q.worldedit.function.mask.SingleBlockTypeMask;
import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.annotation.ClipboardMask; import com.sk89q.worldedit.internal.annotation.ClipboardMask;
import com.sk89q.worldedit.internal.annotation.Range; import com.sk89q.worldedit.internal.expression.EvaluationException;
import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.factory.RegionFactory; import com.sk89q.worldedit.regions.factory.RegionFactory;
@ -133,6 +132,7 @@ import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.annotation.param.Switch; import org.enginehub.piston.annotation.param.Switch;
import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key; import org.enginehub.piston.inject.Key;
import org.jetbrains.annotations.Range;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
@ -308,7 +308,7 @@ public class BrushCommands {
) )
@CommandPermissions("worldedit.brush.spline") @CommandPermissions("worldedit.brush.spline")
public void catenaryBrush(InjectedValueAccess context, @Arg(desc = "Pattern") Pattern fill, public void catenaryBrush(InjectedValueAccess context, @Arg(desc = "Pattern") Pattern fill,
@Arg(def = "1.2", desc = "Length of wire compared to distance between points") @Range(min = 1) double lengthFactor, @Arg(def = "1.2", desc = "Length of wire compared to distance between points") @Range(from = 1, to=Integer.MAX_VALUE) double lengthFactor,
@Arg(desc = "The radius to sample for blending", def = "0") @Arg(desc = "The radius to sample for blending", def = "0")
Expression radius, Expression radius,
@Switch(name = 'h', desc = "Create only a shell") @Switch(name = 'h', desc = "Create only a shell")
@ -439,7 +439,7 @@ public class BrushCommands {
public void stencilBrush(LocalSession session, InjectedValueAccess context, @Arg(desc = "Pattern") Pattern fill, public void stencilBrush(LocalSession session, InjectedValueAccess context, @Arg(desc = "Pattern") Pattern fill,
@Arg(desc = "Expression", def = "5") Expression radius, @Arg(desc = "Expression", def = "5") Expression radius,
@Arg(desc = "String", def = "") String image, @Arg(desc = "String", def = "") String image,
@Arg(def = "0", desc = "rotation") @Range(min = 0, max = 360) int rotation, @Arg(def = "0", desc = "rotation") @Range(from=0, to=360) int rotation,
@Arg(desc = "double", def = "1") double yscale, @Arg(desc = "double", def = "1") double yscale,
@Switch(name = 'w', desc = "Apply at maximum saturation") boolean onlyWhite, @Switch(name = 'w', desc = "Apply at maximum saturation") boolean onlyWhite,
@Switch(name = 'r', desc = "Apply random rotation") boolean randomRotate) throws WorldEditException, FileNotFoundException { @Switch(name = 'r', desc = "Apply random rotation") boolean randomRotate) throws WorldEditException, FileNotFoundException {
@ -470,7 +470,7 @@ public class BrushCommands {
@Arg(desc = "Expression", def = "5") @Arg(desc = "Expression", def = "5")
Expression radius, Expression radius,
ProvideBindings.ImageUri imageUri, ProvideBindings.ImageUri imageUri,
@Arg(def = "1", desc = "scale height") @Range(min = Double.MIN_NORMAL) @Arg(def = "1", desc = "scale height")
double yscale, double yscale,
@Switch(name = 'a', desc = "Use image Alpha") @Switch(name = 'a', desc = "Use image Alpha")
boolean alpha, boolean alpha,
@ -660,13 +660,14 @@ public class BrushCommands {
boolean ignoreAir, boolean ignoreAir,
@Switch(name = 'o', desc = "Paste starting at the target location, instead of centering on it") @Switch(name = 'o', desc = "Paste starting at the target location, instead of centering on it")
boolean usingOrigin, boolean usingOrigin,
@Switch(name = 'e', desc = "Paste entities if available") @Switch(name = 'e', desc = "Skip paste entities if available")
boolean pasteEntities, boolean skipEntities,
@Switch(name = 'b', desc = "Paste biomes if available") @Switch(name = 'b', desc = "Paste biomes if available")
boolean pasteBiomes, boolean pasteBiomes,
@ArgFlag(name = 'm', desc = "Skip blocks matching this mask in the clipboard", def = "") @ArgFlag(name = 'm', desc = "Skip blocks matching this mask in the clipboard", def = "")
@ClipboardMask @ClipboardMask
Mask sourceMask) throws WorldEditException { Mask sourceMask,
InjectedValueAccess context) throws WorldEditException {
ClipboardHolder holder = session.getClipboard(); ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard(); Clipboard clipboard = holder.getClipboard();
@ -695,7 +696,8 @@ public class BrushCommands {
@Arg(desc = "The number of iterations to perform", def = "4") @Arg(desc = "The number of iterations to perform", def = "4")
int iterations, int iterations,
@Arg(desc = "The mask of blocks to use for the heightmap", def = "") @Arg(desc = "The mask of blocks to use for the heightmap", def = "")
Mask maskOpt) throws WorldEditException { Mask maskOpt,
InjectedValueAccess context) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius); worldEdit.checkMaxBrushRadius(radius);
FaweLimit limit = Settings.IMP.getLimit(player); FaweLimit limit = Settings.IMP.getLimit(player);
@ -752,7 +754,7 @@ public class BrushCommands {
"Snow Pic: https://i.imgur.com/Hrzn0I4.png" "Snow Pic: https://i.imgur.com/Hrzn0I4.png"
) )
@CommandPermissions("worldedit.brush.height") @CommandPermissions("worldedit.brush.height")
public void heightBrush(LocalSession session, @Arg(desc = "Expression", def = "5") Expression radius, @Arg(desc = "String", def = "") String image, @Arg(def = "0", desc = "rotation") @Range(min = 0, max = 360) int rotation, @Arg(desc = "double", def = "1") double yscale, @Switch(name = 'r', desc = "TODO") boolean randomRotate, @Switch(name = 'l', desc = "TODO") boolean layers, @Switch(name = 's', desc = "TODO") boolean dontSmooth, InjectedValueAccess context) throws WorldEditException, FileNotFoundException { public void heightBrush(LocalSession session, @Arg(desc = "Expression", def = "5") Expression radius, @Arg(desc = "String", def = "") String image, @Arg(def = "0", desc = "rotation") @Range(from = 0, to = 360) int rotation, @Arg(desc = "double", def = "1") double yscale, @Switch(name = 'r', desc = "TODO") boolean randomRotate, @Switch(name = 'l', desc = "TODO") boolean layers, @Switch(name = 's', desc = "TODO") boolean dontSmooth, InjectedValueAccess context) throws WorldEditException, FileNotFoundException {
terrainBrush(session, radius, image, rotation, yscale, false, randomRotate, layers, !dontSmooth, ScalableHeightMap.Shape.CONE, context); terrainBrush(session, radius, image, rotation, yscale, false, randomRotate, layers, !dontSmooth, ScalableHeightMap.Shape.CONE, context);
} }
@ -768,7 +770,7 @@ public class BrushCommands {
Expression radius, Expression radius,
@Arg(desc = "String", def = "") @Arg(desc = "String", def = "")
String image, String image,
@Arg(def = "0", desc = "rotation") @Step(90) @Range(min = 0, max = 360) @Arg(def = "0", desc = "rotation") @Step(90) @Range(from = 0, to = 360)
int rotation, int rotation,
@Arg(desc = "double", def = "1") @Arg(desc = "double", def = "1")
double yscale, double yscale,
@ -787,7 +789,7 @@ public class BrushCommands {
desc = "This brush raises or lowers land towards the clicked point" desc = "This brush raises or lowers land towards the clicked point"
) )
@CommandPermissions("worldedit.brush.height") @CommandPermissions("worldedit.brush.height")
public void flattenBrush(LocalSession session, @Arg(desc = "Expression", def = "5") Expression radius, @Arg(desc = "String", def = "") String image, @Arg(def = "0", desc = "rotation") @Step(90) @Range(min = 0, max = 360) int rotation, @Arg(desc = "double", def = "1") double yscale, public void flattenBrush(LocalSession session, @Arg(desc = "Expression", def = "5") Expression radius, @Arg(desc = "String", def = "") String image, @Arg(def = "0", desc = "rotation") @Step(90) @Range(from = 0, to = 360) int rotation, @Arg(desc = "double", def = "1") double yscale,
@Switch(name = 'r', desc = "Enables random off-axis rotation") @Switch(name = 'r', desc = "Enables random off-axis rotation")
boolean randomRotate, boolean randomRotate,
@Switch(name = 'l', desc = "Will work on snow layers") @Switch(name = 'l', desc = "Will work on snow layers")

View File

@ -39,10 +39,12 @@ import com.boydti.fawe.util.MaskTraverser;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.extent.PasteEvent; import com.sk89q.worldedit.event.extent.PasteEvent;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
@ -314,8 +316,8 @@ public class ClipboardCommands {
} }
} }
final LocalConfiguration config = this.worldEdit.getConfiguration(); final LocalConfiguration config = WorldEdit.getInstance().getConfiguration();
final File working = this.worldEdit.getWorkingDirectoryFile(config.saveDir).getAbsoluteFile(); final File working = WorldEdit.getInstance().getWorkingDirectoryFile(config.saveDir).getAbsoluteFile();
url = MainUtil.upload(null, null, "zip", new RunnableVal<OutputStream>() { url = MainUtil.upload(null, null, "zip", new RunnableVal<OutputStream>() {
@Override @Override
@ -484,7 +486,7 @@ public class ClipboardCommands {
uri = ((URIClipboardHolder) holder).getURI(clipboard); uri = ((URIClipboardHolder) holder).getURI(clipboard);
} }
PasteEvent event = new PasteEvent(player, clipboard, uri, editSession, to); PasteEvent event = new PasteEvent(player, clipboard, uri, editSession, to);
worldEdit.getEventBus().post(event); WorldEdit.getInstance().getEventBus().post(event);
if (event.isCancelled()) { if (event.isCancelled()) {
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MANUAL); throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MANUAL);
} }

View File

@ -342,7 +342,7 @@ public class GeneralCommands {
desc = "Set the global mask" desc = "Set the global mask"
) )
@CommandPermissions("worldedit.global-texture") @CommandPermissions("worldedit.global-texture")
public void gtexture(Player player, World world, LocalSession session, EditSession editSession, @Arg(name = "context", desc = "InjectedValueAccess", def = "") List<String> arguments) throws WorldEditException, FileNotFoundException { public void gtexture(Player player, World worldArg, LocalSession session, EditSession editSession, @Arg(name = "context", desc = "InjectedValueAccess", def = "") List<String> arguments) throws WorldEditException, FileNotFoundException {
// gtexture <randomize> <min=0> <max=100> // gtexture <randomize> <min=0> <max=100>
// TODO NOT IMPLEMENTED convert this to an ArgumentConverter // TODO NOT IMPLEMENTED convert this to an ArgumentConverter
if (arguments.isEmpty()) { if (arguments.isEmpty()) {
@ -375,7 +375,7 @@ public class GeneralCommands {
} else { } else {
ParserContext parserContext = new ParserContext(); ParserContext parserContext = new ParserContext();
parserContext.setActor(player); parserContext.setActor(player);
parserContext.setWorld(world); parserContext.setWorld(worldArg);
parserContext.setSession(session); parserContext.setSession(session);
parserContext.setExtent(editSession); parserContext.setExtent(editSession);
Mask mask = worldEdit.getMaskFactory().parseFromInput(arg, parserContext); Mask mask = worldEdit.getMaskFactory().parseFromInput(arg, parserContext);

View File

@ -47,8 +47,8 @@ import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.internal.annotation.Radii; import com.sk89q.worldedit.internal.annotation.Radii;
import com.sk89q.worldedit.internal.annotation.Range;
import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.internal.annotation.Selection;
import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
@ -69,6 +69,7 @@ import org.enginehub.piston.annotation.param.Switch;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.InjectedValueAccess;
import org.jetbrains.annotations.Range;
/** /**
* Commands for the generation of shapes and other objects. * Commands for the generation of shapes and other objects.
@ -173,7 +174,7 @@ public class GenerationCommands {
) )
@CommandPermissions("worldedit.generation.ore") @CommandPermissions("worldedit.generation.ore")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void ore(Actor actor, LocalSession session, EditSession editSession, @Selection Region region, @Arg(desc = "Mask") Mask mask, @Arg(desc = "Pattern") Pattern material, @Arg(desc="Ore vein size") @Range(min = 0) int size, int freq, @Range(min = 0, max = 100) int rarity, @Range(min = 0, max = 255) int minY, @Range(min = 0, max = 255) int maxY, InjectedValueAccess context) throws WorldEditException { public void ore(Actor actor, LocalSession session, EditSession editSession, @Selection Region region, @Arg(desc = "Mask") Mask mask, @Arg(desc = "Pattern") Pattern material, @Arg(desc="Ore vein size") @Range(from = 0, to=Integer.MAX_VALUE) int size, int freq, @Range(from=0, to=100) int rarity, @Range(from=0, to=255) int minY, @Range(from=0, to=255) int maxY, InjectedValueAccess context) throws WorldEditException {
actor.checkConfirmationRegion(() -> { actor.checkConfirmationRegion(() -> {
editSession.addOre(region, mask, material, size, freq, rarity, minY, maxY); editSession.addOre(region, mask, material, size, freq, rarity, minY, maxY);
BBC.VISITOR_BLOCK.send(actor, editSession.getBlockChangeCount()); BBC.VISITOR_BLOCK.send(actor, editSession.getBlockChangeCount());
@ -186,15 +187,14 @@ public class GenerationCommands {
) )
@CommandPermissions("worldedit.generation.cylinder") @CommandPermissions("worldedit.generation.cylinder")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int hcyl(Actor actor, LocalSession session, EditSession editSession, public void hcyl(Actor actor, LocalSession session, EditSession editSession, InjectedValueAccess context,
@Arg(desc = "The pattern of blocks to generate") @Arg(desc = "The pattern of blocks to generate")
Pattern pattern, Pattern pattern,
@Arg(desc = "The radii of the cylinder. 1st is N/S, 2nd is E/W") @Arg(desc = "The radii of the cylinder. 1st is N/S, 2nd is E/W")
@Radii(2) BlockVector2 radii,
List<Double> radii,
@Arg(desc = "The height of the cylinder", def = "1") @Arg(desc = "The height of the cylinder", def = "1")
int height) throws WorldEditException { int height) throws WorldEditException {
return cyl(actor, session, editSession, pattern, radii, height, true); cyl(actor, session, editSession, pattern, radii, height, true, context);
} }
@Command( @Command(
@ -206,7 +206,7 @@ public class GenerationCommands {
public void cyl(Actor actor, LocalSession session, EditSession editSession, public void cyl(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to generate") @Arg(desc = "The pattern of blocks to generate")
Pattern pattern, Pattern pattern,
@Arg(desc = "The radii of the cylinder. Order is N/S, E/W") BlockVector2 radius, @Arg(desc = "The radii of the cylinder. Order is N/S, E/W") BlockVector2 radius,
@Arg(desc = "The height of the cylinder", def = "1") @Arg(desc = "The height of the cylinder", def = "1")
int height, int height,
@Switch(name = 'h', desc = "Make a hollow cylinder") @Switch(name = 'h', desc = "Make a hollow cylinder")
@ -293,9 +293,12 @@ public class GenerationCommands {
@Logging(POSITION) @Logging(POSITION)
public int pumpkins(Actor actor, LocalSession session, EditSession editSession, public int pumpkins(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The size of the patch", def = "10") @Arg(desc = "The size of the patch", def = "10")
int size) throws WorldEditException { int size,
@Arg(desc = "//TODO ", def = "0.02")
double density) throws WorldEditException {
checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100");
worldEdit.checkMaxRadius(size); worldEdit.checkMaxRadius(size);
int affected = editSession.makePumpkinPatches(session.getPlacementPosition(actor), size); int affected = editSession.makePumpkinPatches(session.getPlacementPosition(actor), size, density);
actor.print(affected + " pumpkin patches created."); actor.print(affected + " pumpkin patches created.");
return affected; return affected;
} }

View File

@ -40,7 +40,6 @@ import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.annotation.Range;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
@ -54,6 +53,7 @@ import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch; import org.enginehub.piston.annotation.param.Switch;
import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.InjectedValueAccess;
import org.jetbrains.annotations.Range;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
@ -83,7 +83,7 @@ public class HistoryCommands {
" - Import from disk: /frb #import" " - Import from disk: /frb #import"
) )
@CommandPermissions("worldedit.history.rollback") @CommandPermissions("worldedit.history.rollback")
public void faweRollback(Player player, LocalSession session, @Arg(desc = "String user") String user, @Arg(def = "0", desc = "radius") @Range(min = 0) int radius, @Arg(name = "time", desc = "String", def = "0") String time, @Switch(name = 'r', desc = "TODO") boolean restore) throws WorldEditException { public void faweRollback(Player player, LocalSession session, @Arg(desc = "String user") String user, @Arg(def = "0", desc = "radius") @Range(from = 0, to=Integer.MAX_VALUE) int radius, @Arg(name = "time", desc = "String", def = "0") String time, @Switch(name = 'r', desc = "TODO") boolean restore) throws WorldEditException {
if (!Settings.IMP.HISTORY.USE_DATABASE) { if (!Settings.IMP.HISTORY.USE_DATABASE) {
BBC.SETTING_DISABLE.send(player, "history.use-database (Import with /frb #import )"); BBC.SETTING_DISABLE.send(player, "history.use-database (Import with /frb #import )");
return; return;
@ -214,32 +214,22 @@ public class HistoryCommands {
" - Import from disk: /frb #import" " - Import from disk: /frb #import"
) )
@CommandPermissions("worldedit.history.rollback") @CommandPermissions("worldedit.history.rollback")
public void restore(Player player, LocalSession session, @Arg(desc = "String user") String user, @Arg(def = "0", desc = "radius") @Range(min = 0) int radius, @Arg(name = "time", desc = "String", def = "0") String time) throws WorldEditException { public void restore(Player player, LocalSession session, @Arg(desc = "String user") String user, @Arg(def = "0", desc = "radius") int radius, @Arg(name = "time", desc = "String", def = "0") String time) throws WorldEditException {
faweRollback(player, session, user, radius, time, true); faweRollback(player, session, user, radius, time, true);
} }
@Command( @Command(
name = "/undo", name = "/undo",
aliases = { "/un", "/ud", "undo" }, aliases = { "/un", "/ud", "undo" },
desc = "Undoes the last action (from history)" desc = "Undoes the last action (from history)"
) )
} else {
undoSession = session;
}
int finalTimes = times;
player.checkConfirmation(() -> {
EditSession undone = null;
int i = 0;
for (; i < finalTimes; ++i) {
undone = undoSession.undo(undoSession.getBlockBag(player), player);
if (undone == null) break;
@CommandPermissions({"worldedit.history.undo", "worldedit.history.undo.self"}) @CommandPermissions({"worldedit.history.undo", "worldedit.history.undo.self"})
public void undo(Player player, LocalSession session, public void undo(Player player, LocalSession session,
@Range(min = 1) @Arg(desc = "Number of undoes to perform", def = "1") @Arg(desc = "Number of undoes to perform", def = "1")
int times, int times,
@Arg(name = "player", desc = "Undo this player's operations", def = "") @Arg(name = "player", desc = "Undo this player's operations", def = "")
String playerName, String playerName,
InjectedValueAccess context) throws WorldEditException { InjectedValueAccess context) throws WorldEditException {
times = Math.max(1, times); times = Math.max(1, times);
LocalSession undoSession; LocalSession undoSession;
if (session.hasFastMode()) { if (session.hasFastMode()) {
@ -253,6 +243,16 @@ public class HistoryCommands {
BBC.COMMAND_HISTORY_OTHER_ERROR.send(player, playerName); BBC.COMMAND_HISTORY_OTHER_ERROR.send(player, playerName);
return; return;
} }
} else {
undoSession = session;
}
int finalTimes = times;
player.checkConfirmation(() -> {
EditSession undone = null;
int i = 0;
for (; i < finalTimes; ++i) {
undone = undoSession.undo(undoSession.getBlockBag(player), player);
if (undone == null) break;
worldEdit.flushBlockBag(player, undone); worldEdit.flushBlockBag(player, undone);
} }
if (undone == null) i--; if (undone == null) i--;
@ -272,7 +272,7 @@ public class HistoryCommands {
) )
@CommandPermissions({"worldedit.history.redo", "worldedit.history.redo.self"}) @CommandPermissions({"worldedit.history.redo", "worldedit.history.redo.self"})
public void redo(Player player, LocalSession session, public void redo(Player player, LocalSession session,
@Range(min = 1) @Arg(desc = "Number of redoes to perform", def = "1") @Arg(desc = "Number of redoes to perform", def = "1")
int times, int times,
@Arg(name = "player", desc = "Redo this player's operations", def = "") @Arg(name = "player", desc = "Redo this player's operations", def = "")
String playerName) throws WorldEditException { String playerName) throws WorldEditException {

View File

@ -39,8 +39,8 @@ import com.sk89q.worldedit.function.mask.OffsetMask;
import com.sk89q.worldedit.function.mask.RegionMask; import com.sk89q.worldedit.function.mask.RegionMask;
import com.sk89q.worldedit.function.mask.SolidBlockMask; import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionEnvironment;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment;

View File

@ -104,7 +104,7 @@ public class PaintBrushCommands {
double radius = requireNonNull(RADIUS.value(parameters).asSingle(double.class)); double radius = requireNonNull(RADIUS.value(parameters).asSingle(double.class));
double density = requireNonNull(DENSITY.value(parameters).asSingle(double.class)) / 100; double density = requireNonNull(DENSITY.value(parameters).asSingle(double.class)) / 100;
RegionFactory regionFactory = REGION_FACTORY.value(parameters).asSingle(RegionFactory.class); RegionFactory regionFactory = REGION_FACTORY.value(parameters).asSingle(RegionFactory.class);
BrushCommands.setOperationBasedBrush(player, localSession, new Expression(radius), BrushCommands.setOperationBasedBrush(player, localSession, Expression.compile(Double.toString(radius)),
new Paint(generatorFactory, density), regionFactory, "worldedit.brush.paint"); new Paint(generatorFactory, density), regionFactory, "worldedit.brush.paint");
} }

View File

@ -46,7 +46,6 @@ import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.ClipboardPattern; import com.sk89q.worldedit.function.pattern.ClipboardPattern;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.pattern.RandomPattern; import com.sk89q.worldedit.function.pattern.RandomPattern;
import com.sk89q.worldedit.internal.annotation.Range;
import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
@ -61,6 +60,7 @@ import java.util.Set;
import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Arg;
import org.jetbrains.annotations.Range;
//@Command(aliases = {"patterns"}, //@Command(aliases = {"patterns"},
// desc = "Help for the various patterns. [More Info](https://git.io/vSPmA)", // desc = "Help for the various patterns. [More Info](https://git.io/vSPmA)",
@ -226,7 +226,7 @@ public class PatternCommands {
descFooter = "Use the pattern's id and the existing blocks data with the provided mask\n" + descFooter = "Use the pattern's id and the existing blocks data with the provided mask\n" +
" - Use to replace slabs or where the data values needs to be shifted instead of set" " - Use to replace slabs or where the data values needs to be shifted instead of set"
) )
public Pattern iddatamask(Extent extent, @Range(min = 0, max = 15) @Arg(desc = "bit mask") int bitmask, @Arg(desc = "Pattern")Pattern pattern) { public Pattern iddatamask(Extent extent, @Range(from = 0, to = 15) @Arg(desc = "bit mask") int bitmask, @Arg(desc = "Pattern")Pattern pattern) {
return new IdDataMaskPattern(extent, pattern, bitmask); return new IdDataMaskPattern(extent, pattern, bitmask);
} }

View File

@ -54,7 +54,6 @@ import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.FlatRegionVisitor; import com.sk89q.worldedit.function.visitor.FlatRegionVisitor;
import com.sk89q.worldedit.function.visitor.LayerVisitor; import com.sk89q.worldedit.function.visitor.LayerVisitor;
import com.sk89q.worldedit.internal.annotation.Direction; import com.sk89q.worldedit.internal.annotation.Direction;
import com.sk89q.worldedit.internal.annotation.Range;
import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.internal.annotation.Selection;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
@ -83,6 +82,7 @@ import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.annotation.param.Switch; import org.enginehub.piston.annotation.param.Switch;
import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.InjectedValueAccess;
import org.jetbrains.annotations.Range;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -254,7 +254,7 @@ public class RegionCommands {
desc = "Set block lighting in a selection" desc = "Set block lighting in a selection"
) )
@CommandPermissions("worldedit.light.set") @CommandPermissions("worldedit.light.set")
public void setlighting(Player player, EditSession editSession, @Selection Region region, @Range(min = 0, max = 15) int value) { public void setlighting(Player player, EditSession editSession, @Selection Region region, @Range(from = 0, to = 15) int value) {
// TODO NOT IMPLEMENTED // TODO NOT IMPLEMENTED
} }
@ -263,7 +263,7 @@ public class RegionCommands {
desc = "Set sky lighting in a selection" desc = "Set sky lighting in a selection"
) )
@CommandPermissions("worldedit.light.set") @CommandPermissions("worldedit.light.set")
public void setskylighting(Player player, @Selection Region region, @Range(min = 0, max = 15) int value) { public void setskylighting(Player player, @Selection Region region, @Range(from = 0, to= 15) int value) {
// TODO NOT IMPLEMENTED // TODO NOT IMPLEMENTED
} }
@ -314,7 +314,7 @@ public class RegionCommands {
boolean shell, InjectedValueAccess context) throws WorldEditException { boolean shell, InjectedValueAccess context) throws WorldEditException {
if (!(region instanceof ConvexPolyhedralRegion)) { if (!(region instanceof ConvexPolyhedralRegion)) {
actor.printError("//curve only works with convex polyhedral selections"); actor.printError("//curve only works with convex polyhedral selections");
return 0; return;
} }
checkCommandArgument(thickness >= 0, "Thickness must be >= 0"); checkCommandArgument(thickness >= 0, "Thickness must be >= 0");
@ -523,22 +523,24 @@ public class RegionCommands {
@CommandPermissions("worldedit.region.move") @CommandPermissions("worldedit.region.move")
@Logging(ORIENTATION_REGION) @Logging(ORIENTATION_REGION)
public void move(Actor actor, World world, EditSession editSession, LocalSession session, public void move(Actor actor, World world, EditSession editSession, LocalSession session,
@Selection Region region, @Selection Region region,
@Arg(desc = "# of blocks to move", def = "1") @Arg(desc = "# of blocks to move", def = "1")
int count, int count,
@Arg(desc = "The direction to move", def = Direction.AIM) @Arg(desc = "The direction to move", def = Direction.AIM)
@Direction(includeDiagonals = true) @Direction(includeDiagonals = true)
BlockVector3 direction, BlockVector3 direction,
@Arg(desc = "The pattern of blocks to leave", def = "air") @Arg(desc = "The pattern of blocks to leave", def = "air")
Pattern replace, Pattern replace,
@Switch(name = 's', desc = "Shift the selection to the target location") @Switch(name = 's', desc = "Shift the selection to the target location")
boolean moveSelection, boolean moveSelection,
@Switch(name = 'a', desc = "Ignore air blocks") @Switch(name = 'a', desc = "Ignore air blocks")
boolean ignoreAirBlocks, boolean ignoreAirBlocks,
@Switch(name = 'e', desc = "Ignore entities") @Switch(name = 'e', desc = "Skip copy entities")
boolean skipEntities, boolean skipEntities,
@Switch(name = 'b', desc = "Also copy biomes") @Switch(name = 'b', desc = "Also copy biomes")
boolean copyBiomes, boolean copyBiomes,
@ArgFlag(name = 'm', desc = "Set the include mask, non-matching blocks become air", def = "")
Mask mask,
InjectedValueAccess context) throws WorldEditException { InjectedValueAccess context) throws WorldEditException {
checkCommandArgument(count >= 1, "Count must be >= 1"); checkCommandArgument(count >= 1, "Count must be >= 1");
@ -554,7 +556,7 @@ public class RegionCommands {
} }
actor.checkConfirmationRegion(() -> { actor.checkConfirmationRegion(() -> {
int affected = editSession.moveRegion(region, direction, count, !ignoreAirBlocks, !skipEntities, copyBiomes, combinedMask, replace); int affected = editSession.moveRegion(region, direction, count, !skipEntities, copyBiomes, combinedMask, replace);
if (moveSelection) { if (moveSelection) {
try { try {
@ -612,7 +614,7 @@ public class RegionCommands {
@Switch(name = 'b', desc = "Also copy biomes") @Switch(name = 'b', desc = "Also copy biomes")
boolean copyBiomes, boolean copyBiomes,
@ArgFlag(name = 'm', desc = "Source mask", def="") @ArgFlag(name = 'm', desc = "Source mask", def="")
Mask sourceMask, Mask mask,
InjectedValueAccess context) throws WorldEditException { InjectedValueAccess context) throws WorldEditException {
Mask combinedMask; Mask combinedMask;
@ -627,9 +629,6 @@ public class RegionCommands {
} }
actor.checkConfirmationStack(() -> { actor.checkConfirmationStack(() -> {
if (sourceMask != null) {
editSession.addSourceMask(sourceMask);
}
int affected = editSession.stackCuboidRegion(region, direction, count, !skipEntities, copyBiomes, combinedMask); int affected = editSession.stackCuboidRegion(region, direction, count, !skipEntities, copyBiomes, combinedMask);
if (moveSelection) { if (moveSelection) {
@ -751,7 +750,7 @@ public class RegionCommands {
@Logging(REGION) @Logging(REGION)
public void hollow(Actor actor, EditSession editSession, public void hollow(Actor actor, EditSession editSession,
@Selection Region region, @Selection Region region,
@Range(min = 0) @Arg(desc = "Thickness of the shell to leave", def = "0") @Range(from=0, to=Integer.MAX_VALUE) @Arg(desc = "Thickness of the shell to leave", def = "0")
int thickness, int thickness,
@Arg(desc = "The pattern of blocks to replace the hollowed area with", def = "air") @Arg(desc = "The pattern of blocks to replace the hollowed area with", def = "air")
Pattern pattern, Pattern pattern,
@ -799,6 +798,7 @@ public class RegionCommands {
visitor.setMask(new NoiseFilter2D(new RandomNoise(), density / 100)); visitor.setMask(new NoiseFilter2D(new RandomNoise(), density / 100));
Operations.completeLegacy(visitor); Operations.completeLegacy(visitor);
int affected = ground.getAffected();
actor.print(affected + " flora created."); actor.print(affected + " flora created.");
}, "/flora", region, context); }, "/flora", region, context);
} }

View File

@ -429,49 +429,6 @@ public class SchematicCommands {
} }
} }
@Command(
name = "delete",
aliases = {"d"},
desc = "Delete a saved schematic"
)
@CommandPermissions({"worldedit.schematic.delete", "worldedit.schematic.delete.other"})
public void delete(Actor actor, LocalSession session,
@Arg(desc = "File name.")
String filename) throws WorldEditException, IOException {
LocalConfiguration config = worldEdit.getConfiguration();
File working = worldEdit.getWorkingDirectoryFile(config.saveDir);
File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, actor.getUniqueId().toString()) : working;
List<File> files = new ArrayList<>();
if (filename.equalsIgnoreCase("*")) {
files.addAll(getFiles(session.getClipboard()));
} else {
File f = MainUtil.resolveRelative(new File(dir, filename));
files.add(f);
}
if (files.isEmpty()) {
actor.printError(BBC.SCHEMATIC_NONE.s());
return;
}
for (File f : files) {
if (!MainUtil.isInSubDirectory(working, f) || !f.exists()) {
actor.printError("Schematic " + filename + " does not exist! (" + f.exists() + "|" + f + "|" + !MainUtil.isInSubDirectory(working, f)
+ ")");
continue;
}
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && !MainUtil.isInSubDirectory(dir, f) && !actor.hasPermission("worldedit.schematic.delete.other")) {
BBC.NO_PERM.send(actor, "worldedit.schematic.delete.other");
continue;
}
if (!delete(f)) {
actor.printError("Deletion of " + filename + " failed! Maybe it is read-only.");
continue;
}
BBC.FILE_DELETED.send(actor, filename);
}
}
private List<File> getFiles(ClipboardHolder clipboard) { private List<File> getFiles(ClipboardHolder clipboard) {
Collection<URI> uris = Collections.emptyList(); Collection<URI> uris = Collections.emptyList();
if (clipboard instanceof URIClipboardHolder) { if (clipboard instanceof URIClipboardHolder) {
@ -853,17 +810,43 @@ public class SchematicCommands {
) )
@CommandPermissions("worldedit.schematic.delete") @CommandPermissions("worldedit.schematic.delete")
public void delete(Actor actor, public void delete(Actor actor,
LocalSession session,
@Arg(desc = "File name.") @Arg(desc = "File name.")
String filename) throws WorldEditException { String filename) throws WorldEditException, IOException {
LocalConfiguration config = worldEdit.getConfiguration(); LocalConfiguration config = worldEdit.getConfiguration();
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); File working = worldEdit.getWorkingDirectoryFile(config.saveDir);
File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, actor.getUniqueId().toString()) : working;
List<File> files = new ArrayList<>();
File f = worldEdit.getSafeOpenFile(actor instanceof Player ? ((Player) actor) : null, if (filename.equalsIgnoreCase("*")) {
dir, filename, "schematic", ClipboardFormats.getFileExtensionArray()); files.addAll(getFiles(session.getClipboard()));
} else {
File f = MainUtil.resolveRelative(new File(dir, filename));
files.add(f);
}
if (!f.exists()) { if (files.isEmpty()) {
actor.printError("Schematic " + filename + " does not exist!"); actor.printError(BBC.SCHEMATIC_NONE.s());
return; return;
}
for (File f : files) {
if (!MainUtil.isInSubDirectory(working, f) || !f.exists()) {
actor.printError("Schematic " + filename + " does not exist! (" + f.exists() + "|" + f + "|" + !MainUtil.isInSubDirectory(working, f)
+ ")");
continue;
}
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && !MainUtil.isInSubDirectory(dir, f) && !actor.hasPermission("worldedit.schematic.delete.other")) {
BBC.NO_PERM.send(actor, "worldedit.schematic.delete.other");
continue;
}
if (!delete(f)) {
actor.printError("Deletion of " + filename + " failed! Maybe it is read-only.");
continue;
}
BBC.FILE_DELETED.send(actor, filename);
}
}
private boolean delete(File file) { private boolean delete(File file) {
if (file.delete()) { if (file.delete()) {
new File(file.getParentFile(), "." + file.getName() + ".cached").delete(); new File(file.getParentFile(), "." + file.getName() + ".cached").delete();

View File

@ -58,15 +58,6 @@ public class ScriptingCommands {
this.worldEdit = worldEdit; this.worldEdit = worldEdit;
} }
@Command(
name = "setupdispatcher",
desc = ""
)
@CommandPermissions("fawe.setupdispatcher")
public void setupdispatcher(Player player, LocalSession session, InjectedValueAccess args) throws WorldEditException {
PlatformCommandManager.getInstance().registerAllCommands();
}
@Command( @Command(
name = "cs", name = "cs",
desc = "Execute a CraftScript" desc = "Execute a CraftScript"

View File

@ -74,6 +74,7 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.storage.ChunkStore; import com.sk89q.worldedit.world.storage.ChunkStore;
@ -108,6 +109,7 @@ public class SelectionCommands {
@Command( @Command(
name = "/pos1", name = "/pos1",
aliases = "/1",
desc = "Set position 1" desc = "Set position 1"
) )
@Logging(POSITION) @Logging(POSITION)
@ -136,6 +138,7 @@ public class SelectionCommands {
@Command( @Command(
name = "/pos2", name = "/pos2",
aliases = "/2",
desc = "Set position 2" desc = "Set position 2"
) )
@Logging(POSITION) @Logging(POSITION)
@ -544,7 +547,7 @@ public class SelectionCommands {
if (distribution.isEmpty()) { // *Should* always be false if (distribution.isEmpty()) { // *Should* always be false
actor.printError("No blocks counted."); player.printError("No blocks counted.");
return; return;
} }

View File

@ -19,9 +19,6 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
import com.boydti.fawe.config.BBC;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
@ -39,12 +36,15 @@ import com.sk89q.worldedit.world.snapshot.Snapshot;
import com.sk89q.worldedit.world.snapshot.SnapshotRestore; import com.sk89q.worldedit.world.snapshot.SnapshotRestore;
import com.sk89q.worldedit.world.storage.ChunkStore; import com.sk89q.worldedit.world.storage.ChunkStore;
import com.sk89q.worldedit.world.storage.MissingWorldException; import com.sk89q.worldedit.world.storage.MissingWorldException;
import java.io.File;
import java.io.IOException;
import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Arg;
import java.io.File;
import java.io.IOException;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) @CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class SnapshotUtilCommands { public class SnapshotUtilCommands {
@ -55,15 +55,15 @@ public class SnapshotUtilCommands {
} }
@Command( @Command(
name = "restore", name = "restore",
aliases = { "/restore" }, aliases = { "/restore" },
desc = "Restore the selection from a snapshot" desc = "Restore the selection from a snapshot"
) )
@Logging(REGION) @Logging(REGION)
@CommandPermissions("worldedit.snapshots.restore") @CommandPermissions("worldedit.snapshots.restore")
public void restore(Actor actor, World world, LocalSession session, EditSession editSession, public void restore(Actor actor, World world, LocalSession session, EditSession editSession,
@Arg(name = "snapshot", desc = "The snapshot to restore", def = "") @Arg(name = "snapshot", desc = "The snapshot to restore", def = "")
String snapshotName) throws WorldEditException { String snapshotName) throws WorldEditException {
LocalConfiguration config = we.getConfiguration(); LocalConfiguration config = we.getConfiguration();
@ -98,10 +98,10 @@ public class SnapshotUtilCommands {
File dir = config.snapshotRepo.getDirectory(); File dir = config.snapshotRepo.getDirectory();
try { try {
WorldEdit.logger.info("FAWE found no snapshots: looked in: " WorldEdit.logger.info("WorldEdit found no snapshots: looked in: "
+ dir.getCanonicalPath()); + dir.getCanonicalPath());
} catch (IOException e) { } catch (IOException e) {
WorldEdit.logger.info("FAWE found no snapshots: looked in " WorldEdit.logger.info("WorldEdit found no snapshots: looked in "
+ "(NON-RESOLVABLE PATH - does it exist?): " + "(NON-RESOLVABLE PATH - does it exist?): "
+ dir.getPath()); + dir.getPath());
} }
@ -125,6 +125,7 @@ public class SnapshotUtilCommands {
return; return;
} }
try {
// Restore snapshot // Restore snapshot
SnapshotRestore restore = new SnapshotRestore(chunkStore, editSession, region); SnapshotRestore restore = new SnapshotRestore(chunkStore, editSession, region);
//player.print(restore.getChunksAffected() + " chunk(s) will be loaded."); //player.print(restore.getChunksAffected() + " chunk(s) will be loaded.");
@ -143,12 +144,15 @@ public class SnapshotUtilCommands {
} }
} else { } else {
actor.print(String.format("Restored; %d " actor.print(String.format("Restored; %d "
+ "missing chunks and %d other errors.", + "missing chunks and %d other errors.",
restore.getMissingChunks().size(), restore.getMissingChunks().size(),
restore.getErrorChunks().size())); restore.getErrorChunks().size()));
} }
} catch (DataException | IOException e) { } finally {
actor.printError("Failed to load snapshot: " + e.getMessage()); try {
chunkStore.close();
} catch (IOException ignored) {
} }
} }
}
} }

View File

@ -42,13 +42,13 @@ import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.extension.platform.PlatformCommandManager; import com.sk89q.worldedit.extension.platform.PlatformCommandManager;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.annotation.Range;
import com.sk89q.worldedit.internal.command.CommandArgParser; import com.sk89q.worldedit.internal.command.CommandArgParser;
import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.HandSide;
import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch; import org.enginehub.piston.annotation.param.Switch;
import org.jetbrains.annotations.Range;
import java.util.List; import java.util.List;
@ -253,7 +253,7 @@ public class ToolUtilCommands {
) )
@CommandPermissions("worldedit.brush.visualize") @CommandPermissions("worldedit.brush.visualize")
public void visual(Player player, LocalSession session, public void visual(Player player, LocalSession session,
@Arg(name = "mode", desc = "int", def = "0") @Range(min = 0, max = 2) @Arg(name = "mode", desc = "int", def = "0") @Range(from = 0, to = 2)
int mode) int mode)
throws WorldEditException { throws WorldEditException {
BrushTool tool = session.getBrushTool(player, false); BrushTool tool = session.getBrushTool(player, false);

View File

@ -45,6 +45,7 @@ import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.command.util.PrintCommandHelp; import com.sk89q.worldedit.command.util.PrintCommandHelp;
import com.sk89q.worldedit.command.util.SkipQueue; import com.sk89q.worldedit.command.util.SkipQueue;
import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
@ -57,7 +58,7 @@ import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.function.mask.BlockTypeMask;
import com.sk89q.worldedit.function.visitor.EntityVisitor; import com.sk89q.worldedit.function.visitor.EntityVisitor;
import com.sk89q.worldedit.internal.annotation.Direction; import com.sk89q.worldedit.internal.annotation.Direction;
import com.sk89q.worldedit.internal.annotation.Range; import com.sk89q.worldedit.internal.expression.EvaluationException;
import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.ExpressionException;
@ -95,15 +96,13 @@ import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.annotation.param.Switch; import org.enginehub.piston.annotation.param.Switch;
import org.enginehub.piston.exception.StopExecutionException;
import org.jetbrains.annotations.Range;
/** /**
* Utility commands. * Utility commands.
*/ */
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) @CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class UtilityCommands {
// CommandQueuedConditionGenerator.Registration.class,
CommandPermissionsConditionGenerator.Registration.class // TODO NOT IMPLEMENTED - Piston doesn't seem to work with multiple conditions???
})
public class UtilityCommands { public class UtilityCommands {
private final WorldEdit we; private final WorldEdit we;
@ -201,9 +200,9 @@ public class UtilityCommands {
public int fill(Actor actor, LocalSession session, EditSession editSession, public int fill(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The blocks to fill with") @Arg(desc = "The blocks to fill with")
Pattern pattern, Pattern pattern,
@Range(min=1) @Arg(desc = "The radius to fill in") @Range(from=1, to=Integer.MAX_VALUE) @Arg(desc = "The radius to fill in")
Expression radiusExp, Expression radiusExp,
@Range(min=1) @Arg(desc = "The depth to fill", def = "1") @Range(from=1, to=Integer.MAX_VALUE) @Arg(desc = "The depth to fill", def = "1")
int depth, int depth,
@Arg(desc = "The direction to move", def = "down") @Arg(desc = "The direction to move", def = "down")
@Direction BlockVector3 direction) throws WorldEditException, EvaluationException { @Direction BlockVector3 direction) throws WorldEditException, EvaluationException {
@ -745,7 +744,7 @@ public class UtilityCommands {
} }
try { try {
if (!MainUtil.isInSubDirectory(root, file)) { if (!MainUtil.isInSubDirectory(root, file)) {
throw new RuntimeException(new CommandException("Invalid path")); throw new RuntimeException(new StopExecutionException(TextComponent.of("Invalid path")));
} }
} catch (IOException ignore) { } catch (IOException ignore) {
} }

View File

@ -1,18 +1,12 @@
package com.sk89q.worldedit.command.argument; package com.sk89q.worldedit.command.argument;
import com.google.common.collect.ImmutableSetMultimap;
import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.world.World;
import org.enginehub.piston.CommandManager; import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.ArgumentConverter; import org.enginehub.piston.converter.ArgumentConverter;
import org.enginehub.piston.converter.ConversionResult; import org.enginehub.piston.converter.ConversionResult;
import org.enginehub.piston.converter.FailedConversion; import org.enginehub.piston.converter.FailedConversion;
import org.enginehub.piston.converter.MultiKeyConverter;
import org.enginehub.piston.converter.SimpleArgumentConverter;
import org.enginehub.piston.converter.SuccessfulConversion; import org.enginehub.piston.converter.SuccessfulConversion;
import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key; import org.enginehub.piston.inject.Key;
@ -32,16 +26,11 @@ public class ExpressionConverter implements ArgumentConverter<Expression> {
public ConversionResult<Expression> convert(String s, InjectedValueAccess injectedValueAccess) { public ConversionResult<Expression> convert(String s, InjectedValueAccess injectedValueAccess) {
Expression expression; Expression expression;
try { try {
expression = new Expression(Double.parseDouble(s)); expression = Expression.compile(s);
} catch (NumberFormatException e1) { expression.optimize();
try { return SuccessfulConversion.fromSingle(expression);
expression = Expression.compile(s); } catch (Exception e) {
expression.optimize(); return FailedConversion.from(e);
return SuccessfulConversion.fromSingle(expression);
} catch (Exception e) {
return FailedConversion.from(e);
}
} }
return SuccessfulConversion.fromSingle(expression);
} }
} }

View File

@ -0,0 +1,44 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.factory;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.EditContext;
import com.sk89q.worldedit.function.generator.ForestGenerator;
import com.sk89q.worldedit.util.TreeGenerator;
public final class TreeGeneratorFactory implements Contextual<ForestGenerator> {
private final TreeGenerator.TreeType type;
public TreeGeneratorFactory(TreeGenerator.TreeType type) {
this.type = type;
}
@Override
public ForestGenerator createFromContext(EditContext input) {
return new ForestGenerator((EditSession) input.getDestination(), type);
}
@Override
public String toString() {
return "tree of type " + type;
}
}

View File

@ -23,6 +23,7 @@ import com.boydti.fawe.object.mask.IdMask;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extension.platform.Platform;
@ -35,6 +36,8 @@ import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.Set;
/** /**
* A pickaxe mode that recursively finds adjacent blocks within range of * A pickaxe mode that recursively finds adjacent blocks within range of
* an initial block and of the same type. * an initial block and of the same type.

View File

@ -29,6 +29,7 @@ import java.util.LinkedHashSet;
import java.util.Set; import java.util.Set;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.util.collection.LocatedBlockList; import com.sk89q.worldedit.util.collection.LocatedBlockList;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypes;
public class GravityBrush implements Brush { public class GravityBrush implements Brush {
@ -53,15 +54,11 @@ public class GravityBrush implements Brush {
if (y != freeSpot) { if (y != freeSpot) {
editSession.setBlock((int)x, (int)y, (int)z, BlockTypes.AIR.getDefaultState()); editSession.setBlock((int)x, (int)y, (int)z, BlockTypes.AIR.getDefaultState());
editSession.setBlock((int)x, (int)freeSpot, (int)z, block); editSession.setBlock((int)x, (int)freeSpot, (int)z, block);
} }
freeSpot = y + 1; freeSpot = y + 1;
}
} }
} }
column.clear();
removedBlocks.clear();
} }
} }
}
} }

View File

@ -62,9 +62,12 @@ import com.sk89q.worldedit.world.block.FuzzyBlockState;
import com.sk89q.worldedit.world.registry.LegacyMapper; import com.sk89q.worldedit.world.registry.LegacyMapper;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.entity.EntityTypes;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -367,7 +370,7 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
} }
} }
// this should be impossible but IntelliJ isn't that smart // this should be impossible but IntelliJ isn't that smart
if (blockType == null) { if (state == null) {
throw new NoMatchException("Does not match a valid block type: '" + input + "'"); throw new NoMatchException("Does not match a valid block type: '" + input + "'");
} }
@ -398,23 +401,10 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
// Allow setting mob spawn type // Allow setting mob spawn type
if (blockAndExtraData.length > 1) { if (blockAndExtraData.length > 1) {
String mobName = blockAndExtraData[1]; String mobName = blockAndExtraData[1];
for (MobType mobType : MobType.values()) { EntityType mobType = EntityTypes.parse(mobName);
if (mobType.getName().toLowerCase().equals(mobName.toLowerCase(Locale.ROOT))) {
mobName = mobType.getName();
break;
}
}
mobName = ent.getId();
if (!worldEdit.getPlatformManager().queryCapability(Capability.USER_COMMANDS).isValidMobType(mobName)) {
String finalMobName = mobName.toLowerCase(Locale.ROOT);
throw new SuggestInputParseException("Unknown mob type '" + mobName + "'", mobName, () -> Stream.of(MobType.values())
.map(m -> m.getName().toLowerCase(Locale.ROOT))
.filter(s -> s.startsWith(finalMobName))
.collect(Collectors.toList()));
}
return validate(context, new MobSpawnerBlock(state, mobName)); return validate(context, new MobSpawnerBlock(state, mobName));
} else { } else {
return validate(context, new MobSpawnerBlock(state, MobType.PIG.getName())); return validate(context, new MobSpawnerBlock(state, EntityTypes.PIG.getId()));
} }
} else if (blockType == BlockTypes.PLAYER_HEAD || blockType == BlockTypes.PLAYER_WALL_HEAD) { } else if (blockType == BlockTypes.PLAYER_HEAD || blockType == BlockTypes.PLAYER_WALL_HEAD) {
// allow setting type/player/rotation // allow setting type/player/rotation

View File

@ -19,9 +19,16 @@
package com.sk89q.worldedit.extension.platform; package com.sk89q.worldedit.extension.platform;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.object.task.SimpleAsyncNotifyQueue;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.internal.cui.CUIEvent;
import java.io.File; import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class AbstractNonPlayerActor implements Actor { public abstract class AbstractNonPlayerActor implements Actor {
@ -48,4 +55,61 @@ public abstract class AbstractNonPlayerActor implements Actor {
@Override @Override
public void dispatchCUIEvent(CUIEvent event) { public void dispatchCUIEvent(CUIEvent event) {
} }
private final ConcurrentHashMap<String, Object> meta = new ConcurrentHashMap<>();
@Override
public Map<String, Object> getRawMeta() {
return meta;
}
// Queue for async tasks
private AtomicInteger runningCount = new AtomicInteger();
private SimpleAsyncNotifyQueue asyncNotifyQueue = new SimpleAsyncNotifyQueue(
(thread, throwable) -> {
while (throwable.getCause() != null) {
throwable = throwable.getCause();
}
if (throwable instanceof WorldEditException) {
printError(throwable.getLocalizedMessage());
} else {
FaweException fe = FaweException.get(throwable);
if (fe != null) {
printError(fe.getMessage());
} else {
throwable.printStackTrace();
}
}
});
/**
* Run a task either async, or on the current thread
*
* @param ifFree
* @param checkFree Whether to first check if a task is running
* @param async
* @return false if the task was ran or queued
*/
@Override
public boolean runAction(Runnable ifFree, boolean checkFree, boolean async) {
if (checkFree) {
if (runningCount.get() != 0) {
return false;
}
}
Runnable wrapped = () -> {
try {
runningCount.addAndGet(1);
ifFree.run();
} finally {
runningCount.decrementAndGet();
}
};
if (async) {
asyncNotifyQueue.queue(wrapped);
} else {
TaskManager.IMP.taskNow(wrapped, false);
}
return true;
}
} }

View File

@ -498,7 +498,7 @@ public final class PlatformCommandManager {
this.registration.register( this.registration.register(
commandManager, commandManager,
ClipboardCommandsRegistration.builder(), ClipboardCommandsRegistration.builder(),
new ClipboardCommands(worldEdit) new ClipboardCommands()
); );
this.registration.register( this.registration.register(
commandManager, commandManager,
@ -523,7 +523,7 @@ public final class PlatformCommandManager {
this.registration.register( this.registration.register(
commandManager, commandManager,
RegionCommandsRegistration.builder(), RegionCommandsRegistration.builder(),
new RegionCommands(worldEdit) new RegionCommands()
); );
this.registration.register( this.registration.register(
commandManager, commandManager,

View File

@ -415,7 +415,6 @@ public class PlatformManager {
player.runAsyncIfFree(() -> reset((DoubleActionTraceTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING), player.runAsyncIfFree(() -> reset((DoubleActionTraceTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING),
getConfiguration(), player, session)); getConfiguration(), player, session));
event.setCancelled(true); event.setCancelled(true);
}
return; return;
} }
@ -429,7 +428,6 @@ public class PlatformManager {
player.runAction(() -> reset((TraceTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), player.runAction(() -> reset((TraceTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING),
getConfiguration(), player, session), false, true); getConfiguration(), player, session), false, true);
event.setCancelled(true); event.setCancelled(true);
}
return; return;
} }

View File

@ -1,46 +0,0 @@
package com.sk89q.worldedit.extension.platform.binding;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.internal.annotation.Validate;
import java.lang.annotation.Annotation;
public class AnnotatedBindings extends Bindings {
public AnnotatedBindings(WorldEdit worldEdit) {
super(worldEdit);
}
@Validate()
public String getText(String argument, Validate modifier) {
return validate(argument, modifier);
}
/**
* Validate a string value using relevant modifiers.
*
* @param string the string
* @param modifiers the list of modifiers to scan
* @throws InputParseException on a validation error
*/
private static String validate(String string, Annotation... modifiers) {
if (string != null) {
for (Annotation modifier : modifiers) {
if (modifier instanceof Validate) {
Validate validate = (Validate) modifier;
if (!validate.value().isEmpty()) {
if (!string.matches(validate.value())) {
throw new InputParseException(
String.format(
"The given text doesn't match the right format (technically speaking, the 'format' is %s)",
validate.value()));
}
}
}
}
}
return string;
}
}

View File

@ -14,7 +14,6 @@ import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.annotation.Direction; import com.sk89q.worldedit.internal.annotation.Direction;
import com.sk89q.worldedit.internal.annotation.Validate;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;

View File

@ -10,10 +10,9 @@ import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.annotation.Range; import com.sk89q.worldedit.internal.expression.EvaluationException;
import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector2; import com.sk89q.worldedit.math.Vector2;
@ -38,19 +37,15 @@ public class PrimitiveBindings extends Bindings {
@Binding @Binding
public Expression getExpression(String argument) throws ExpressionException { public Expression getExpression(String argument) throws ExpressionException {
try { try {
return new Expression(Double.parseDouble(argument)); Expression expression = Expression.compile(argument);
} catch (NumberFormatException e1) { expression.optimize();
try { return expression;
Expression expression = Expression.compile(argument); } catch (EvaluationException e) {
expression.optimize(); throw new InputParseException(String.format(
return expression; "Expected '%s' to be a valid number (or a valid mathematical expression)", argument));
} catch (EvaluationException e) { } catch (ExpressionException e) {
throw new InputParseException(String.format( throw new InputParseException(String.format(
"Expected '%s' to be a valid number (or a valid mathematical expression)", argument)); "Expected '%s' to be a number or valid math expression (error: %s)", argument, e.getMessage()));
} catch (ExpressionException e) {
throw new InputParseException(String.format(
"Expected '%s' to be a number or valid math expression (error: %s)", argument, e.getMessage()));
}
} }
} }

View File

@ -25,11 +25,8 @@ import com.boydti.fawe.object.schematic.PNGWriter;
import com.boydti.fawe.object.schematic.MinecraftStructure; import com.boydti.fawe.object.schematic.MinecraftStructure;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.NamedTag;
import com.sk89q.jnbt.Tag;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
@ -38,7 +35,6 @@ import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
@ -95,7 +91,7 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
} }
BufferedInputStream buffered = new BufferedInputStream(inputStream); BufferedInputStream buffered = new BufferedInputStream(inputStream);
NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered))); NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered)));
return new SpongeSchematicReader(nbtStream); return new FastSchematicReader(nbtStream);
} }
@Override @Override
@ -108,7 +104,7 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
gzip = new PGZIPOutputStream(outputStream); gzip = new PGZIPOutputStream(outputStream);
} }
NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip)); NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip));
return new SpongeSchematicWriter(nbtStream); return new FastSchematicWriter(nbtStream);
} }
@Override @Override

View File

@ -0,0 +1,343 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extent.clipboard.io;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.jnbt.streamer.IntValueReader;
import com.boydti.fawe.jnbt.streamer.StreamDelegate;
import com.boydti.fawe.jnbt.streamer.ValueReader;
import com.boydti.fawe.object.FaweInputStream;
import com.boydti.fawe.object.FaweOutputStream;
import com.boydti.fawe.object.clipboard.LinearClipboard;
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.boydti.fawe.object.io.FastByteArraysInputStream;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.entity.EntityTypes;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.function.Function;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Reads schematic files using the Sponge Schematic Specification.
*/
public class FastSchematicReader extends NBTSchematicReader {
private static final Logger log = LoggerFactory.getLogger(FastSchematicReader.class);
private final NBTInputStream inputStream;
private DataFixer fixer = null;
private int dataVersion = -1;
private FastByteArrayOutputStream blocksOut;
private FaweOutputStream blocks;
private FastByteArrayOutputStream biomesOut;
private FaweOutputStream biomes;
private List<Map<String, Object>> tiles;
private List<Map<String, Object>> entities;
private int width, height, length;
private int offsetX, offsetY, offsetZ;
private char[] palette, biomePalette;
private BlockVector3 min = BlockVector3.ZERO;
/**
* Create a new instance.
*
* @param inputStream the input stream to read from
*/
public FastSchematicReader(NBTInputStream inputStream) {
checkNotNull(inputStream);
this.inputStream = inputStream;
}
private String fix(String palettePart) {
if (fixer == null || dataVersion == -1) return palettePart;
return fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, palettePart, dataVersion);
}
private CompoundTag fixBlockEntity(CompoundTag tag) {
if (fixer == null || dataVersion == -1) return tag;
return fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, tag, dataVersion);
}
private CompoundTag fixEntity(CompoundTag tag) {
if (fixer == null || dataVersion == -1) return tag;
return fixer.fixUp(DataFixer.FixTypes.ENTITY, tag, dataVersion);
}
public StreamDelegate createDelegate() {
StreamDelegate root = new StreamDelegate();
StreamDelegate schematic = root.add("Schematic");
schematic.add("DataVersion").withInt((i, v) -> dataVersion = v);
schematic.add("Width").withInt((i, v) -> width = v);
schematic.add("Height").withInt((i, v) -> height = v);
schematic.add("Length").withInt((i, v) -> length = v);
schematic.add("Offset").withValue((ValueReader<int[]>) (index, v) -> min = BlockVector3.at(v[0], v[1], v[2]));
StreamDelegate metadata = schematic.add("Metadata");
metadata.add("WEOffsetX").withInt((i, v) -> offsetX = v);
metadata.add("WEOffsetY").withInt((i, v) -> offsetY = v);
metadata.add("WEOffsetZ").withInt((i, v) -> offsetZ = v);
StreamDelegate paletteDelegate = schematic.add("Palette");
paletteDelegate.withValue((ValueReader<Map<String, Object>>) (ignore, v) -> {
palette = new char[v.size()];
for (Entry<String, Object> entry : v.entrySet()) {
BlockState state = null;
try {
String palettePart = fix(entry.getKey());
state = BlockState.get(palettePart);
} catch (InputParseException e) {
e.printStackTrace();
}
int index = (int) entry.getValue();
palette[index] = (char) state.getOrdinal();
}
});
StreamDelegate blockData = schematic.add("BlockData");
blockData.withInfo((length, type) -> {
blocksOut = new FastByteArrayOutputStream();
blocks = new FaweOutputStream(new LZ4BlockOutputStream(blocksOut));
});
blockData.withInt((index, value) -> blocks.writeVarInt(value));
StreamDelegate tilesDelegate = schematic.add("TileEntities");
tilesDelegate.withInfo((length, type) -> tiles = new ArrayList<>(length));
tilesDelegate.withElem((ValueReader<Map<String, Object>>) (index, tile) -> tiles.add(tile));
StreamDelegate entitiesDelegate = schematic.add("Entities");
entitiesDelegate.withInfo((length, type) -> entities = new ArrayList<>(length));
entitiesDelegate.withElem((ValueReader<Map<String, Object>>) (index, entity) -> entities.add(entity));
StreamDelegate biomeData = schematic.add("BiomeData");
biomeData.withInfo((length, type) -> {
biomesOut = new FastByteArrayOutputStream();
biomes = new FaweOutputStream(new LZ4BlockOutputStream(blocksOut));
});
biomeData.withElem((IntValueReader) (index, value) -> {
try {
biomes.write(value); // byte of varInt
} catch (IOException e) {
e.printStackTrace();
}
});
StreamDelegate biomePaletteDelegate = schematic.add("BiomePalette");
biomePaletteDelegate.withInfo((length, type) -> biomePalette = new char[length]);
biomePaletteDelegate.withElem(new ValueReader<Map.Entry<String, Number>>() {
@Override
public void apply(int index, Map.Entry<String, Number> palettePart) {
String key = palettePart.getKey();
if (fixer != null) {
key = fixer.fixUp(DataFixer.FixTypes.BIOME, key, dataVersion);
}
BiomeType biome = BiomeTypes.get(key);
if (biome == null) {
System. out.println("Unknown biome " + key);
biome = BiomeTypes.FOREST;
}
int paletteIndex = palettePart.getValue().intValue();
biomePalette[paletteIndex] = (char) biome.getInternalId();
}
});
return root;
}
private BlockState getBlockState(int id) {
return BlockTypesCache.states[palette[id]];
}
private BiomeType getBiomeType(FaweInputStream fis) throws IOException {
char biomeId = biomePalette[fis.readVarInt()];
BiomeType biome = BiomeTypes.get(biomeId);
return biome;
}
@Override
public Clipboard read(UUID uuid, Function<BlockVector3, Clipboard> createOutput) throws IOException {
StreamDelegate root = createDelegate();
inputStream.readNamedTagLazy(root);
if (blocks != null) blocks.close();
if (biomes != null) biomes.close();
blocks = null;
biomes = null;
BlockVector3 dimensions = BlockVector3.at(width, height, length);
BlockVector3 origin = BlockVector3.ZERO;
if (offsetX != Integer.MIN_VALUE && offsetY != Integer.MIN_VALUE && offsetZ != Integer.MIN_VALUE) {
origin = BlockVector3.at(-offsetX, -offsetY, -offsetZ);
}
Clipboard clipboard = createOutput.apply(dimensions);
if (blocksOut != null && blocksOut.getSize() != 0) {
try (FaweInputStream fis = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(blocksOut.toByteArrays())))) {
if (clipboard instanceof LinearClipboard) {
LinearClipboard linear = (LinearClipboard) clipboard;
int volume = width * height * length;
if (palette.length < 128) {
for (int index = 0; index < volume; index++) {
linear.setBlock(index, getBlockState(fis.read()));
}
} else {
for (int index = 0; index < volume; index++) {
linear.setBlock(index, getBlockState(fis.readVarInt()));
}
}
} else {
if (palette.length < 128) {
for (int y = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++) {
clipboard.setBlock(x, y, z, getBlockState(fis.read()));
}
}
}
} else {
for (int y = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++) {
clipboard.setBlock(x, y, z, getBlockState(fis.readVarInt()));
}
}
}
}
}
}
}
if (biomesOut != null && biomesOut.getSize() != 0) {
try (FaweInputStream fis = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(biomesOut.toByteArrays())))) {
if (clipboard instanceof LinearClipboard) {
LinearClipboard linear = (LinearClipboard) clipboard;
int volume = width * length;
for (int index = 0; index < volume; index++) {
linear.setBiome(index, getBiomeType(fis));
}
} else {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++) {
clipboard.setBiome(x, 0, z, getBiomeType(fis));
}
}
}
}
}
// tiles
if (tiles != null && !tiles.isEmpty()) {
for (Map<String, Object> tileRaw : tiles) {
CompoundTag tile = FaweCache.IMP.asTag(tileRaw);
int[] pos = tile.getIntArray("Pos");
int x,y,z;
if (pos.length != 3) {
if (!tile.containsKey("x") || !tile.containsKey("y") || !tile.containsKey("z")) {
return null;
}
x = tile.getInt("x");
y = tile.getInt("y");
z = tile.getInt("z");
} else {
x = pos[0];
y = pos[1];
z = pos[2];
}
Map<String, Tag> values = tile.getValue();
Tag id = values.get("Id");
if (id != null) {
values.put("x", new IntTag(x));
values.put("y", new IntTag(y));
values.put("z", new IntTag(z));
values.put("id", id);
}
values.remove("Id");
values.remove("Pos");
tile = fixBlockEntity(tile);
clipboard.setTile(x, y, z, tile);
}
}
// entities
if (entities != null && !entities.isEmpty()) {
for (Map<String, Object> entRaw : entities) {
CompoundTag ent = FaweCache.IMP.asTag(entRaw);
Map<String, Tag> value = ent.getValue();
StringTag id = (StringTag) value.get("Id");
if (id == null) {
id = (StringTag) value.get("id");
if (id == null) {
return null;
}
}
value.put("id", id);
value.remove("Id");
EntityType type = EntityTypes.parse(id.getValue());
if (type != null) {
ent = fixEntity(ent);
BaseEntity state = new BaseEntity(type, ent);
Location loc = ent.getEntityLocation(clipboard);
clipboard.createEntity(loc, state);
} else {
log.debug("Invalid entity: " + id);
}
}
}
clipboard.setOrigin(origin);
if (!min.equals(BlockVector3.ZERO)) {
new BlockArrayClipboard(clipboard, min);
}
return clipboard;
}
@Override
public void close() throws IOException {
inputStream.close();
}
}

View File

@ -0,0 +1,341 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extent.clipboard.io;
import com.boydti.fawe.jnbt.streamer.IntValueReader;
import com.boydti.fawe.object.FaweOutputStream;
import com.boydti.fawe.object.clipboard.LinearClipboard;
import com.boydti.fawe.util.IOUtil;
import com.google.common.collect.Maps;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntArrayTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.NBTConstants;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.visitor.Order;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Writes schematic files using the Sponge schematic format.
*/
public class FastSchematicWriter implements ClipboardWriter {
private static final int CURRENT_VERSION = 2;
private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE;
private final NBTOutputStream outputStream;
/**
* Create a new schematic writer.
*
* @param outputStream the output stream to write to
*/
public FastSchematicWriter(NBTOutputStream outputStream) {
checkNotNull(outputStream);
this.outputStream = outputStream;
}
@Override
public void write(Clipboard clipboard) throws IOException {
// For now always write the latest version. Maybe provide support for earlier if more appear.
write2(clipboard);
}
/**
* Writes a version 2 schematic file.
*
* @param clipboard The clipboard
*/
private void write2(Clipboard clipboard) throws IOException {
Region region = clipboard.getRegion();
BlockVector3 origin = clipboard.getOrigin();
BlockVector3 min = region.getMinimumPoint();
BlockVector3 offset = min.subtract(origin);
int width = region.getWidth();
int height = region.getHeight();
int length = region.getLength();
if (width > MAX_SIZE) {
throw new IllegalArgumentException("Width of region too large for a .schematic");
}
if (height > MAX_SIZE) {
throw new IllegalArgumentException("Height of region too large for a .schematic");
}
if (length > MAX_SIZE) {
throw new IllegalArgumentException("Length of region too large for a .schematic");
}
final DataOutput rawStream = outputStream.getOutputStream();
outputStream.writeLazyCompoundTag("Schematic", out -> {
out.writeNamedTag("DataVersion", WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion());
out.writeNamedTag("Version", CURRENT_VERSION);
out.writeNamedTag("Width", (short) width);
out.writeNamedTag("Height", (short) height);
out.writeNamedTag("Length", (short) length);
// The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin'
out.writeNamedTag("Offset", new int[]{
min.getBlockX(),
min.getBlockY(),
min.getBlockZ(),
});
out.writeLazyCompoundTag("Metadata", out1 -> {
out1.writeNamedTag("WEOffsetX", offset.getBlockX());
out1.writeNamedTag("WEOffsetY", offset.getBlockY());
out1.writeNamedTag("WEOffsetZ", offset.getBlockZ());
});
ByteArrayOutputStream blocksCompressed = new ByteArrayOutputStream();
FaweOutputStream blocksOut = new FaweOutputStream(new DataOutputStream(new LZ4BlockOutputStream(blocksCompressed)));
ByteArrayOutputStream tilesCompressed = new ByteArrayOutputStream();
NBTOutputStream tilesOut = new NBTOutputStream(new LZ4BlockOutputStream(tilesCompressed));
List<Integer> paletteList = new ArrayList<>();
char[] palette = new char[BlockTypesCache.states.length];
Arrays.fill(palette, Character.MAX_VALUE);
int paletteMax = 0;
int numTiles = 0;
Clipboard finalClipboard;
if (clipboard instanceof BlockArrayClipboard) {
finalClipboard = ((BlockArrayClipboard) clipboard).getParent();
} else {
finalClipboard = clipboard;
}
Iterator<BlockVector3> iterator = finalClipboard.iterator(Order.YZX);
while (iterator.hasNext()) {
BlockVector3 pos = iterator.next();
BaseBlock block = pos.getFullBlock(finalClipboard);
CompoundTag nbt = block.getNbtData();
if (nbt != null) {
Map<String, Tag> values = nbt.getValue();
values.remove("id"); // Remove 'id' if it exists. We want 'Id'
// Positions are kept in NBT, we don't want that.
values.remove("x");
values.remove("y");
values.remove("z");
if (!values.containsKey("Id")) {
values.put("Id", new StringTag(block.getNbtId()));
}
values.put("Pos", new IntArrayTag(new int[]{
pos.getX(),
pos.getY(),
pos.getZ()
}));
numTiles++;
tilesOut.writeTagPayload(block.getNbtData());
}
int ordinal = block.getOrdinal();
char value = palette[ordinal];
if (value == Character.MAX_VALUE) {
int size = paletteMax++;
palette[ordinal] = value = (char) size;
paletteList.add(ordinal);
}
blocksOut.writeVarInt(value);
}
// close
tilesOut.close();
blocksOut.close();
out.writeNamedTag("PaletteMax", paletteMax);
out.writeLazyCompoundTag("Palette", out12 -> {
for (int i = 0; i < paletteList.size(); i++) {
int stateOrdinal = paletteList.get(i);
BlockState state = BlockTypesCache.states[stateOrdinal];
out12.writeNamedTag(state.getAsString(), i);
}
});
out.writeNamedTagName("BlockData", NBTConstants.TYPE_BYTE_ARRAY);
rawStream.writeInt(blocksOut.size());
try (LZ4BlockInputStream in = new LZ4BlockInputStream(new ByteArrayInputStream(blocksCompressed.toByteArray()))) {
IOUtil.copy(in, rawStream);
}
if (numTiles != 0) {
out.writeNamedTagName("TileEntities", NBTConstants.TYPE_LIST);
rawStream.write(NBTConstants.TYPE_COMPOUND);
rawStream.writeInt(numTiles);
try (LZ4BlockInputStream in = new LZ4BlockInputStream(new ByteArrayInputStream(tilesCompressed.toByteArray()))) {
IOUtil.copy(in, rawStream);
}
} else {
out.writeNamedEmptyList("TileEntities");
}
if (finalClipboard.hasBiomes()) {
writeBiomes(finalClipboard, out);
}
List<Tag> entities = new ArrayList<>();
for (Entity entity : finalClipboard.getEntities()) {
BaseEntity state = entity.getState();
if (state != null) {
Map<String, Tag> values = new HashMap<>();
// Put NBT provided data
CompoundTag rawTag = state.getNbtData();
if (rawTag != null) {
values.putAll(rawTag.getValue());
}
// Store our location data, overwriting any
values.remove("id");
values.put("Id", new StringTag(state.getType().getId()));
values.put("Pos", writeVector(entity.getLocation()));
values.put("Rotation", writeRotation(entity.getLocation()));
CompoundTag entityTag = new CompoundTag(values);
entities.add(entityTag);
}
}
if (entities.isEmpty()) {
out.writeNamedEmptyList("Entities");
} else {
out.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities));
}
});
}
private void writeBiomes(Clipboard clipboard, NBTOutputStream out) throws IOException {
ByteArrayOutputStream biomesCompressed = new ByteArrayOutputStream();
DataOutputStream biomesOut = new DataOutputStream(new LZ4BlockOutputStream(biomesCompressed));
List<Integer> paletteList = new ArrayList<>();
int[] palette = new int[BiomeTypes.getMaxId() + 1];
Arrays.fill(palette, Integer.MAX_VALUE);
int[] paletteMax = {0};
IntValueReader task = new IntValueReader() {
@Override
public void applyInt(int index, int ordinal) {
try {
int value = palette[ordinal];
if (value == Integer.MAX_VALUE) {
int size = paletteMax[0]++;
palette[ordinal] = value = size;
paletteList.add(ordinal);
}
IOUtil.writeVarInt(biomesOut, value);
} catch (IOException e) {
e.printStackTrace();
}
}
};
BlockVector3 min = clipboard.getMinimumPoint();
int width = clipboard.getRegion().getWidth();
int length = clipboard.getRegion().getLength();
for (int z = 0, i = 0; z < length; z++) {
int z0 = min.getBlockZ() + z;
for (int x = 0; x < width; x++, i++) {
int x0 = min.getBlockX() + x;
BlockVector2 pt = BlockVector2.at(x0, z0);
BiomeType biome = clipboard.getBiome(pt);
task.applyInt(i, biome.getInternalId());
}
}
biomesOut.close();
out.writeNamedTag("BiomePaletteMax", paletteMax[0]);
out.writeLazyCompoundTag("BiomePalette", out12 -> {
for (int i = 0; i < paletteList.size(); i++) {
int ordinal = paletteList.get(i);
BiomeType state = BiomeTypes.get(ordinal);
out12.writeNamedTag(state.getId(), i);
}
});
out.writeNamedTagName("BiomeData", NBTConstants.TYPE_BYTE_ARRAY);
out.writeInt(biomesOut.size());
try (LZ4BlockInputStream in = new LZ4BlockInputStream(new ByteArrayInputStream(biomesCompressed.toByteArray()))) {
IOUtil.copy(in, (DataOutput) out);
}
}
private void writeEntities(Clipboard clipboard, NBTOutputStream schematic) throws IOException {
List<CompoundTag> entities = clipboard.getEntities().stream().map(e -> {
BaseEntity state = e.getState();
if (state == null) {
return null;
}
Map<String, Tag> values = Maps.newHashMap();
CompoundTag rawData = state.getNbtData();
if (rawData != null) {
values.putAll(rawData.getValue());
}
values.remove("id");
values.put("Id", new StringTag(state.getType().getId()));
values.put("Pos", writeVector(e.getLocation().toVector()));
values.put("Rotation", writeRotation(e.getLocation()));
return new CompoundTag(values);
}).filter(Objects::nonNull).collect(Collectors.toList());
if (entities.isEmpty()) {
return;
}
schematic.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities));
}
@Override
public void close() throws IOException {
outputStream.close();
}
}

View File

@ -56,6 +56,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;

View File

@ -19,88 +19,63 @@
package com.sk89q.worldedit.extent.clipboard.io; package com.sk89q.worldedit.extent.clipboard.io;
import com.boydti.fawe.Fawe; import com.google.common.collect.Maps;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.jnbt.streamer.InfoReader;
import com.boydti.fawe.jnbt.streamer.IntValueReader;
import com.boydti.fawe.jnbt.streamer.StreamDelegate;
import com.boydti.fawe.jnbt.streamer.ValueReader;
import com.boydti.fawe.object.FaweInputStream;
import com.boydti.fawe.object.FaweOutputStream;
import com.boydti.fawe.object.clipboard.CPUOptimizedClipboard;
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
import com.boydti.fawe.object.clipboard.LinearClipboard;
import com.boydti.fawe.object.clipboard.MemoryOptimizedClipboard;
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.boydti.fawe.object.io.FastByteArraysInputStream;
import com.sk89q.jnbt.ByteArrayTag; import com.sk89q.jnbt.ByteArrayTag;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntArrayTag;
import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NamedTag;
import com.sk89q.jnbt.ShortTag;
import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.entity.EntityTypes;
import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.world.storage.NBTConversions;
import com.sk89q.worldedit.extension.platform.Capability;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.DataInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.UUID; import java.util.OptionalInt;
import java.util.function.Function; import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.world.storage.NBTConversions;
import java.util.OptionalInt;
/** /**
* Reads schematic files using the Sponge Schematic Specification. * Reads schematic files using the Sponge Schematic Specification.
*/ */
@Deprecated // High mem usage + slow
public class SpongeSchematicReader extends NBTSchematicReader { public class SpongeSchematicReader extends NBTSchematicReader {
private static final Logger log = LoggerFactory.getLogger(SpongeSchematicReader.class); private static final Logger log = LoggerFactory.getLogger(SpongeSchematicReader.class);
private final NBTInputStream inputStream; private final NBTInputStream inputStream;
private DataFixer fixer = null; private DataFixer fixer = null;
private int dataVersion = -1;
private FastByteArrayOutputStream blocksOut;
private FaweOutputStream blocks;
private FastByteArrayOutputStream biomesOut;
private FaweOutputStream biomes;
private List<Map<String, Object>> tiles;
private List<Map<String, Object>> entities;
private int width, height, length;
private int offsetX, offsetY, offsetZ;
private char[] palette, biomePalette;
private BlockVector3 min = BlockVector3.ZERO;
private int schematicVersion = -1; private int schematicVersion = -1;
private int dataVersion = -1;
/** /**
* Create a new instance. * Create a new instance.
@ -112,107 +87,6 @@ public class SpongeSchematicReader extends NBTSchematicReader {
this.inputStream = inputStream; this.inputStream = inputStream;
} }
private String fix(String palettePart) {
if (fixer == null || dataVersion == -1) return palettePart;
return fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, palettePart, dataVersion);
}
private CompoundTag fixBlockEntity(CompoundTag tag) {
if (fixer == null || dataVersion == -1) return tag;
return fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, tag, dataVersion);
}
private CompoundTag fixEntity(CompoundTag tag) {
if (fixer == null || dataVersion == -1) return tag;
return fixer.fixUp(DataFixer.FixTypes.ENTITY, tag, dataVersion);
}
public StreamDelegate createDelegate() {
StreamDelegate root = new StreamDelegate();
StreamDelegate schematic = root.add("Schematic");
schematic.add("DataVersion").withInt((i, v) -> dataVersion = v);
schematic.add("Width").withInt((i, v) -> width = v);
schematic.add("Height").withInt((i, v) -> height = v);
schematic.add("Length").withInt((i, v) -> length = v);
schematic.add("Offset").withValue((ValueReader<int[]>) (index, v) -> min = BlockVector3.at(v[0], v[1], v[2]));
StreamDelegate metadata = schematic.add("Metadata");
metadata.add("WEOffsetX").withInt((i, v) -> offsetX = v);
metadata.add("WEOffsetY").withInt((i, v) -> offsetY = v);
metadata.add("WEOffsetZ").withInt((i, v) -> offsetZ = v);
StreamDelegate paletteDelegate = schematic.add("Palette");
paletteDelegate.withValue((ValueReader<Map<String, Object>>) (ignore, v) -> {
palette = new char[v.size()];
for (Entry<String, Object> entry : v.entrySet()) {
BlockState state = null;
try {
String palettePart = fix(entry.getKey());
System.out.println("Read " + palettePart);
state = BlockState.get(palettePart);
} catch (InputParseException e) {
e.printStackTrace();
}
int index = (int) entry.getValue();
palette[index] = (char) state.getOrdinal();
}
});
StreamDelegate blockData = schematic.add("BlockData");
blockData.withInfo((length, type) -> {
blocksOut = new FastByteArrayOutputStream();
blocks = new FaweOutputStream(new LZ4BlockOutputStream(blocksOut));
});
blockData.withInt((index, value) -> blocks.writeVarInt(value));
StreamDelegate tilesDelegate = schematic.add("TileEntities");
tilesDelegate.withInfo((length, type) -> tiles = new ArrayList<>(length));
tilesDelegate.withElem((ValueReader<Map<String, Object>>) (index, tile) -> tiles.add(tile));
StreamDelegate entitiesDelegate = schematic.add("Entities");
entitiesDelegate.withInfo((length, type) -> entities = new ArrayList<>(length));
entitiesDelegate.withElem((ValueReader<Map<String, Object>>) (index, entity) -> entities.add(entity));
StreamDelegate biomeData = schematic.add("BiomeData");
biomeData.withInfo((length, type) -> {
biomesOut = new FastByteArrayOutputStream();
biomes = new FaweOutputStream(new LZ4BlockOutputStream(blocksOut));
});
biomeData.withElem((IntValueReader) (index, value) -> {
try {
biomes.write(value); // byte of varInt
} catch (IOException e) {
e.printStackTrace();
}
});
StreamDelegate biomePaletteDelegate = schematic.add("BiomePalette");
biomePaletteDelegate.withInfo((length, type) -> biomePalette = new char[length]);
biomePaletteDelegate.withElem(new ValueReader<Map.Entry<String, Number>>() {
@Override
public void apply(int index, Map.Entry<String, Number> palettePart) {
String key = palettePart.getKey();
if (fixer != null) {
key = fixer.fixUp(DataFixer.FixTypes.BIOME, key, dataVersion);
}
BiomeType biome = BiomeTypes.get(key);
if (biome == null) {
System. out.println("Unknown biome " + key);
biome = BiomeTypes.FOREST;
}
int paletteIndex = palettePart.getValue().intValue();
biomePalette[paletteIndex] = (char) biome.getInternalId();
}
});
return root;
}
private BlockState getBlockState(int id) {
return BlockTypesCache.states[palette[id]];
}
private BiomeType getBiomeType(FaweInputStream fis) throws IOException {
char biomeId = biomePalette[fis.readVarInt()];
BiomeType biome = BiomeTypes.get(biomeId);
return biome;
}
@Override @Override
public Clipboard read() throws IOException { public Clipboard read() throws IOException {
CompoundTag schematicTag = getBaseTag(); CompoundTag schematicTag = getBaseTag();
@ -264,141 +138,156 @@ public class SpongeSchematicReader extends NBTSchematicReader {
} }
} }
@Override private CompoundTag getBaseTag() throws IOException {
public Clipboard getBaseTag(UUID uuid, Function<BlockVector3, Clipboard> createOutput) throws IOException { NamedTag rootTag = inputStream.readNamedTag();
StreamDelegate root = createDelegate(); if (!rootTag.getName().equals("Schematic")) {
inputStream.readNamedTagLazy(root); throw new IOException("Tag 'Schematic' does not exist or is not first");
if (blocks != null) blocks.close();
if (biomes != null) biomes.close();
blocks = null;
biomes = null;
BlockVector3 dimensions = BlockVector3.at(width, height, length);
BlockVector3 origin = BlockVector3.ZERO;
if (offsetX != Integer.MIN_VALUE && offsetY != Integer.MIN_VALUE && offsetZ != Integer.MIN_VALUE) {
origin = BlockVector3.at(-offsetX, -offsetY, -offsetZ);
} }
CompoundTag schematicTag = (CompoundTag) rootTag.getTag();
Clipboard clipboard = createOutput.apply(dimensions); // Check
Map<String, Tag> schematic = schematicTag.getValue();
if (blocksOut != null && blocksOut.getSize() != 0) { schematicVersion = requireTag(schematic, "Version", IntTag.class).getValue();
try (FaweInputStream fis = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(blocksOut.toByteArrays())))) { return schematicTag;
if (clipboard instanceof LinearClipboard) { }
LinearClipboard linear = (LinearClipboard) clipboard;
int volume = width * height * length; private BlockArrayClipboard readVersion1(CompoundTag schematicTag) throws IOException {
if (palette.length < 128) { BlockVector3 origin;
for (int index = 0; index < volume; index++) { Region region;
linear.setBlock(index, getBlockState(fis.read())); Map<String, Tag> schematic = schematicTag.getValue();
}
} else { int width = requireTag(schematic, "Width", ShortTag.class).getValue();
for (int index = 0; index < volume; index++) { int height = requireTag(schematic, "Height", ShortTag.class).getValue();
linear.setBlock(index, getBlockState(fis.readVarInt())); int length = requireTag(schematic, "Length", ShortTag.class).getValue();
}
} IntArrayTag offsetTag = getTag(schematic, "Offset", IntArrayTag.class);
} else { int[] offsetParts;
if (palette.length < 128) { if (offsetTag != null) {
for (int y = 0; y < height; y++) { offsetParts = offsetTag.getValue();
for (int z = 0; z < length; z++) { if (offsetParts.length != 3) {
for (int x = 0; x < width; x++) { throw new IOException("Invalid offset specified in schematic.");
clipboard.setBlock(x, y, z, getBlockState(fis.read()));
}
}
}
} else {
for (int y = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++) {
clipboard.setBlock(x, y, z, getBlockState(fis.readVarInt()));
}
}
}
}
}
} }
} else {
offsetParts = new int[] {0, 0, 0};
} }
if (biomesOut != null && biomesOut.getSize() != 0) {
try (FaweInputStream fis = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(biomesOut.toByteArrays())))) {
if (clipboard instanceof LinearClipboard) {
LinearClipboard linear = (LinearClipboard) clipboard;
int volume = width * length;
for (int index = 0; index < volume; index++) {
linear.setBiome(index, getBiomeType(fis));
}
} else {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++) {
clipboard.setBiome(x, 0, z, getBiomeType(fis));
}
}
}
}
}
// tiles
if (tiles != null && !tiles.isEmpty()) {
for (Map<String, Object> tileRaw : tiles) {
CompoundTag tile = FaweCache.IMP.asTag(tileRaw);
int[] pos = tile.getIntArray("Pos"); BlockVector3 min = BlockVector3.at(offsetParts[0], offsetParts[1], offsetParts[2]);
int x,y,z;
if (pos.length != 3) { CompoundTag metadataTag = getTag(schematic, "Metadata", CompoundTag.class);
if (!tile.containsKey("x") || !tile.containsKey("y") || !tile.containsKey("z")) { if (metadataTag != null && metadataTag.containsKey("WEOffsetX")) {
return null; // We appear to have WorldEdit Metadata
} Map<String, Tag> metadata = metadataTag.getValue();
x = tile.getInt("x"); int offsetX = requireTag(metadata, "WEOffsetX", IntTag.class).getValue();
y = tile.getInt("y"); int offsetY = requireTag(metadata, "WEOffsetY", IntTag.class).getValue();
z = tile.getInt("z"); int offsetZ = requireTag(metadata, "WEOffsetZ", IntTag.class).getValue();
} else { BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ);
x = pos[0]; origin = min.subtract(offset);
y = pos[1]; region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE));
z = pos[2]; } else {
} origin = min;
Map<String, Tag> values = tile.getValue(); region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE));
Tag id = values.get("Id"); }
if (id != null) {
values.put("x", new IntTag(x)); IntTag paletteMaxTag = getTag(schematic, "PaletteMax", IntTag.class);
values.put("y", new IntTag(y)); Map<String, Tag> paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue();
values.put("z", new IntTag(z)); if (paletteMaxTag != null && paletteObject.size() != paletteMaxTag.getValue()) {
values.put("id", id); throw new IOException("Block palette size does not match expected size.");
} }
Map<Integer, BlockState> palette = new HashMap<>();
ParserContext parserContext = new ParserContext();
parserContext.setRestricted(false);
parserContext.setTryLegacy(false);
parserContext.setPreferringWildcard(false);
for (String palettePart : paletteObject.keySet()) {
int id = requireTag(paletteObject, palettePart, IntTag.class).getValue();
if (fixer != null) {
palettePart = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, palettePart, dataVersion);
}
BlockState state;
try {
state = WorldEdit.getInstance().getBlockFactory().parseFromInput(palettePart, parserContext).toImmutableState();
} catch (InputParseException e) {
log.warn("Invalid BlockState in palette: " + palettePart + ". Block will be replaced with air.");
state = BlockTypes.AIR.getDefaultState();
}
palette.put(id, state);
}
byte[] blocks = requireTag(schematic, "BlockData", ByteArrayTag.class).getValue();
Map<BlockVector3, Map<String, Tag>> tileEntitiesMap = new HashMap<>();
ListTag tileEntities = getTag(schematic, "BlockEntities", ListTag.class);
if (tileEntities == null) {
tileEntities = getTag(schematic, "TileEntities", ListTag.class);
}
if (tileEntities != null) {
List<Map<String, Tag>> tileEntityTags = tileEntities.getValue().stream()
.map(tag -> (CompoundTag) tag)
.map(CompoundTag::getValue)
.collect(Collectors.toList());
for (Map<String, Tag> tileEntity : tileEntityTags) {
int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue();
final BlockVector3 pt = BlockVector3.at(pos[0], pos[1], pos[2]);
Map<String, Tag> values = Maps.newHashMap(tileEntity);
values.put("x", new IntTag(pt.getBlockX()));
values.put("y", new IntTag(pt.getBlockY()));
values.put("z", new IntTag(pt.getBlockZ()));
values.put("id", values.get("Id"));
values.remove("Id"); values.remove("Id");
values.remove("Pos"); values.remove("Pos");
if (fixer != null) {
tile = fixBlockEntity(tile); tileEntity = fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, new CompoundTag(values), dataVersion).getValue();
clipboard.setTile(x, y, z, tile);
}
}
// entities
if (entities != null && !entities.isEmpty()) {
for (Map<String, Object> entRaw : entities) {
CompoundTag ent = FaweCache.IMP.asTag(entRaw);
Map<String, Tag> value = ent.getValue();
StringTag id = (StringTag) value.get("Id");
if (id == null) {
id = (StringTag) value.get("id");
if (id == null) {
return null;
}
}
value.put("id", id);
value.remove("Id");
EntityType type = EntityTypes.parse(id.getValue());
if (type != null) {
ent = fixEntity(ent);
BaseEntity state = new BaseEntity(type, ent);
Location loc = ent.getEntityLocation(clipboard);
clipboard.createEntity(loc, state);
} else { } else {
log.debug("Invalid entity: " + id); tileEntity = values;
} }
tileEntitiesMap.put(pt, tileEntity);
} }
} }
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
clipboard.setOrigin(origin); clipboard.setOrigin(origin);
if (!min.equals(BlockVector3.ZERO)) { int index = 0;
new BlockArrayClipboard(clipboard, min); int i = 0;
int value;
int varintLength;
while (i < blocks.length) {
value = 0;
varintLength = 0;
while (true) {
value |= (blocks[i] & 127) << (varintLength++ * 7);
if (varintLength > 5) {
throw new IOException("VarInt too big (probably corrupted data)");
}
if ((blocks[i] & 128) != 128) {
i++;
break;
}
i++;
}
// index = (y * length * width) + (z * width) + x
int y = index / (width * length);
int z = (index % (width * length)) / width;
int x = (index % (width * length)) % width;
BlockState state = palette.get(value);
BlockVector3 pt = BlockVector3.at(x, y, z);
try {
if (tileEntitiesMap.containsKey(pt)) {
clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state.toBaseBlock(new CompoundTag(tileEntitiesMap.get(pt))));
} else {
clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state);
}
} catch (WorldEditException e) {
throw new IOException("Failed to load a block in the schematic");
}
index++;
} }
return clipboard; return clipboard;

View File

@ -19,61 +19,45 @@
package com.sk89q.worldedit.extent.clipboard.io; package com.sk89q.worldedit.extent.clipboard.io;
import com.boydti.fawe.jnbt.streamer.IntValueReader; import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.boydti.fawe.object.FaweOutputStream; import com.sk89q.jnbt.ByteArrayTag;
import com.boydti.fawe.object.clipboard.LinearClipboard;
import com.boydti.fawe.util.IOUtil;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntArrayTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.FloatTag;
import com.sk89q.jnbt.DoubleTag; import com.sk89q.jnbt.DoubleTag;
import com.sk89q.jnbt.NBTConstants; import com.sk89q.jnbt.FloatTag;
import com.sk89q.jnbt.IntArrayTag;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.ShortTag;
import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.visitor.Order;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.sk89q.worldedit.math.Vector3;
import java.util.Objects; import java.util.Objects;
import com.sk89q.worldedit.util.Location;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* Writes schematic files using the Sponge schematic format. * Writes schematic files using the Sponge schematic format.
*/ */
@Deprecated // High mem usage + slow
public class SpongeSchematicWriter implements ClipboardWriter { public class SpongeSchematicWriter implements ClipboardWriter {
private static final int CURRENT_VERSION = 2; private static final int CURRENT_VERSION = 2;
@ -94,15 +78,16 @@ public class SpongeSchematicWriter implements ClipboardWriter {
@Override @Override
public void write(Clipboard clipboard) throws IOException { public void write(Clipboard clipboard) throws IOException {
// For now always write the latest version. Maybe provide support for earlier if more appear. // For now always write the latest version. Maybe provide support for earlier if more appear.
write2(clipboard); outputStream.writeNamedTag("Schematic", new CompoundTag(write2(clipboard)));
} }
/** /**
* Writes a version 2 schematic file. * Writes a version 2 schematic file.
* *
* @param clipboard The clipboard * @param clipboard The clipboard
* @return The schematic map
*/ */
private void write2(Clipboard clipboard) throws IOException { private Map<String, Tag> write2(Clipboard clipboard) {
Region region = clipboard.getRegion(); Region region = clipboard.getRegion();
BlockVector3 origin = clipboard.getOrigin(); BlockVector3 origin = clipboard.getOrigin();
BlockVector3 min = region.getMinimumPoint(); BlockVector3 min = region.getMinimumPoint();
@ -121,222 +106,102 @@ public class SpongeSchematicWriter implements ClipboardWriter {
throw new IllegalArgumentException("Length of region too large for a .schematic"); throw new IllegalArgumentException("Length of region too large for a .schematic");
} }
final DataOutput rawStream = outputStream.getOutputStream(); Map<String, Tag> schematic = new HashMap<>();
outputStream.writeLazyCompoundTag("Schematic", out -> { schematic.put("Version", new IntTag(CURRENT_VERSION));
out.writeNamedTag("DataVersion", WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion()); schematic.put("DataVersion", new IntTag(
out.writeNamedTag("Version", CURRENT_VERSION); WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion()));
out.writeNamedTag("Width", (short) width);
out.writeNamedTag("Height", (short) height);
out.writeNamedTag("Length", (short) length);
// The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin' Map<String, Tag> metadata = new HashMap<>();
out.writeNamedTag("Offset", new int[]{ metadata.put("WEOffsetX", new IntTag(offset.getBlockX()));
min.getBlockX(), metadata.put("WEOffsetY", new IntTag(offset.getBlockY()));
min.getBlockY(), metadata.put("WEOffsetZ", new IntTag(offset.getBlockZ()));
min.getBlockZ(),
});
out.writeLazyCompoundTag("Metadata", out1 -> { schematic.put("Metadata", new CompoundTag(metadata));
out1.writeNamedTag("WEOffsetX", offset.getBlockX());
out1.writeNamedTag("WEOffsetY", offset.getBlockY());
out1.writeNamedTag("WEOffsetZ", offset.getBlockZ());
});
ByteArrayOutputStream blocksCompressed = new ByteArrayOutputStream(); schematic.put("Width", new ShortTag((short) width));
FaweOutputStream blocksOut = new FaweOutputStream(new DataOutputStream(new LZ4BlockOutputStream(blocksCompressed))); schematic.put("Height", new ShortTag((short) height));
schematic.put("Length", new ShortTag((short) length));
ByteArrayOutputStream tilesCompressed = new ByteArrayOutputStream(); // The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin'
NBTOutputStream tilesOut = new NBTOutputStream(new LZ4BlockOutputStream(tilesCompressed)); schematic.put("Offset", new IntArrayTag(new int[]{
min.getBlockX(),
min.getBlockY(),
min.getBlockZ(),
}));
List<Integer> paletteList = new ArrayList<>(); int paletteMax = 0;
char[] palette = new char[BlockTypesCache.states.length]; Map<String, Integer> palette = new HashMap<>();
Arrays.fill(palette, Character.MAX_VALUE);
int paletteMax = 0;
int numTiles = 0;
Clipboard finalClipboard;
if (clipboard instanceof BlockArrayClipboard) {
finalClipboard = ((BlockArrayClipboard) clipboard).getParent();
} else {
finalClipboard = clipboard;
}
Iterator<BlockVector3> iterator = finalClipboard.iterator(Order.YZX);
while (iterator.hasNext()) {
BlockVector3 pos = iterator.next();
BaseBlock block = pos.getFullBlock(finalClipboard);
CompoundTag nbt = block.getNbtData();
if (nbt != null) {
Map<String, Tag> values = nbt.getValue();
values.remove("id"); // Remove 'id' if it exists. We want 'Id' List<CompoundTag> tileEntities = new ArrayList<>();
ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * height * length);
for (int y = 0; y < height; y++) {
int y0 = min.getBlockY() + y;
for (int z = 0; z < length; z++) {
int z0 = min.getBlockZ() + z;
for (int x = 0; x < width; x++) {
int x0 = min.getBlockX() + x;
BlockVector3 point = BlockVector3.at(x0, y0, z0);
BaseBlock block = clipboard.getFullBlock(point);
if (block.getNbtData() != null) {
Map<String, Tag> values = new HashMap<>(block.getNbtData().getValue());
values.remove("id"); // Remove 'id' if it exists. We want 'Id'
// Positions are kept in NBT, we don't want that.
values.remove("x");
values.remove("y");
values.remove("z");
// Positions are kept in NBT, we don't want that.
values.remove("x");
values.remove("y");
values.remove("z");
if (!values.containsKey("Id")) {
values.put("Id", new StringTag(block.getNbtId())); values.put("Id", new StringTag(block.getNbtId()));
} values.put("Pos", new IntArrayTag(new int[]{
values.put("Pos", new IntArrayTag(new int[]{ x,
pos.getX(), y,
pos.getY(), z
pos.getZ() }));
}));
numTiles++;
tilesOut.writeTagPayload(block.getNbtData());
}
int ordinal = block.getOrdinal(); tileEntities.add(new CompoundTag(values));
char value = palette[ordinal];
if (value == Character.MAX_VALUE) {
int size = paletteMax++;
palette[ordinal] = value = (char) size;
paletteList.add(ordinal);
}
blocksOut.writeVarInt(value);
}
// close
tilesOut.close();
blocksOut.close();
out.writeNamedTag("PaletteMax", paletteMax);
out.writeLazyCompoundTag("Palette", out12 -> {
for (int i = 0; i < paletteList.size(); i++) {
int stateOrdinal = paletteList.get(i);
BlockState state = BlockTypesCache.states[stateOrdinal];
out12.writeNamedTag(state.getAsString(), i);
}
});
out.writeNamedTagName("BlockData", NBTConstants.TYPE_BYTE_ARRAY);
rawStream.writeInt(blocksOut.size());
try (LZ4BlockInputStream in = new LZ4BlockInputStream(new ByteArrayInputStream(blocksCompressed.toByteArray()))) {
IOUtil.copy(in, rawStream);
}
if (numTiles != 0) {
out.writeNamedTagName("TileEntities", NBTConstants.TYPE_LIST);
rawStream.write(NBTConstants.TYPE_COMPOUND);
rawStream.writeInt(numTiles);
try (LZ4BlockInputStream in = new LZ4BlockInputStream(new ByteArrayInputStream(tilesCompressed.toByteArray()))) {
IOUtil.copy(in, rawStream);
}
} else {
out.writeNamedEmptyList("TileEntities");
}
if (finalClipboard.hasBiomes()) {
writeBiomes(finalClipboard, out);
}
List<Tag> entities = new ArrayList<>();
for (Entity entity : finalClipboard.getEntities()) {
BaseEntity state = entity.getState();
if (state != null) {
Map<String, Tag> values = new HashMap<>();
// Put NBT provided data
CompoundTag rawTag = state.getNbtData();
if (rawTag != null) {
values.putAll(rawTag.getValue());
} }
// Store our location data, overwriting any String blockKey = block.toImmutableState().getAsString();
values.remove("id"); int blockId;
values.put("Id", new StringTag(state.getType().getId())); if (palette.containsKey(blockKey)) {
values.put("Pos", writeVector(entity.getLocation())); blockId = palette.get(blockKey);
values.put("Rotation", writeRotation(entity.getLocation())); } else {
blockId = paletteMax;
CompoundTag entityTag = new CompoundTag(values); palette.put(blockKey, blockId);
entities.add(entityTag); paletteMax++;
}
}
if (entities.isEmpty()) {
out.writeNamedEmptyList("Entities");
} else {
out.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities));
}
});
}
private void writeBiomes(Clipboard clipboard, NBTOutputStream out) throws IOException {
ByteArrayOutputStream biomesCompressed = new ByteArrayOutputStream();
DataOutputStream biomesOut = new DataOutputStream(new LZ4BlockOutputStream(biomesCompressed));
List<Integer> paletteList = new ArrayList<>();
int[] palette = new int[BiomeTypes.getMaxId() + 1];
Arrays.fill(palette, Integer.MAX_VALUE);
int[] paletteMax = {0};
IntValueReader task = new IntValueReader() {
@Override
public void applyInt(int index, int ordinal) {
try {
int value = palette[ordinal];
if (value == Integer.MAX_VALUE) {
int size = paletteMax[0]++;
palette[ordinal] = value = size;
paletteList.add(ordinal);
} }
IOUtil.writeVarInt(biomesOut, value);
} catch (IOException e) { while ((blockId & -128) != 0) {
e.printStackTrace(); buffer.write(blockId & 127 | 128);
blockId >>>= 7;
}
buffer.write(blockId);
} }
} }
};
BlockVector3 min = clipboard.getMinimumPoint();
int width = clipboard.getRegion().getWidth();
int length = clipboard.getRegion().getLength();
for (int z = 0, i = 0; z < length; z++) {
int z0 = min.getBlockZ() + z;
for (int x = 0; x < width; x++, i++) {
int x0 = min.getBlockX() + x;
BlockVector2 pt = BlockVector2.at(x0, z0);
BiomeType biome = clipboard.getBiome(pt);
task.applyInt(i, biome.getInternalId());
}
} }
biomesOut.close();
out.writeNamedTag("BiomePaletteMax", paletteMax[0]); schematic.put("PaletteMax", new IntTag(paletteMax));
out.writeLazyCompoundTag("BiomePalette", out12 -> { Map<String, Tag> paletteTag = new HashMap<>();
for (int i = 0; i < paletteList.size(); i++) { palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value)));
int ordinal = paletteList.get(i);
BiomeType state = BiomeTypes.get(ordinal);
out12.writeNamedTag(state.getId(), i);
}
});
out.writeNamedTagName("BiomeData", NBTConstants.TYPE_BYTE_ARRAY); schematic.put("Palette", new CompoundTag(paletteTag));
out.writeInt(biomesOut.size()); schematic.put("BlockData", new ByteArrayTag(buffer.toByteArray()));
try (LZ4BlockInputStream in = new LZ4BlockInputStream(new ByteArrayInputStream(biomesCompressed.toByteArray()))) { schematic.put("BlockEntities", new ListTag(CompoundTag.class, tileEntities));
IOUtil.copy(in, (DataOutput) out);
// version 2 stuff
if (clipboard.hasBiomes()) {
writeBiomes(clipboard, schematic);
} }
}
private void writeEntities(Clipboard clipboard, NBTOutputStream schematic) throws IOException { if (!clipboard.getEntities().isEmpty()) {
List<CompoundTag> entities = clipboard.getEntities().stream().map(e -> { writeEntities(clipboard, schematic);
BaseEntity state = e.getState();
if (state == null) {
return null;
}
Map<String, Tag> values = Maps.newHashMap();
CompoundTag rawData = state.getNbtData();
if (rawData != null) {
values.putAll(rawData.getValue());
}
values.remove("id");
values.put("Id", new StringTag(state.getType().getId()));
values.put("Pos", writeVector(e.getLocation().toVector()));
values.put("Rotation", writeRotation(e.getLocation()));
return new CompoundTag(values);
}).filter(Objects::nonNull).collect(Collectors.toList());
if (entities.isEmpty()) {
return;
} }
schematic.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities));
return schematic;
} }
private void writeBiomes(Clipboard clipboard, Map<String, Tag> schematic) { private void writeBiomes(Clipboard clipboard, Map<String, Tag> schematic) {
@ -408,7 +273,7 @@ public class SpongeSchematicWriter implements ClipboardWriter {
schematic.put("Entities", new ListTag(CompoundTag.class, entities)); schematic.put("Entities", new ListTag(CompoundTag.class, entities));
} }
private Tag writeVector(Vector3 vector) { public Tag writeVector(Vector3 vector) {
List<DoubleTag> list = new ArrayList<>(); List<DoubleTag> list = new ArrayList<>();
list.add(new DoubleTag(vector.getX())); list.add(new DoubleTag(vector.getX()));
list.add(new DoubleTag(vector.getY())); list.add(new DoubleTag(vector.getY()));
@ -416,7 +281,7 @@ public class SpongeSchematicWriter implements ClipboardWriter {
return new ListTag(DoubleTag.class, list); return new ListTag(DoubleTag.class, list);
} }
private Tag writeRotation(Location location) { public Tag writeRotation(Location location) {
List<FloatTag> list = new ArrayList<>(); List<FloatTag> list = new ArrayList<>();
list.add(new FloatTag(location.getYaw())); list.add(new FloatTag(location.getYaw()));
list.add(new FloatTag(location.getPitch())); list.add(new FloatTag(location.getPitch()));

View File

@ -22,8 +22,8 @@ package com.sk89q.worldedit.function.mask;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.EvaluationException;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.internal.expression.EvaluationException;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment;
@ -75,7 +75,8 @@ public class ExpressionMask extends AbstractMask {
if (timeout == null) { if (timeout == null) {
return expression.evaluate(vector.getX(), vector.getY(), vector.getZ()) > 0; return expression.evaluate(vector.getX(), vector.getY(), vector.getZ()) > 0;
} else { } else {
return expression.evaluateTimeout(timeout.getAsInt(), vector.getX(), vector.getY(), vector.getZ()) > 0; return expression.evaluate(new double[]{vector.getX(), vector.getY(), vector.getZ()},
timeout.getAsInt()) > 0;
} }
} catch (EvaluationException e) { } catch (EvaluationException e) {
return false; return false;

View File

@ -411,6 +411,7 @@ public class ForwardExtentCopy implements Operation {
} }
} }
int affected;
affected = region.getArea(); affected = region.getArea();
return null; return null;
} }

View File

@ -40,7 +40,6 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.io.file.FileSelectionAbortedException; import com.sk89q.worldedit.util.io.file.FileSelectionAbortedException;
import com.sk89q.worldedit.util.io.file.FilenameResolutionException; import com.sk89q.worldedit.util.io.file.FilenameResolutionException;
import com.sk89q.worldedit.util.io.file.InvalidFilenameException; import com.sk89q.worldedit.util.io.file.InvalidFilenameException;
import com.sk89q.worldedit.world.storage.MissingWorldException;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.exception.CommandException;

View File

@ -22,25 +22,23 @@ package com.sk89q.worldedit.internal.expression;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.SetMultimap; import com.google.common.collect.SetMultimap;
import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.antlr.ExpressionLexer; import com.sk89q.worldedit.antlr.ExpressionLexer;
import com.sk89q.worldedit.antlr.ExpressionParser; import com.sk89q.worldedit.antlr.ExpressionParser;
import com.sk89q.worldedit.session.request.Request;
import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.misc.ParseCancellationException; import org.antlr.v4.runtime.misc.ParseCancellationException;
import com.sk89q.worldedit.session.request.Request;
import org.antlr.v4.runtime.tree.ParseTreeWalker; import org.antlr.v4.runtime.tree.ParseTreeWalker;
import java.util.ArrayDeque;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.ExecutionException; import java.util.Stack;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@ -75,17 +73,16 @@ import java.util.concurrent.TimeoutException;
*/ */
public class Expression { public class Expression {
private static final ThreadLocal<ArrayDeque<Expression>> instance = ThreadLocal.withInitial(ArrayDeque::new); private static final ThreadLocal<Stack<Expression>> instance = new ThreadLocal<>();
private static final ExecutorService evalThread = Executors.newFixedThreadPool( private static final ExecutorService evalThread = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors(), Runtime.getRuntime().availableProcessors(),
new ThreadFactoryBuilder() new ThreadFactoryBuilder()
.setDaemon(true) .setDaemon(true)
.setNameFormat("worldedit-expression-eval-%d") .setNameFormat("worldedit-expression-eval-%d")
.build()); .build());
private final SlotTable slots = new SlotTable(); private final SlotTable slots = new SlotTable();
private final List<String> providedSlots; private final List<String> providedSlots;
private Variable[] variableArray;
private ExpressionParser.AllStatementsContext root; private ExpressionParser.AllStatementsContext root;
private final SetMultimap<String, MethodHandle> functions = Functions.getFunctionMap(); private final SetMultimap<String, MethodHandle> functions = Functions.getFunctionMap();
private ExpressionEnvironment environment; private ExpressionEnvironment environment;
@ -102,8 +99,8 @@ public class Expression {
for (String variableName : variableNames) { for (String variableName : variableNames) {
slots.initVariable(variableName) slots.initVariable(variableName)
.orElseThrow(() -> new ExpressionException(-1, .orElseThrow(() -> new ExpressionException(-1,
"Tried to overwrite identifier '" + variableName + "'")); "Tried to overwrite identifier '" + variableName + "'"));
} }
this.providedSlots = ImmutableList.copyOf(variableNames); this.providedSlots = ImmutableList.copyOf(variableNames);
@ -124,48 +121,16 @@ public class Expression {
ParseTreeWalker.DEFAULT.walk(new ExpressionValidator(slots.keySet(), functions), root); ParseTreeWalker.DEFAULT.walk(new ExpressionValidator(slots.keySet(), functions), root);
} }
public Expression(double constant) {
root = new Constant(0, constant);
}
public double evaluate(double x, double y, double z) throws EvaluationException {
return evaluateTimeout(WorldEdit.getInstance().getConfiguration().calculationTimeout, x, y, z);
}
public double evaluate() throws EvaluationException {
return evaluateFinal(WorldEdit.getInstance().getConfiguration().calculationTimeout);
}
public double evaluate(double... values) throws EvaluationException { public double evaluate(double... values) throws EvaluationException {
return evaluateTimeout(WorldEdit.getInstance().getConfiguration().calculationTimeout, values); return evaluate(values, WorldEdit.getInstance().getConfiguration().calculationTimeout);
}
private double evaluateTimeout(int timeout, double x, double y, double z) throws EvaluationException {
if (root instanceof Constant) return root.getValue();
variableArray[0].value = x;
variableArray[1].value = y;
variableArray[2].value = z;
return evaluateFinal(timeout);
}
public double evaluateTimeout(int timeout, double... values) throws EvaluationException {
if (root instanceof Constant) return root.getValue();
for (int i = 0; i < values.length; ++i) {
final Variable var = variableArray[i];
var.value = values[i];
}
return evaluateFinal(timeout);
} }
public double evaluate(double[] values, int timeout) throws EvaluationException { public double evaluate(double[] values, int timeout) throws EvaluationException {
if (root instanceof Constant) {
return root.getValue();
}
for (int i = 0; i < values.length; ++i) { for (int i = 0; i < values.length; ++i) {
String slotName = providedSlots.get(i); String slotName = providedSlots.get(i);
LocalSlot.Variable slot = slots.getVariable(slotName) LocalSlot.Variable slot = slots.getVariable(slotName)
.orElseThrow(() -> new EvaluationException(-1, .orElseThrow(() -> new EvaluationException(-1,
"Tried to assign to non-variable " + slotName + ".")); "Tried to assign to non-variable " + slotName + "."));
slot.setValue(values[i]); slot.setValue(values[i]);
} }
@ -177,17 +142,6 @@ public class Expression {
return evaluateRootTimed(timeout); return evaluateRootTimed(timeout);
} }
private double evaluateFinal(int timeout) throws EvaluationException {
try {
if (timeout < 0) {
return evaluateRoot();
}
return evaluateRootTimed(timeout);
} catch (ReturnException e) {
return e.getValue();
} // other evaluation exceptions are thrown out of this method
}
private double evaluateRootTimed(int timeout) throws EvaluationException { private double evaluateRootTimed(int timeout) throws EvaluationException {
CountDownLatch startLatch = new CountDownLatch(1); CountDownLatch startLatch = new CountDownLatch(1);
Request request = Request.request(); Request request = Request.request();
@ -233,32 +187,36 @@ public class Expression {
// TODO optimizing // TODO optimizing
} }
public SlotTable getSlots() {
return slots;
}
public RValue getRoot() {
return root;
}
@Override @Override
public String toString() { public String toString() {
return root.toString(); return root.toString();
} }
public SlotTable getSlots() {
return slots;
}
public static Expression getInstance() { public static Expression getInstance() {
return instance.get().peek(); return instance.get().peek();
} }
private void pushInstance() { private void pushInstance() {
ArrayDeque<Expression> foo = instance.get(); Stack<Expression> threadLocalExprStack = instance.get();
foo.push(this); if (threadLocalExprStack == null) {
instance.set(threadLocalExprStack = new Stack<>());
}
threadLocalExprStack.push(this);
} }
private void popInstance() { private void popInstance() {
ArrayDeque<Expression> foo = instance.get(); Stack<Expression> threadLocalExprStack = instance.get();
foo.pop(); threadLocalExprStack.pop();
if (threadLocalExprStack.isEmpty()) {
instance.set(null);
}
} }
public ExpressionEnvironment getEnvironment() { public ExpressionEnvironment getEnvironment() {

View File

@ -0,0 +1,52 @@
/*
* 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.math;
public final class BitMath {
public static int mask(int bits) {
return ~(~0 << bits);
}
public static int unpackX(long packed) {
return extractSigned(packed, 0, 26);
}
public static int unpackZ(long packed) {
return extractSigned(packed, 26, 26);
}
public static int unpackY(long packed) {
return extractSigned(packed, 26 + 26, 12);
}
public static int extractSigned(long i, int shift, int bits) {
return fixSign((int) (i >> shift) & mask(bits), bits);
}
public static int fixSign(int i, int bits) {
// Using https://stackoverflow.com/a/29266331/436524
return i << (32 - bits) >> (32 - bits);
}
private BitMath() {
}
}

View File

@ -124,7 +124,7 @@ public abstract class BlockVector3 {
public long toLongPackedForm() { public long toLongPackedForm() {
checkLongPackable(this); checkLongPackable(this);
return (x & BITS_26) | ((z & BITS_26) << 26) | (((y & (long) BITS_12) << (26 + 26))); return (getX() & BITS_26) | ((getZ() & BITS_26) << 26) | (((getY() & (long) BITS_12) << (26 + 26)));
} }
public MutableBlockVector3 mutX(double x) { public MutableBlockVector3 mutX(double x) {

View File

@ -54,7 +54,15 @@ public interface Subject {
* @param permission the permission * @param permission the permission
* @return false if the permission was removed, true if this subject has permission * @return false if the permission was removed, true if this subject has permission
*/ */
boolean togglePermission(String permission); default boolean togglePermission(String permission) {
if (this.hasPermission(permission)) {
setPermission(permission, false);
return false;
} else {
setPermission(permission, true);
return true;
}
}
void setPermission(String permission, boolean value); void setPermission(String permission, boolean value);
} }

View File

@ -103,15 +103,16 @@ public class BlockType implements FawePattern, Keyed {
return name; return name;
} }
} }
/*
private BlockState computeDefaultState() { private BlockState computeDefaultState() {
BlockState defaultState = Iterables.getFirst(getBlockStatesMap().values(), null); BlockState defaultState = Iterables.getFirst(getBlockStatesMap().values(), null);
if (values != null) { if (values != null) {
defaultState = values.apply(defaultState); defaultState = values.apply(defaultState);
} }
return defaultState; return defaultState;
} }
*/
@Deprecated @Deprecated
public BlockState withPropertyId(int propertyId) { public BlockState withPropertyId(int propertyId) {
if (settings.stateOrdinals == null) return settings.defaultState; if (settings.stateOrdinals == null) return settings.defaultState;

View File

@ -102,7 +102,7 @@ public final class LegacyMapper {
Integer combinedId = getCombinedId(blockEntry.getKey()); Integer combinedId = getCombinedId(blockEntry.getKey());
final String value = blockEntry.getValue(); final String value = blockEntry.getValue();
blockEntries.put(id, value); blockEntries.put(id, value);
BlockState blockState; BlockState blockState = null;
try { try {
blockState = BlockState.get(null, blockEntry.getValue()); blockState = BlockState.get(null, blockEntry.getValue());
BlockType type = blockState.getBlockType(); BlockType type = blockState.getBlockType();
@ -114,10 +114,10 @@ public final class LegacyMapper {
String newEntry = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, value, 1631); String newEntry = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, value, 1631);
try { try {
blockState = WorldEdit.getInstance().getBlockFactory().parseFromInput(newEntry, parserContext).toImmutableState(); blockState = WorldEdit.getInstance().getBlockFactory().parseFromInput(newEntry, parserContext).toImmutableState();
} catch (InputParseException ignored) { } catch (InputParseException ignored) {}
log.warn("Unknown block: " + value); }
continue; if (blockState == null) {
} log.warn("Unknown block: " + value);
} }
} }
blockArr[combinedId] = blockState.getInternalId(); blockArr[combinedId] = blockState.getInternalId();
@ -135,9 +135,21 @@ public final class LegacyMapper {
} }
for (Map.Entry<String, String> itemEntry : dataFile.items.entrySet()) { for (Map.Entry<String, String> itemEntry : dataFile.items.entrySet()) {
try { String id = itemEntry.getKey();
itemMap.put(getCombinedId(itemEntry.getKey()), ItemTypes.get(itemEntry.getValue())); String value = itemEntry.getValue();
ItemType type = ItemTypes.get(value);
if (type == null && fixer != null) {
value = fixer.fixUp(DataFixer.FixTypes.ITEM_TYPE, value, 1631);
type = ItemTypes.get(value);
} }
if (type != null) {
try {
itemMap.put(getCombinedId(id), type);
continue;
} catch (Exception e) {
}
}
log.warn("Unknown item: " + value);
} }
} }