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

View File

@ -230,16 +230,6 @@ public class BukkitPlayer extends AbstractPlayerActor {
|| 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
public boolean isAllowedToFly() {
return player.getAllowFlight();
@ -257,13 +247,13 @@ public class BukkitPlayer extends AbstractPlayerActor {
* - The `/wea` command will give/remove the required bypass permission
*/
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) {
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)) {
player.addAttachment(Fawe.<FaweBukkit>imp().getPlugin()).setPermission(permission, value);
player.addAttachment(plugin).setPermission(permission, value);
}
}

View File

@ -10,6 +10,7 @@ plugins {
repositories {
maven { url = uri("http://ci.athion.net/job/PlotSquared-breaking/ws/mvn/") }
}
applyPlatformAndCoreConfiguration()
@ -23,7 +24,7 @@ configurations.all {
dependencies {
"compile"(project(":worldedit-libs:core"))
"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"("com.google.guava:guava:21.0")
"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.function.mask.Mask;
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.ExpressionException;
import com.sk89q.worldedit.internal.expression.runtime.Constant;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@ -39,6 +38,8 @@ public class BrushSettings {
SCROLL_ACTION,
}
private static final Expression DEFAULT_SIZE = Expression.compile("1");
private final Map<SettingType, Object> constructor = new ConcurrentHashMap<>();
private Brush brush;
@ -46,7 +47,7 @@ public class BrushSettings {
private Mask sourceMask;
private ResettableExtent transform;
private Pattern material;
private Expression size = new Expression(1);
private Expression size = DEFAULT_SIZE;
private Set<String> permissions;
private Scroll scrollAction;
private String lastWorld;
@ -135,7 +136,7 @@ public class BrushSettings {
transform = null;
material = null;
scrollAction = null;
size = new Expression(1);
size = DEFAULT_SIZE;
permissions.clear();
constructor.clear();
return this;
@ -182,7 +183,7 @@ public class BrushSettings {
public BrushSettings setSize(Expression size) {
checkNotNull(size);
this.size = size;
if (size.getRoot() instanceof Constant && ((Constant) size.getRoot()).getValue() == -1) {
if (size == DEFAULT_SIZE) {
constructor.remove(SettingType.SIZE);
} else {
constructor.put(SettingType.SIZE, size.toString());
@ -191,7 +192,7 @@ public class BrushSettings {
}
public BrushSettings setSize(double size) {
return setSize(new Expression(size));
return setSize(Expression.compile(Double.toString(size)));
}
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 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.ExpressionException;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment;
import com.sk89q.worldedit.world.block.BaseBlock;
@ -49,7 +49,7 @@ public class ExpressionPattern extends AbstractPattern {
((WorldEditExpressionEnvironment) expression.getEnvironment()).setCurrentBlock(vector.toVector3());
}
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) {
e.printStackTrace();
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.Clipboard;
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.regions.CuboidRegion;
import java.io.BufferedOutputStream;
@ -78,7 +78,7 @@ public class FaweSchematicHandler extends SchematicHandler {
if (cTag instanceof CompressedSchematicTag) {
Clipboard clipboard = (Clipboard) cTag.getSource();
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 {
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.FastByteArraysInputStream;
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.LZ4BlockOutputStream;
@ -19,7 +19,7 @@ public class CompressedSchematicTag extends CompressedCompoundTag<Clipboard> {
FastByteArrayOutputStream blocksOut = new FastByteArrayOutputStream();
try (LZ4BlockOutputStream lz4out = new LZ4BlockOutputStream(blocksOut)) {
NBTOutputStream nbtOut = new NBTOutputStream(lz4out);
new SpongeSchematicWriter(nbtOut).write(getSource());
new FastSchematicWriter(nbtOut).write(getSource());
} catch (IOException 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.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.registry.LegacyMapper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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.
* Use {@link #stackCuboidRegion(Region, BlockVector3, int, boolean, boolean, boolean)} to fine tune.
* Stack a cuboid region. For compatibility, entities are copied by biomes are not.
* 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 dir the direction to stack
@ -1439,7 +1454,8 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* @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, 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(dir);
checkArgument(count >= 1, "count >= 1 required");
@ -1451,14 +1467,10 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
copy.setCopyingBiomes(copyBiomes);
copy.setRepetitions(count);
copy.setTransform(new AffineTransform().translate(dir.multiply(size)));
Mask sourceMask = getSourceMask();
if (sourceMask != null) {
new MaskTraverser(sourceMask).reset(EditSession.this);
copy.setSourceMask(sourceMask);
mask = MaskIntersection.of(getSourceMask(), mask).optimize();
if (mask != Masks.alwaysTrue()) {
setSourceMask(null);
}
if (!copyAir) {
copy.setSourceMask(new ExistingBlockMask(this));
copy.setSourceMask(mask);
}
Operations.completeBlindly(copy);
return this.changes = copy.getAffected();
@ -2327,15 +2339,15 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* @throws MaxChangedBlocksException
*/
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 {
final Expression expression = Expression.compile(expressionString, "x", "y", "z", "type", "data");
expression.optimize();
final Variable typeVariable = expression.getSlots().getVariable("type")
.orElseThrow(IllegalStateException::new);
.orElseThrow(IllegalStateException::new);
final Variable dataVariable = expression.getSlots().getVariable("data")
.orElseThrow(IllegalStateException::new);
.orElseThrow(IllegalStateException::new);
final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero);
expression.setEnvironment(environment);
@ -2349,12 +2361,26 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
final Vector3 scaled = current.subtract(zero).divide(unit);
try {
if (expression.evaluateTimeout(timeout, scaled.getX(), scaled.getY(), scaled.getZ(), defaultMaterial.getBlockType().getInternalId(), defaultMaterial.getInternalPropertiesId()) <= 0) {
// TODO data
int[] legacy = LegacyMapper.getInstance().getLegacyFromBlock(defaultMaterial.toImmutableState());
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 BlockTypes.get((int) typeVariable.getValue()).withPropertyId((int) dataVariable.getValue()).toBaseBlock();
int newType = (int) typeVariable.getValue();
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) {
timedOut[0] = timedOut[0] + 1;
return null;
@ -2404,7 +2430,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
final Vector3 scaled = position.toVector3().subtract(zero).divide(unit);
// 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 yv = (int) (y.getValue() * unit.getY() + zero2.getY());
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.BlockState;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.snapshot.Snapshot;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.io.File;
@ -147,7 +148,6 @@ public class LocalSession implements TextureHolder {
private transient ResettableExtent transform = null;
private transient ZoneId timezone = ZoneId.systemDefault();
private transient World currentWorld;
private transient boolean tickingWatchdog = false;
private transient UUID uuid;
private transient volatile long historySize = 0;
@ -992,6 +992,8 @@ public class LocalSession implements TextureHolder {
return getTool(item, player);
}
private transient boolean loadDefaults = true;
public Tool getTool(BaseItem item, Player player) {
if (Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES && item.getNativeItem() != null) {
BrushTool tool = BrushCache.getTool(player, this, item);
@ -1612,7 +1614,9 @@ public class LocalSession implements TextureHolder {
private void prepareEditingExtents(EditSession editSession, Actor actor) {
editSession.setFastMode(fastMode);
/*
editSession.setReorderMode(reorderMode);
*/
if (editSession.getSurvivalExtent() != null) {
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.pattern.Pattern;
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.scripting.CraftScriptContext;
import com.sk89q.worldedit.scripting.CraftScriptEngine;
@ -397,8 +395,8 @@ public final class WorldEdit {
public void checkMaxBrushRadius(Expression radius) throws MaxBrushRadiusException {
if (getConfiguration().maxBrushRadius > 0) {
RValue r = radius.getRoot();
if (r instanceof Constant && ((Constant) r).getValue() > getConfiguration().maxBrushRadius) {
double val = radius.evaluate();
if (val > getConfiguration().maxBrushRadius) {
throw new MaxBrushRadiusException();
}
}

View File

@ -97,7 +97,7 @@ public class ApplyBrushCommands {
Contextual<? extends RegionFunction> generatorFactory) throws WorldEditException {
double radius = requireNonNull(RADIUS.value(parameters).asSingle(double.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");
}

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.RegionVisitor;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.FlatRegion;
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.pattern.Pattern;
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.runtime.EvaluationException;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
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.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key;
import org.jetbrains.annotations.Range;
import static com.google.common.base.Preconditions.checkNotNull;
@ -308,7 +308,7 @@ public class BrushCommands {
)
@CommandPermissions("worldedit.brush.spline")
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")
Expression radius,
@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,
@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(def = "0", desc = "rotation") @Range(from=0, to=360) int rotation,
@Arg(desc = "double", def = "1") double yscale,
@Switch(name = 'w', desc = "Apply at maximum saturation") boolean onlyWhite,
@Switch(name = 'r', desc = "Apply random rotation") boolean randomRotate) throws WorldEditException, FileNotFoundException {
@ -470,7 +470,7 @@ public class BrushCommands {
@Arg(desc = "Expression", def = "5")
Expression radius,
ProvideBindings.ImageUri imageUri,
@Arg(def = "1", desc = "scale height") @Range(min = Double.MIN_NORMAL)
@Arg(def = "1", desc = "scale height")
double yscale,
@Switch(name = 'a', desc = "Use image Alpha")
boolean alpha,
@ -660,13 +660,14 @@ public class BrushCommands {
boolean ignoreAir,
@Switch(name = 'o', desc = "Paste starting at the target location, instead of centering on it")
boolean usingOrigin,
@Switch(name = 'e', desc = "Paste entities if available")
boolean pasteEntities,
@Switch(name = 'e', desc = "Skip paste entities if available")
boolean skipEntities,
@Switch(name = 'b', desc = "Paste biomes if available")
boolean pasteBiomes,
@ArgFlag(name = 'm', desc = "Skip blocks matching this mask in the clipboard", def = "")
@ClipboardMask
Mask sourceMask) throws WorldEditException {
Mask sourceMask,
InjectedValueAccess context) throws WorldEditException {
ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard();
@ -695,7 +696,8 @@ public class BrushCommands {
@Arg(desc = "The number of iterations to perform", def = "4")
int iterations,
@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);
FaweLimit limit = Settings.IMP.getLimit(player);
@ -752,7 +754,7 @@ public class BrushCommands {
"Snow Pic: https://i.imgur.com/Hrzn0I4.png"
)
@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);
}
@ -768,7 +770,7 @@ public class BrushCommands {
Expression radius,
@Arg(desc = "String", def = "")
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,
@Arg(desc = "double", def = "1")
double yscale,
@ -787,7 +789,7 @@ public class BrushCommands {
desc = "This brush raises or lowers land towards the clicked point"
)
@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")
boolean randomRotate,
@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.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.extent.PasteEvent;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.Extent;
@ -314,8 +316,8 @@ public class ClipboardCommands {
}
}
final LocalConfiguration config = this.worldEdit.getConfiguration();
final File working = this.worldEdit.getWorkingDirectoryFile(config.saveDir).getAbsoluteFile();
final LocalConfiguration config = WorldEdit.getInstance().getConfiguration();
final File working = WorldEdit.getInstance().getWorkingDirectoryFile(config.saveDir).getAbsoluteFile();
url = MainUtil.upload(null, null, "zip", new RunnableVal<OutputStream>() {
@Override
@ -484,7 +486,7 @@ public class ClipboardCommands {
uri = ((URIClipboardHolder) holder).getURI(clipboard);
}
PasteEvent event = new PasteEvent(player, clipboard, uri, editSession, to);
worldEdit.getEventBus().post(event);
WorldEdit.getInstance().getEventBus().post(event);
if (event.isCancelled()) {
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MANUAL);
}

View File

@ -342,7 +342,7 @@ public class GeneralCommands {
desc = "Set the global mask"
)
@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>
// TODO NOT IMPLEMENTED convert this to an ArgumentConverter
if (arguments.isEmpty()) {
@ -375,7 +375,7 @@ public class GeneralCommands {
} else {
ParserContext parserContext = new ParserContext();
parserContext.setActor(player);
parserContext.setWorld(world);
parserContext.setWorld(worldArg);
parserContext.setSession(session);
parserContext.setExtent(editSession);
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.visitor.RegionVisitor;
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.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.math.BlockVector2;
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 org.enginehub.piston.inject.InjectedValueAccess;
import org.jetbrains.annotations.Range;
/**
* Commands for the generation of shapes and other objects.
@ -173,7 +174,7 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.ore")
@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(() -> {
editSession.addOre(region, mask, material, size, freq, rarity, minY, maxY);
BBC.VISITOR_BLOCK.send(actor, editSession.getBlockChangeCount());
@ -186,15 +187,14 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.cylinder")
@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")
Pattern pattern,
@Arg(desc = "The radii of the cylinder. 1st is N/S, 2nd is E/W")
@Radii(2)
List<Double> radii,
BlockVector2 radii,
@Arg(desc = "The height of the cylinder", def = "1")
int height) throws WorldEditException {
return cyl(actor, session, editSession, pattern, radii, height, true);
cyl(actor, session, editSession, pattern, radii, height, true, context);
}
@Command(
@ -206,7 +206,7 @@ public class GenerationCommands {
public void cyl(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to generate")
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")
int height,
@Switch(name = 'h', desc = "Make a hollow cylinder")
@ -293,9 +293,12 @@ public class GenerationCommands {
@Logging(POSITION)
public int pumpkins(Actor actor, LocalSession session, EditSession editSession,
@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);
int affected = editSession.makePumpkinPatches(session.getPlacementPosition(actor), size);
int affected = editSession.makePumpkinPatches(session.getPlacementPosition(actor), size, density);
actor.print(affected + " pumpkin patches created.");
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.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.annotation.Range;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
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.Switch;
import org.enginehub.piston.inject.InjectedValueAccess;
import org.jetbrains.annotations.Range;
import static com.google.common.base.Preconditions.checkNotNull;
@ -83,7 +83,7 @@ public class HistoryCommands {
" - Import from disk: /frb #import"
)
@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) {
BBC.SETTING_DISABLE.send(player, "history.use-database (Import with /frb #import )");
return;
@ -214,32 +214,22 @@ public class HistoryCommands {
" - Import from disk: /frb #import"
)
@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);
}
@Command(
name = "/undo",
aliases = { "/un", "/ud", "undo" },
desc = "Undoes the last action (from history)"
name = "/undo",
aliases = { "/un", "/ud", "undo" },
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"})
public void undo(Player player, LocalSession session,
@Range(min = 1) @Arg(desc = "Number of undoes to perform", def = "1")
int times,
@Arg(name = "player", desc = "Undo this player's operations", def = "")
String playerName,
InjectedValueAccess context) throws WorldEditException {
@Arg(desc = "Number of undoes to perform", def = "1")
int times,
@Arg(name = "player", desc = "Undo this player's operations", def = "")
String playerName,
InjectedValueAccess context) throws WorldEditException {
times = Math.max(1, times);
LocalSession undoSession;
if (session.hasFastMode()) {
@ -253,6 +243,16 @@ public class HistoryCommands {
BBC.COMMAND_HISTORY_OTHER_ERROR.send(player, playerName);
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);
}
if (undone == null) i--;
@ -272,7 +272,7 @@ public class HistoryCommands {
)
@CommandPermissions({"worldedit.history.redo", "worldedit.history.redo.self"})
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,
@Arg(name = "player", desc = "Redo this player's operations", def = "")
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.SolidBlockMask;
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.runtime.ExpressionEnvironment;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
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 density = requireNonNull(DENSITY.value(parameters).asSingle(double.class)) / 100;
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");
}

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.Pattern;
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.ExpressionException;
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.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.jetbrains.annotations.Range;
//@Command(aliases = {"patterns"},
// 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" +
" - 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);
}

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.LayerVisitor;
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.expression.ExpressionException;
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.Switch;
import org.enginehub.piston.inject.InjectedValueAccess;
import org.jetbrains.annotations.Range;
import java.util.ArrayList;
import java.util.Collections;
@ -254,7 +254,7 @@ public class RegionCommands {
desc = "Set block lighting in a selection"
)
@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
}
@ -263,7 +263,7 @@ public class RegionCommands {
desc = "Set sky lighting in a selection"
)
@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
}
@ -314,7 +314,7 @@ public class RegionCommands {
boolean shell, InjectedValueAccess context) throws WorldEditException {
if (!(region instanceof ConvexPolyhedralRegion)) {
actor.printError("//curve only works with convex polyhedral selections");
return 0;
return;
}
checkCommandArgument(thickness >= 0, "Thickness must be >= 0");
@ -523,22 +523,24 @@ public class RegionCommands {
@CommandPermissions("worldedit.region.move")
@Logging(ORIENTATION_REGION)
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")
int count,
int count,
@Arg(desc = "The direction to move", def = Direction.AIM)
@Direction(includeDiagonals = true)
BlockVector3 direction,
BlockVector3 direction,
@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")
boolean moveSelection,
boolean moveSelection,
@Switch(name = 'a', desc = "Ignore air blocks")
boolean ignoreAirBlocks,
@Switch(name = 'e', desc = "Ignore entities")
boolean skipEntities,
boolean ignoreAirBlocks,
@Switch(name = 'e', desc = "Skip copy entities")
boolean skipEntities,
@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 {
checkCommandArgument(count >= 1, "Count must be >= 1");
@ -554,7 +556,7 @@ public class RegionCommands {
}
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) {
try {
@ -612,7 +614,7 @@ public class RegionCommands {
@Switch(name = 'b', desc = "Also copy biomes")
boolean copyBiomes,
@ArgFlag(name = 'm', desc = "Source mask", def="")
Mask sourceMask,
Mask mask,
InjectedValueAccess context) throws WorldEditException {
Mask combinedMask;
@ -627,9 +629,6 @@ public class RegionCommands {
}
actor.checkConfirmationStack(() -> {
if (sourceMask != null) {
editSession.addSourceMask(sourceMask);
}
int affected = editSession.stackCuboidRegion(region, direction, count, !skipEntities, copyBiomes, combinedMask);
if (moveSelection) {
@ -751,7 +750,7 @@ public class RegionCommands {
@Logging(REGION)
public void hollow(Actor actor, EditSession editSession,
@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,
@Arg(desc = "The pattern of blocks to replace the hollowed area with", def = "air")
Pattern pattern,
@ -799,6 +798,7 @@ public class RegionCommands {
visitor.setMask(new NoiseFilter2D(new RandomNoise(), density / 100));
Operations.completeLegacy(visitor);
int affected = ground.getAffected();
actor.print(affected + " flora created.");
}, "/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) {
Collection<URI> uris = Collections.emptyList();
if (clipboard instanceof URIClipboardHolder) {
@ -853,17 +810,43 @@ public class SchematicCommands {
)
@CommandPermissions("worldedit.schematic.delete")
public void delete(Actor actor,
LocalSession session,
@Arg(desc = "File name.")
String filename) throws WorldEditException {
String filename) throws WorldEditException, IOException {
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,
dir, filename, "schematic", ClipboardFormats.getFileExtensionArray());
if (filename.equalsIgnoreCase("*")) {
files.addAll(getFiles(session.getClipboard()));
} else {
File f = MainUtil.resolveRelative(new File(dir, filename));
files.add(f);
}
if (!f.exists()) {
actor.printError("Schematic " + filename + " does not exist!");
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 boolean delete(File file) {
if (file.delete()) {
new File(file.getParentFile(), "." + file.getName() + ".cached").delete();

View File

@ -58,15 +58,6 @@ public class ScriptingCommands {
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(
name = "cs",
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.format.TextColor;
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.ItemTypes;
import com.sk89q.worldedit.world.storage.ChunkStore;
@ -108,6 +109,7 @@ public class SelectionCommands {
@Command(
name = "/pos1",
aliases = "/1",
desc = "Set position 1"
)
@Logging(POSITION)
@ -136,6 +138,7 @@ public class SelectionCommands {
@Command(
name = "/pos2",
aliases = "/2",
desc = "Set position 2"
)
@Logging(POSITION)
@ -544,7 +547,7 @@ public class SelectionCommands {
if (distribution.isEmpty()) { // *Should* always be false
actor.printError("No blocks counted.");
player.printError("No blocks counted.");
return;
}

View File

@ -19,9 +19,6 @@
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.LocalConfiguration;
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.storage.ChunkStore;
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.CommandContainer;
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)
public class SnapshotUtilCommands {
@ -55,15 +55,15 @@ public class SnapshotUtilCommands {
}
@Command(
name = "restore",
aliases = { "/restore" },
desc = "Restore the selection from a snapshot"
name = "restore",
aliases = { "/restore" },
desc = "Restore the selection from a snapshot"
)
@Logging(REGION)
@CommandPermissions("worldedit.snapshots.restore")
public void restore(Actor actor, World world, LocalSession session, EditSession editSession,
@Arg(name = "snapshot", desc = "The snapshot to restore", def = "")
String snapshotName) throws WorldEditException {
String snapshotName) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
@ -98,10 +98,10 @@ public class SnapshotUtilCommands {
File dir = config.snapshotRepo.getDirectory();
try {
WorldEdit.logger.info("FAWE found no snapshots: looked in: "
WorldEdit.logger.info("WorldEdit found no snapshots: looked in: "
+ dir.getCanonicalPath());
} 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?): "
+ dir.getPath());
}
@ -125,6 +125,7 @@ public class SnapshotUtilCommands {
return;
}
try {
// Restore snapshot
SnapshotRestore restore = new SnapshotRestore(chunkStore, editSession, region);
//player.print(restore.getChunksAffected() + " chunk(s) will be loaded.");
@ -143,12 +144,15 @@ public class SnapshotUtilCommands {
}
} else {
actor.print(String.format("Restored; %d "
+ "missing chunks and %d other errors.",
+ "missing chunks and %d other errors.",
restore.getMissingChunks().size(),
restore.getErrorChunks().size()));
}
} catch (DataException | IOException e) {
actor.printError("Failed to load snapshot: " + e.getMessage());
} finally {
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.function.mask.Mask;
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.util.HandSide;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch;
import org.jetbrains.annotations.Range;
import java.util.List;
@ -253,7 +253,7 @@ public class ToolUtilCommands {
)
@CommandPermissions("worldedit.brush.visualize")
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)
throws WorldEditException {
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.SkipQueue;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
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.visitor.EntityVisitor;
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.ExpressionException;
@ -95,15 +96,13 @@ import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.annotation.param.Switch;
import org.enginehub.piston.exception.StopExecutionException;
import org.jetbrains.annotations.Range;
/**
* Utility commands.
*/
@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 {
private final WorldEdit we;
@ -201,9 +200,9 @@ public class UtilityCommands {
public int fill(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The blocks to fill with")
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,
@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,
@Arg(desc = "The direction to move", def = "down")
@Direction BlockVector3 direction) throws WorldEditException, EvaluationException {
@ -745,7 +744,7 @@ public class UtilityCommands {
}
try {
if (!MainUtil.isInSubDirectory(root, file)) {
throw new RuntimeException(new CommandException("Invalid path"));
throw new RuntimeException(new StopExecutionException(TextComponent.of("Invalid path")));
}
} catch (IOException ignore) {
}

View File

@ -1,18 +1,12 @@
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.ExpressionException;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.world.World;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.ArgumentConverter;
import org.enginehub.piston.converter.ConversionResult;
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.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key;
@ -32,16 +26,11 @@ public class ExpressionConverter implements ArgumentConverter<Expression> {
public ConversionResult<Expression> convert(String s, InjectedValueAccess injectedValueAccess) {
Expression expression;
try {
expression = new Expression(Double.parseDouble(s));
} catch (NumberFormatException e1) {
try {
expression = Expression.compile(s);
expression.optimize();
return SuccessfulConversion.fromSingle(expression);
} catch (Exception e) {
return FailedConversion.from(e);
}
expression = Expression.compile(s);
expression.optimize();
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.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
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.BlockTypes;
import java.util.Set;
/**
* A pickaxe mode that recursively finds adjacent blocks within range of
* an initial block and of the same type.

View File

@ -29,6 +29,7 @@ import java.util.LinkedHashSet;
import java.util.Set;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.util.collection.LocatedBlockList;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
public class GravityBrush implements Brush {
@ -53,15 +54,11 @@ public class GravityBrush implements Brush {
if (y != freeSpot) {
editSession.setBlock((int)x, (int)y, (int)z, BlockTypes.AIR.getDefaultState());
editSession.setBlock((int)x, (int)freeSpot, (int)z, block);
}
}
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 java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.entity.EntityTypes;
import java.util.Map;
import java.util.stream.Collectors;
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
if (blockType == null) {
if (state == null) {
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
if (blockAndExtraData.length > 1) {
String mobName = blockAndExtraData[1];
for (MobType mobType : MobType.values()) {
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()));
}
EntityType mobType = EntityTypes.parse(mobName);
return validate(context, new MobSpawnerBlock(state, mobName));
} 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) {
// allow setting type/player/rotation

View File

@ -19,9 +19,16 @@
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 java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class AbstractNonPlayerActor implements Actor {
@ -48,4 +55,61 @@ public abstract class AbstractNonPlayerActor implements Actor {
@Override
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(
commandManager,
ClipboardCommandsRegistration.builder(),
new ClipboardCommands(worldEdit)
new ClipboardCommands()
);
this.registration.register(
commandManager,
@ -523,7 +523,7 @@ public final class PlatformCommandManager {
this.registration.register(
commandManager,
RegionCommandsRegistration.builder(),
new RegionCommands(worldEdit)
new RegionCommands()
);
this.registration.register(
commandManager,

View File

@ -415,7 +415,6 @@ public class PlatformManager {
player.runAsyncIfFree(() -> reset((DoubleActionTraceTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING),
getConfiguration(), player, session));
event.setCancelled(true);
}
return;
}
@ -429,7 +428,6 @@ public class PlatformManager {
player.runAction(() -> reset((TraceTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING),
getConfiguration(), player, session), false, true);
event.setCancelled(true);
}
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.extent.Extent;
import com.sk89q.worldedit.internal.annotation.Direction;
import com.sk89q.worldedit.internal.annotation.Validate;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.TreeGenerator;
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.platform.Actor;
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.ExpressionException;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector2;
@ -38,19 +37,15 @@ public class PrimitiveBindings extends Bindings {
@Binding
public Expression getExpression(String argument) throws ExpressionException {
try {
return new Expression(Double.parseDouble(argument));
} catch (NumberFormatException e1) {
try {
Expression expression = Expression.compile(argument);
expression.optimize();
return expression;
} catch (EvaluationException e) {
throw new InputParseException(String.format(
"Expected '%s' to be a valid number (or a valid mathematical expression)", argument));
} catch (ExpressionException e) {
throw new InputParseException(String.format(
"Expected '%s' to be a number or valid math expression (error: %s)", argument, e.getMessage()));
}
Expression expression = Expression.compile(argument);
expression.optimize();
return expression;
} catch (EvaluationException e) {
throw new InputParseException(String.format(
"Expected '%s' to be a valid number (or a valid mathematical expression)", argument));
} 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.google.common.collect.ImmutableSet;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.NamedTag;
import com.sk89q.jnbt.Tag;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@ -38,7 +35,6 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@ -95,7 +91,7 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
}
BufferedInputStream buffered = new BufferedInputStream(inputStream);
NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered)));
return new SpongeSchematicReader(nbtStream);
return new FastSchematicReader(nbtStream);
}
@Override
@ -108,7 +104,7 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
gzip = new PGZIPOutputStream(outputStream);
}
NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip));
return new SpongeSchematicWriter(nbtStream);
return new FastSchematicWriter(nbtStream);
}
@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 java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

View File

@ -19,88 +19,63 @@
package com.sk89q.worldedit.extent.clipboard.io;
import com.boydti.fawe.Fawe;
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.google.common.collect.Maps;
import com.sk89q.jnbt.ByteArrayTag;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntArrayTag;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NamedTag;
import com.sk89q.jnbt.ShortTag;
import com.sk89q.jnbt.StringTag;
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.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.Clipboard;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
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.BlockTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.entity.EntityTypes;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extension.platform.Capability;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import com.sk89q.worldedit.world.storage.NBTConversions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.function.Function;
import java.util.OptionalInt;
import java.util.stream.Collectors;
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.
*/
@Deprecated // High mem usage + slow
public class SpongeSchematicReader extends NBTSchematicReader {
private static final Logger log = LoggerFactory.getLogger(SpongeSchematicReader.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;
private int schematicVersion = -1;
private int dataVersion = -1;
/**
* Create a new instance.
@ -112,107 +87,6 @@ public class SpongeSchematicReader extends NBTSchematicReader {
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
public Clipboard read() throws IOException {
CompoundTag schematicTag = getBaseTag();
@ -264,141 +138,156 @@ public class SpongeSchematicReader extends NBTSchematicReader {
}
}
@Override
public Clipboard getBaseTag(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);
private CompoundTag getBaseTag() throws IOException {
NamedTag rootTag = inputStream.readNamedTag();
if (!rootTag.getName().equals("Schematic")) {
throw new IOException("Tag 'Schematic' does not exist or is not first");
}
CompoundTag schematicTag = (CompoundTag) rootTag.getTag();
Clipboard clipboard = createOutput.apply(dimensions);
// Check
Map<String, Tag> schematic = schematicTag.getValue();
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()));
}
}
}
}
}
schematicVersion = requireTag(schematic, "Version", IntTag.class).getValue();
return schematicTag;
}
private BlockArrayClipboard readVersion1(CompoundTag schematicTag) throws IOException {
BlockVector3 origin;
Region region;
Map<String, Tag> schematic = schematicTag.getValue();
int width = requireTag(schematic, "Width", ShortTag.class).getValue();
int height = requireTag(schematic, "Height", ShortTag.class).getValue();
int length = requireTag(schematic, "Length", ShortTag.class).getValue();
IntArrayTag offsetTag = getTag(schematic, "Offset", IntArrayTag.class);
int[] offsetParts;
if (offsetTag != null) {
offsetParts = offsetTag.getValue();
if (offsetParts.length != 3) {
throw new IOException("Invalid offset specified in schematic.");
}
} 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");
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);
}
BlockVector3 min = BlockVector3.at(offsetParts[0], offsetParts[1], offsetParts[2]);
CompoundTag metadataTag = getTag(schematic, "Metadata", CompoundTag.class);
if (metadataTag != null && metadataTag.containsKey("WEOffsetX")) {
// We appear to have WorldEdit Metadata
Map<String, Tag> metadata = metadataTag.getValue();
int offsetX = requireTag(metadata, "WEOffsetX", IntTag.class).getValue();
int offsetY = requireTag(metadata, "WEOffsetY", IntTag.class).getValue();
int offsetZ = requireTag(metadata, "WEOffsetZ", IntTag.class).getValue();
BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ);
origin = min.subtract(offset);
region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE));
} else {
origin = min;
region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE));
}
IntTag paletteMaxTag = getTag(schematic, "PaletteMax", IntTag.class);
Map<String, Tag> paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue();
if (paletteMaxTag != null && paletteObject.size() != paletteMaxTag.getValue()) {
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("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);
if (fixer != null) {
tileEntity = fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, new CompoundTag(values), dataVersion).getValue();
} else {
log.debug("Invalid entity: " + id);
tileEntity = values;
}
tileEntitiesMap.put(pt, tileEntity);
}
}
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
clipboard.setOrigin(origin);
if (!min.equals(BlockVector3.ZERO)) {
new BlockArrayClipboard(clipboard, min);
int index = 0;
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;
@ -508,4 +397,4 @@ public class SpongeSchematicReader extends NBTSchematicReader {
public void close() throws IOException {
inputStream.close();
}
}
}

View File

@ -19,61 +19,45 @@
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.boydti.fawe.object.FaweOutputStream;
import com.boydti.fawe.object.clipboard.LinearClipboard;
import com.boydti.fawe.util.IOUtil;
import com.sk89q.jnbt.ByteArrayTag;
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.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.ShortTag;
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.math.Vector3;
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.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 com.sk89q.worldedit.math.Vector3;
import java.util.Objects;
import com.sk89q.worldedit.util.Location;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Writes schematic files using the Sponge schematic format.
*/
@Deprecated // High mem usage + slow
public class SpongeSchematicWriter implements ClipboardWriter {
private static final int CURRENT_VERSION = 2;
@ -94,15 +78,16 @@ public class SpongeSchematicWriter implements ClipboardWriter {
@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);
outputStream.writeNamedTag("Schematic", new CompoundTag(write2(clipboard)));
}
/**
* Writes a version 2 schematic file.
*
* @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();
BlockVector3 origin = clipboard.getOrigin();
BlockVector3 min = region.getMinimumPoint();
@ -121,222 +106,102 @@ public class SpongeSchematicWriter implements ClipboardWriter {
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);
Map<String, Tag> schematic = new HashMap<>();
schematic.put("Version", new IntTag(CURRENT_VERSION));
schematic.put("DataVersion", new IntTag(
WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion()));
// 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(),
});
Map<String, Tag> metadata = new HashMap<>();
metadata.put("WEOffsetX", new IntTag(offset.getBlockX()));
metadata.put("WEOffsetY", new IntTag(offset.getBlockY()));
metadata.put("WEOffsetZ", new IntTag(offset.getBlockZ()));
out.writeLazyCompoundTag("Metadata", out1 -> {
out1.writeNamedTag("WEOffsetX", offset.getBlockX());
out1.writeNamedTag("WEOffsetY", offset.getBlockY());
out1.writeNamedTag("WEOffsetZ", offset.getBlockZ());
});
schematic.put("Metadata", new CompoundTag(metadata));
ByteArrayOutputStream blocksCompressed = new ByteArrayOutputStream();
FaweOutputStream blocksOut = new FaweOutputStream(new DataOutputStream(new LZ4BlockOutputStream(blocksCompressed)));
schematic.put("Width", new ShortTag((short) width));
schematic.put("Height", new ShortTag((short) height));
schematic.put("Length", new ShortTag((short) length));
ByteArrayOutputStream tilesCompressed = new ByteArrayOutputStream();
NBTOutputStream tilesOut = new NBTOutputStream(new LZ4BlockOutputStream(tilesCompressed));
// The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin'
schematic.put("Offset", new IntArrayTag(new int[]{
min.getBlockX(),
min.getBlockY(),
min.getBlockZ(),
}));
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();
int paletteMax = 0;
Map<String, Integer> palette = new HashMap<>();
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("Pos", new IntArrayTag(new int[]{
pos.getX(),
pos.getY(),
pos.getZ()
}));
numTiles++;
tilesOut.writeTagPayload(block.getNbtData());
}
values.put("Pos", new IntArrayTag(new int[]{
x,
y,
z
}));
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());
tileEntities.add(new CompoundTag(values));
}
// 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);
String blockKey = block.toImmutableState().getAsString();
int blockId;
if (palette.containsKey(blockKey)) {
blockId = palette.get(blockKey);
} else {
blockId = paletteMax;
palette.put(blockKey, blockId);
paletteMax++;
}
IOUtil.writeVarInt(biomesOut, value);
} catch (IOException e) {
e.printStackTrace();
while ((blockId & -128) != 0) {
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 -> {
for (int i = 0; i < paletteList.size(); i++) {
int ordinal = paletteList.get(i);
BiomeType state = BiomeTypes.get(ordinal);
out12.writeNamedTag(state.getId(), i);
}
});
Map<String, Tag> paletteTag = new HashMap<>();
palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value)));
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);
schematic.put("Palette", new CompoundTag(paletteTag));
schematic.put("BlockData", new ByteArrayTag(buffer.toByteArray()));
schematic.put("BlockEntities", new ListTag(CompoundTag.class, tileEntities));
// version 2 stuff
if (clipboard.hasBiomes()) {
writeBiomes(clipboard, schematic);
}
}
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;
if (!clipboard.getEntities().isEmpty()) {
writeEntities(clipboard, schematic);
}
schematic.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities));
return 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));
}
private Tag writeVector(Vector3 vector) {
public Tag writeVector(Vector3 vector) {
List<DoubleTag> list = new ArrayList<>();
list.add(new DoubleTag(vector.getX()));
list.add(new DoubleTag(vector.getY()));
@ -416,7 +281,7 @@ public class SpongeSchematicWriter implements ClipboardWriter {
return new ListTag(DoubleTag.class, list);
}
private Tag writeRotation(Location location) {
public Tag writeRotation(Location location) {
List<FloatTag> list = new ArrayList<>();
list.add(new FloatTag(location.getYaw()));
list.add(new FloatTag(location.getPitch()));
@ -427,4 +292,4 @@ public class SpongeSchematicWriter implements ClipboardWriter {
public void close() throws IOException {
outputStream.close();
}
}
}

View File

@ -22,8 +22,8 @@ package com.sk89q.worldedit.function.mask;
import static com.google.common.base.Preconditions.checkNotNull;
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.EvaluationException;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment;
@ -75,7 +75,8 @@ public class ExpressionMask extends AbstractMask {
if (timeout == null) {
return expression.evaluate(vector.getX(), vector.getY(), vector.getZ()) > 0;
} 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) {
return false;
@ -88,4 +89,4 @@ public class ExpressionMask extends AbstractMask {
return new ExpressionMask2D(expression, timeout);
}
}
}

View File

@ -411,6 +411,7 @@ public class ForwardExtentCopy implements Operation {
}
}
int affected;
affected = region.getArea();
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.FilenameResolutionException;
import com.sk89q.worldedit.util.io.file.InvalidFilenameException;
import com.sk89q.worldedit.world.storage.MissingWorldException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.collect.ImmutableList;
import com.google.common.collect.SetMultimap;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.antlr.ExpressionLexer;
import com.sk89q.worldedit.antlr.ExpressionParser;
import com.sk89q.worldedit.session.request.Request;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.misc.ParseCancellationException;
import com.sk89q.worldedit.session.request.Request;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import java.util.ArrayDeque;
import java.lang.invoke.MethodHandle;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.Stack;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@ -75,17 +73,16 @@ import java.util.concurrent.TimeoutException;
*/
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(
Runtime.getRuntime().availableProcessors(),
new ThreadFactoryBuilder()
.setDaemon(true)
.setNameFormat("worldedit-expression-eval-%d")
.build());
Runtime.getRuntime().availableProcessors(),
new ThreadFactoryBuilder()
.setDaemon(true)
.setNameFormat("worldedit-expression-eval-%d")
.build());
private final SlotTable slots = new SlotTable();
private final List<String> providedSlots;
private Variable[] variableArray;
private ExpressionParser.AllStatementsContext root;
private final SetMultimap<String, MethodHandle> functions = Functions.getFunctionMap();
private ExpressionEnvironment environment;
@ -102,8 +99,8 @@ public class Expression {
for (String variableName : variableNames) {
slots.initVariable(variableName)
.orElseThrow(() -> new ExpressionException(-1,
"Tried to overwrite identifier '" + variableName + "'"));
.orElseThrow(() -> new ExpressionException(-1,
"Tried to overwrite identifier '" + variableName + "'"));
}
this.providedSlots = ImmutableList.copyOf(variableNames);
@ -124,48 +121,16 @@ public class Expression {
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 {
return evaluateTimeout(WorldEdit.getInstance().getConfiguration().calculationTimeout, values);
}
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);
return evaluate(values, WorldEdit.getInstance().getConfiguration().calculationTimeout);
}
public double evaluate(double[] values, int timeout) throws EvaluationException {
if (root instanceof Constant) {
return root.getValue();
}
for (int i = 0; i < values.length; ++i) {
String slotName = providedSlots.get(i);
LocalSlot.Variable slot = slots.getVariable(slotName)
.orElseThrow(() -> new EvaluationException(-1,
"Tried to assign to non-variable " + slotName + "."));
.orElseThrow(() -> new EvaluationException(-1,
"Tried to assign to non-variable " + slotName + "."));
slot.setValue(values[i]);
}
@ -177,17 +142,6 @@ public class Expression {
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 {
CountDownLatch startLatch = new CountDownLatch(1);
Request request = Request.request();
@ -233,32 +187,36 @@ public class Expression {
// TODO optimizing
}
public SlotTable getSlots() {
return slots;
}
public RValue getRoot() {
return root;
}
@Override
public String toString() {
return root.toString();
}
public SlotTable getSlots() {
return slots;
}
public static Expression getInstance() {
return instance.get().peek();
}
private void pushInstance() {
ArrayDeque<Expression> foo = instance.get();
foo.push(this);
Stack<Expression> threadLocalExprStack = instance.get();
if (threadLocalExprStack == null) {
instance.set(threadLocalExprStack = new Stack<>());
}
threadLocalExprStack.push(this);
}
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() {
@ -269,4 +227,4 @@ public class Expression {
this.environment = environment;
}
}
}

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() {
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) {

View File

@ -54,7 +54,15 @@ public interface Subject {
* @param permission the 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);
}

View File

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

View File

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