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.
This commit is contained in:
Kenzie Togami 2016-02-22 17:54:50 -08:00
commit 7f43bc4b47
8 changed files with 150 additions and 65 deletions

View File

@ -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

View File

@ -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;
}
}

View File

@ -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());
}

View File

@ -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);

View File

@ -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));
}
}
}

View File

@ -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;

View File

@ -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 {

View File

@ -142,5 +142,4 @@ final class TileEntityUtils {
return genericTE;
}
}