mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-23 01:37:37 +00:00
Fix some merge issues
This commit is contained in:
parent
0e22d4718a
commit
60759934a3
@ -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")
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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))) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
@ -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());
|
||||
|
@ -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"));
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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")
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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,7 +214,7 @@ 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);
|
||||
}
|
||||
|
||||
@ -223,19 +223,9 @@ public class HistoryCommands {
|
||||
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")
|
||||
@Arg(desc = "Number of undoes to perform", def = "1")
|
||||
int times,
|
||||
@Arg(name = "player", desc = "Undo this player's operations", def = "")
|
||||
String playerName,
|
||||
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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");
|
||||
|
||||
@ -535,10 +535,12 @@ public class RegionCommands {
|
||||
boolean moveSelection,
|
||||
@Switch(name = 'a', desc = "Ignore air blocks")
|
||||
boolean ignoreAirBlocks,
|
||||
@Switch(name = 'e', desc = "Ignore entities")
|
||||
@Switch(name = 'e', desc = "Skip copy entities")
|
||||
boolean skipEntities,
|
||||
@Switch(name = 'b', desc = "Also copy biomes")
|
||||
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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
@ -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.");
|
||||
@ -147,8 +148,11 @@ public class SnapshotUtilCommands {
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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) {
|
||||
}
|
||||
|
@ -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;
|
||||
@ -31,9 +25,6 @@ public class ExpressionConverter implements ArgumentConverter<Expression> {
|
||||
@Override
|
||||
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();
|
||||
@ -42,6 +33,4 @@ public class ExpressionConverter implements ArgumentConverter<Expression> {
|
||||
return FailedConversion.from(e);
|
||||
}
|
||||
}
|
||||
return SuccessfulConversion.fromSingle(expression);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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.
|
||||
|
@ -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 {
|
||||
@ -58,10 +59,6 @@ public class GravityBrush implements Brush {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
column.clear();
|
||||
removedBlocks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
@ -37,9 +36,6 @@ 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();
|
||||
@ -52,7 +48,6 @@ public class PrimitiveBindings extends Bindings {
|
||||
"Expected '%s' to be a number or valid math expression (error: %s)", argument, e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link com.sk89q.worldedit.extent.Extent} from a {@link ArgumentStack}.
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
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();
|
||||
|
||||
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);
|
||||
// Check
|
||||
Map<String, Tag> schematic = schematicTag.getValue();
|
||||
|
||||
schematicVersion = requireTag(schematic, "Version", IntTag.class).getValue();
|
||||
return schematicTag;
|
||||
}
|
||||
|
||||
Clipboard clipboard = createOutput.apply(dimensions);
|
||||
private BlockArrayClipboard readVersion1(CompoundTag schematicTag) throws IOException {
|
||||
BlockVector3 origin;
|
||||
Region region;
|
||||
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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 width = requireTag(schematic, "Width", ShortTag.class).getValue();
|
||||
int height = requireTag(schematic, "Height", ShortTag.class).getValue();
|
||||
int length = requireTag(schematic, "Length", ShortTag.class).getValue();
|
||||
|
||||
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;
|
||||
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.");
|
||||
}
|
||||
x = tile.getInt("x");
|
||||
y = tile.getInt("y");
|
||||
z = tile.getInt("z");
|
||||
} else {
|
||||
x = pos[0];
|
||||
y = pos[1];
|
||||
z = pos[2];
|
||||
offsetParts = new int[] {0, 0, 0};
|
||||
}
|
||||
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;
|
||||
|
@ -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,51 +106,46 @@ 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()));
|
||||
|
||||
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()));
|
||||
|
||||
schematic.put("Metadata", new CompoundTag(metadata));
|
||||
|
||||
schematic.put("Width", new ShortTag((short) width));
|
||||
schematic.put("Height", new ShortTag((short) height));
|
||||
schematic.put("Length", new ShortTag((short) length));
|
||||
|
||||
// The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin'
|
||||
out.writeNamedTag("Offset", new int[]{
|
||||
schematic.put("Offset", new IntArrayTag(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();
|
||||
Map<String, Integer> palette = new HashMap<>();
|
||||
|
||||
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'
|
||||
|
||||
@ -173,170 +153,55 @@ public class SpongeSchematicWriter implements ClipboardWriter {
|
||||
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()
|
||||
x,
|
||||
y,
|
||||
z
|
||||
}));
|
||||
numTiles++;
|
||||
tilesOut.writeTagPayload(block.getNbtData());
|
||||
|
||||
tileEntities.add(new CompoundTag(values));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
String blockKey = block.toImmutableState().getAsString();
|
||||
int blockId;
|
||||
if (palette.containsKey(blockKey)) {
|
||||
blockId = palette.get(blockKey);
|
||||
} else {
|
||||
out.writeNamedEmptyList("TileEntities");
|
||||
blockId = paletteMax;
|
||||
palette.put(blockKey, blockId);
|
||||
paletteMax++;
|
||||
}
|
||||
|
||||
if (finalClipboard.hasBiomes()) {
|
||||
writeBiomes(finalClipboard, out);
|
||||
while ((blockId & -128) != 0) {
|
||||
buffer.write(blockId & 127 | 128);
|
||||
blockId >>>= 7;
|
||||
}
|
||||
|
||||
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());
|
||||
buffer.write(blockId);
|
||||
}
|
||||
|
||||
// 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()));
|
||||
schematic.put("PaletteMax", new IntTag(paletteMax));
|
||||
|
||||
return new CompoundTag(values);
|
||||
}).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
if (entities.isEmpty()) {
|
||||
return;
|
||||
Map<String, Tag> paletteTag = new HashMap<>();
|
||||
palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value)));
|
||||
|
||||
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);
|
||||
}
|
||||
schematic.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities));
|
||||
|
||||
if (!clipboard.getEntities().isEmpty()) {
|
||||
writeEntities(clipboard, schematic);
|
||||
}
|
||||
|
||||
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()));
|
||||
|
@ -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;
|
||||
|
@ -411,6 +411,7 @@ public class ForwardExtentCopy implements Operation {
|
||||
}
|
||||
|
||||
}
|
||||
int affected;
|
||||
affected = region.getArea();
|
||||
return null;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,7 +73,7 @@ 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()
|
||||
@ -85,7 +83,6 @@ public class Expression {
|
||||
|
||||
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;
|
||||
@ -124,43 +121,11 @@ 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)
|
||||
@ -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() {
|
||||
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user