geforkt von Mirrors/FastAsyncWorldEdit
Merge in from master, mostly.
The most important part of this merge is that it REVERTS FMP compatibility, since no such thing needs to exist in 1.8. In fact, there isn't even an FMP in 1.8 yet. It will be added back if FMP ever ports to 1.8 and the problem still exists.
Dieser Commit ist enthalten in:
Commit
7f43bc4b47
21
.travis.yml
21
.travis.yml
@ -2,8 +2,19 @@ language: java
|
||||
notifications:
|
||||
email: false
|
||||
before_install: chmod +x gradlew
|
||||
install: ./gradlew setupCIWorkspace -S
|
||||
matrix:
|
||||
include:
|
||||
- jdk: oraclejdk7
|
||||
script: ./gradlew build -S
|
||||
install: ./gradlew setupCIWorkspace -s
|
||||
script: ./gradlew build -s
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
- oraclejdk7
|
||||
- openjdk6
|
||||
# Caching for Gradle files, prevents hitting Maven too much.
|
||||
before_cache:
|
||||
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.gradle/caches/
|
||||
- $HOME/.gradle/wrapper/
|
||||
|
||||
# Faster builds without sudo.
|
||||
sudo: false
|
||||
|
@ -24,8 +24,6 @@ import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.util.io.file.FilenameException;
|
||||
import com.sk89q.worldedit.util.io.file.FilenameResolutionException;
|
||||
import com.sk89q.worldedit.LocalConfiguration;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
@ -40,21 +38,25 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.util.io.Closer;
|
||||
import com.sk89q.worldedit.util.command.binding.Switch;
|
||||
import com.sk89q.worldedit.util.command.parametric.Optional;
|
||||
import com.sk89q.worldedit.util.io.Closer;
|
||||
import com.sk89q.worldedit.util.io.file.FilenameException;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -63,6 +65,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
*/
|
||||
public class SchematicCommands {
|
||||
|
||||
/**
|
||||
* 9 schematics per page fits in the MC chat window.
|
||||
*/
|
||||
private static final int SCHEMATICS_PER_PAGE = 9;
|
||||
private static final Logger log = Logger.getLogger(SchematicCommands.class.getCanonicalName());
|
||||
private final WorldEdit worldEdit;
|
||||
|
||||
@ -244,26 +250,34 @@ public class SchematicCommands {
|
||||
@Command(
|
||||
aliases = {"list", "all", "ls"},
|
||||
desc = "List saved schematics",
|
||||
max = 0,
|
||||
flags = "dn",
|
||||
min = 0,
|
||||
max = 1,
|
||||
flags = "dnp",
|
||||
help = "List all schematics in the schematics directory\n" +
|
||||
" -d sorts by date, oldest first\n" +
|
||||
" -n sorts by date, newest first\n"
|
||||
" -n sorts by date, newest first\n" +
|
||||
" -p <page> prints the requested page\n"
|
||||
)
|
||||
@CommandPermissions("worldedit.schematic.list")
|
||||
public void list(Actor actor, CommandContext args) throws WorldEditException {
|
||||
public void list(Actor actor, CommandContext args, @Switch('p') @Optional("1") int page) throws WorldEditException {
|
||||
File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().saveDir);
|
||||
File[] files = dir.listFiles(new FileFilter(){
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
// sort out directories from the schematic list
|
||||
// if WE supports sub-directories in the future,
|
||||
// this will have to be changed
|
||||
return file.isFile();
|
||||
}
|
||||
});
|
||||
if (files == null) {
|
||||
throw new FilenameResolutionException(dir.getPath(), "Schematics directory invalid or not found.");
|
||||
List<File> fileList = allFiles(dir);
|
||||
File[] files = new File[fileList.size()];
|
||||
fileList.toArray(files);
|
||||
|
||||
if (files.length == 0) {
|
||||
actor.printError("No schematics found.");
|
||||
return;
|
||||
}
|
||||
|
||||
int pageCount = files.length / SCHEMATICS_PER_PAGE + 1;
|
||||
if (page < 1) {
|
||||
actor.printError("Page must be at least 1");
|
||||
return;
|
||||
}
|
||||
if (page > pageCount) {
|
||||
actor.printError("Page must be less than " + (pageCount + 1));
|
||||
return;
|
||||
}
|
||||
|
||||
final int sortType = args.hasFlag('d') ? -1 : args.hasFlag('n') ? 1 : 0;
|
||||
@ -271,38 +285,68 @@ public class SchematicCommands {
|
||||
Arrays.sort(files, new Comparator<File>(){
|
||||
@Override
|
||||
public int compare(File f1, File f2) {
|
||||
// this should no longer happen, as directory-ness is checked before
|
||||
// however, if a directory slips through, this will break the contract
|
||||
// of comparator transitivity
|
||||
if (!f1.isFile() || !f2.isFile()) return -1;
|
||||
// http://stackoverflow.com/questions/203030/best-way-to-list-files-in-java-sorted-by-date-modified
|
||||
int result = sortType == 0 ? f1.getName().compareToIgnoreCase(f2.getName()) : // use name by default
|
||||
Long.valueOf(f1.lastModified()).compareTo(f2.lastModified()); // use date if there is a flag
|
||||
if (sortType == 1) result = -result; // flip date for newest first instead of oldest first
|
||||
return result;
|
||||
int res;
|
||||
if (sortType == 0) { // use name by default
|
||||
int p = f1.getParent().compareTo(f2.getParent());
|
||||
if (p == 0) { // same parent, compare names
|
||||
res = f1.getName().compareTo(f2.getName());
|
||||
} else { // different parent, sort by that
|
||||
res = p;
|
||||
}
|
||||
} else {
|
||||
res = Long.valueOf(f1.lastModified()).compareTo(f2.lastModified()); // use date if there is a flag
|
||||
if (sortType == 1) res = -res; // flip date for newest first instead of oldest first
|
||||
}
|
||||
return res;
|
||||
}
|
||||
});
|
||||
|
||||
actor.print("Available schematics (Filename (Format)):");
|
||||
actor.print(listFiles("", files));
|
||||
List<String> schematics = listFiles(worldEdit.getConfiguration().saveDir, files);
|
||||
int offset = (page - 1) * SCHEMATICS_PER_PAGE;
|
||||
|
||||
actor.print("Available schematics (Filename: Format) [" + page + "/" + pageCount + "]:");
|
||||
StringBuilder build = new StringBuilder();
|
||||
int limit = Math.min(offset + SCHEMATICS_PER_PAGE, schematics.size());
|
||||
for (int i = offset; i < limit;) {
|
||||
build.append(schematics.get(i));
|
||||
if (++i != limit) {
|
||||
build.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
actor.print(build.toString());
|
||||
}
|
||||
|
||||
private String listFiles(String prefix, File[] files) {
|
||||
StringBuilder build = new StringBuilder();
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
build.append(listFiles(prefix + file.getName() + "/", file.listFiles()));
|
||||
continue;
|
||||
private List<File> allFiles(File root) {
|
||||
File[] files = root.listFiles();
|
||||
if (files == null) return null;
|
||||
List<File> fileList = new ArrayList<File>();
|
||||
for (File f : files) {
|
||||
if (f.isDirectory()) {
|
||||
List<File> subFiles = allFiles(f);
|
||||
if (subFiles == null) continue; // empty subdir
|
||||
fileList.addAll(subFiles);
|
||||
} else {
|
||||
fileList.add(f);
|
||||
}
|
||||
|
||||
if (!file.isFile()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
build.append("\n\u00a79");
|
||||
ClipboardFormat format = ClipboardFormat.findByFile(file);
|
||||
build.append(prefix).append(file.getName()).append(": ").append(format == null ? "Unknown" : format.name());
|
||||
}
|
||||
return build.toString();
|
||||
return fileList;
|
||||
}
|
||||
|
||||
private List<String> listFiles(String prefix, File[] files) {
|
||||
if (prefix == null) prefix = "";
|
||||
List<String> result = new ArrayList<String>();
|
||||
for (File file : files) {
|
||||
StringBuilder build = new StringBuilder();
|
||||
|
||||
build.append("\u00a72");
|
||||
ClipboardFormat format = ClipboardFormat.findByFile(file);
|
||||
boolean inRoot = file.getParentFile().getName().equals(prefix);
|
||||
build.append(inRoot ? file.getName() : file.getPath().split(Pattern.quote(prefix + File.separator))[1])
|
||||
.append(": ").append(format == null ? "Unknown" : format.name());
|
||||
result.add(build.toString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -37,9 +37,11 @@ import com.sk89q.worldedit.function.mask.NoiseFilter;
|
||||
import com.sk89q.worldedit.function.mask.OffsetMask;
|
||||
import com.sk89q.worldedit.function.mask.RegionMask;
|
||||
import com.sk89q.worldedit.function.mask.SolidBlockMask;
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.ExpressionException;
|
||||
import com.sk89q.worldedit.internal.registry.InputParser;
|
||||
import com.sk89q.worldedit.math.noise.RandomNoise;
|
||||
import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment;
|
||||
import com.sk89q.worldedit.session.request.Request;
|
||||
import com.sk89q.worldedit.session.request.RequestSelection;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
@ -144,7 +146,11 @@ class DefaultMaskParser extends InputParser<Mask> {
|
||||
|
||||
case '=':
|
||||
try {
|
||||
return new ExpressionMask(component.substring(1));
|
||||
Expression exp = Expression.compile(component.substring(1), "x", "y", "z");
|
||||
WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment(
|
||||
Request.request().getEditSession(), Vector.ONE, Vector.ZERO);
|
||||
exp.setEnvironment(env);
|
||||
return new ExpressionMask(exp);
|
||||
} catch (ExpressionException e) {
|
||||
throw new InputParseException("Invalid expression: " + e.getMessage());
|
||||
}
|
||||
|
@ -442,7 +442,9 @@ public final class Functions {
|
||||
|
||||
private static double queryInternal(RValue type, RValue data, double typeId, double dataValue) throws EvaluationException {
|
||||
// Compare to input values and determine return value
|
||||
final double ret = (typeId == type.getValue() && dataValue == data.getValue()) ? 1.0 : 0.0;
|
||||
// -1 is a wildcard, always true
|
||||
final double ret = ((type.getValue() == -1 || typeId == type.getValue())
|
||||
&& (data.getValue() == -1 || dataValue == data.getValue())) ? 1.0 : 0.0;
|
||||
|
||||
if (type instanceof LValue) {
|
||||
((LValue) type).assign(typeId);
|
||||
|
@ -300,10 +300,9 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
|
||||
Vector min = getMinimumPoint();
|
||||
Vector max = getMaximumPoint();
|
||||
|
||||
for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) {
|
||||
for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) {
|
||||
chunks.add(new BlockVector2D(x >> ChunkStore.CHUNK_SHIFTS,
|
||||
z >> ChunkStore.CHUNK_SHIFTS));
|
||||
for (int x = min.getBlockX() >> ChunkStore.CHUNK_SHIFTS; x <= max.getBlockX() >> ChunkStore.CHUNK_SHIFTS; ++x) {
|
||||
for (int z = min.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; z <= max.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; ++z) {
|
||||
chunks.add(new BlockVector2D(x, z));
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,11 +316,10 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
|
||||
Vector min = getMinimumPoint();
|
||||
Vector max = getMaximumPoint();
|
||||
|
||||
for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) {
|
||||
for (int y = min.getBlockY(); y <= max.getBlockY(); ++y) {
|
||||
for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) {
|
||||
chunks.add(new BlockVector(x >> ChunkStore.CHUNK_SHIFTS,
|
||||
y >> ChunkStore.CHUNK_SHIFTS, z >> ChunkStore.CHUNK_SHIFTS));
|
||||
for (int x = min.getBlockX() >> ChunkStore.CHUNK_SHIFTS; x <= max.getBlockX() >> ChunkStore.CHUNK_SHIFTS; ++x) {
|
||||
for (int z = min.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; z <= max.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; ++z) {
|
||||
for (int y = min.getBlockY() >> ChunkStore.CHUNK_SHIFTS; y <= max.getBlockY() >> ChunkStore.CHUNK_SHIFTS; ++y) {
|
||||
chunks.add(new BlockVector(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -55,6 +56,7 @@ public final class Closer implements Closeable {
|
||||
|
||||
// only need space for 2 elements in most cases, so try to use the smallest array possible
|
||||
private final Deque<Closeable> stack = new ArrayDeque<Closeable>(4);
|
||||
private final Deque<ZipFile> zipStack = new ArrayDeque<ZipFile>(4);
|
||||
private Throwable thrown;
|
||||
|
||||
@VisibleForTesting Closer(Suppressor suppressor) {
|
||||
@ -73,6 +75,17 @@ public final class Closer implements Closeable {
|
||||
return closeable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the given {@code zipFile} to be closed when this {@code Closer} is
|
||||
* {@linkplain #close closed}.
|
||||
*
|
||||
* @return the given {@code closeable}
|
||||
*/
|
||||
public <Z extends ZipFile> Z register(Z zipFile) {
|
||||
zipStack.push(zipFile);
|
||||
return zipFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the given throwable and rethrows it. It will be rethrown as is if it is an
|
||||
* {@code IOException}, {@code RuntimeException} or {@code Error}. Otherwise, it will be rethrown
|
||||
@ -161,6 +174,18 @@ public final class Closer implements Closeable {
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!zipStack.isEmpty()) {
|
||||
ZipFile zipFile = zipStack.pop();
|
||||
try {
|
||||
zipFile.close();
|
||||
} catch (Throwable e) {
|
||||
if (throwable == null) {
|
||||
throwable = e;
|
||||
} else {
|
||||
suppressor.suppress(zipFile, throwable, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (thrown == null && throwable != null) {
|
||||
Throwables.propagateIfPossible(throwable, IOException.class);
|
||||
@ -177,7 +202,7 @@ public final class Closer implements Closeable {
|
||||
* the given closeable. {@code thrown} is the exception that is actually being thrown from the
|
||||
* method. Implementations of this method should not throw under any circumstances.
|
||||
*/
|
||||
void suppress(Closeable closeable, Throwable thrown, Throwable suppressed);
|
||||
void suppress(Object closeable, Throwable thrown, Throwable suppressed);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,7 +213,7 @@ public final class Closer implements Closeable {
|
||||
static final LoggingSuppressor INSTANCE = new LoggingSuppressor();
|
||||
|
||||
@Override
|
||||
public void suppress(Closeable closeable, Throwable thrown, Throwable suppressed) {
|
||||
public void suppress(Object closeable, Throwable thrown, Throwable suppressed) {
|
||||
// log to the same place as Closeables
|
||||
logger.log(Level.WARNING, "Suppressing exception thrown when closing " + closeable, suppressed);
|
||||
}
|
||||
@ -217,7 +242,7 @@ public final class Closer implements Closeable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suppress(Closeable closeable, Throwable thrown, Throwable suppressed) {
|
||||
public void suppress(Object closeable, Throwable thrown, Throwable suppressed) {
|
||||
// ensure no exceptions from addSuppressed
|
||||
if (thrown == suppressed) {
|
||||
return;
|
||||
|
@ -16,7 +16,7 @@ apply plugin: 'net.minecraftforge.gradle.forge'
|
||||
dependencies {
|
||||
compile project(':worldedit-core')
|
||||
compile 'org.spongepowered:spongeapi:3.1.0-SNAPSHOT'
|
||||
testCompile group: 'org.mockito', name: 'mockito-core', version:'1.9.0-rc1'
|
||||
testCompile group: 'org.mockito', name: 'mockito-core', version: '1.9.0-rc1'
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
@ -142,5 +142,4 @@ final class TileEntityUtils {
|
||||
return genericTE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren