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: notifications:
email: false email: false
before_install: chmod +x gradlew before_install: chmod +x gradlew
install: ./gradlew setupCIWorkspace -S install: ./gradlew setupCIWorkspace -s
matrix: script: ./gradlew build -s
include: jdk:
- jdk: oraclejdk7 - oraclejdk8
script: ./gradlew build -S - 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.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.EditSession; 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.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; 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.function.operation.Operations;
import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.session.ClipboardHolder; 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.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 com.sk89q.worldedit.world.registry.WorldData;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
@ -63,6 +65,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/ */
public class SchematicCommands { 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 static final Logger log = Logger.getLogger(SchematicCommands.class.getCanonicalName());
private final WorldEdit worldEdit; private final WorldEdit worldEdit;
@ -244,26 +250,34 @@ public class SchematicCommands {
@Command( @Command(
aliases = {"list", "all", "ls"}, aliases = {"list", "all", "ls"},
desc = "List saved schematics", desc = "List saved schematics",
max = 0, min = 0,
flags = "dn", max = 1,
flags = "dnp",
help = "List all schematics in the schematics directory\n" + help = "List all schematics in the schematics directory\n" +
" -d sorts by date, oldest first\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") @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 dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().saveDir);
File[] files = dir.listFiles(new FileFilter(){ List<File> fileList = allFiles(dir);
@Override File[] files = new File[fileList.size()];
public boolean accept(File file) { fileList.toArray(files);
// sort out directories from the schematic list
// if WE supports sub-directories in the future, if (files.length == 0) {
// this will have to be changed actor.printError("No schematics found.");
return file.isFile(); return;
} }
});
if (files == null) { int pageCount = files.length / SCHEMATICS_PER_PAGE + 1;
throw new FilenameResolutionException(dir.getPath(), "Schematics directory invalid or not found."); 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; 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>(){ Arrays.sort(files, new Comparator<File>(){
@Override @Override
public int compare(File f1, File f2) { 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 // 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 int res;
Long.valueOf(f1.lastModified()).compareTo(f2.lastModified()); // use date if there is a flag if (sortType == 0) { // use name by default
if (sortType == 1) result = -result; // flip date for newest first instead of oldest first int p = f1.getParent().compareTo(f2.getParent());
return result; 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)):"); List<String> schematics = listFiles(worldEdit.getConfiguration().saveDir, files);
actor.print(listFiles("", 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) { private List<File> allFiles(File root) {
StringBuilder build = new StringBuilder(); File[] files = root.listFiles();
for (File file : files) { if (files == null) return null;
if (file.isDirectory()) { List<File> fileList = new ArrayList<File>();
build.append(listFiles(prefix + file.getName() + "/", file.listFiles())); for (File f : files) {
continue; 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.OffsetMask;
import com.sk89q.worldedit.function.mask.RegionMask; import com.sk89q.worldedit.function.mask.RegionMask;
import com.sk89q.worldedit.function.mask.SolidBlockMask; import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.internal.registry.InputParser;
import com.sk89q.worldedit.math.noise.RandomNoise; 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.Request;
import com.sk89q.worldedit.session.request.RequestSelection; import com.sk89q.worldedit.session.request.RequestSelection;
import com.sk89q.worldedit.world.biome.BaseBiome; import com.sk89q.worldedit.world.biome.BaseBiome;
@ -144,7 +146,11 @@ class DefaultMaskParser extends InputParser<Mask> {
case '=': case '=':
try { 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) { } catch (ExpressionException e) {
throw new InputParseException("Invalid expression: " + e.getMessage()); 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 { private static double queryInternal(RValue type, RValue data, double typeId, double dataValue) throws EvaluationException {
// Compare to input values and determine return value // 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) { if (type instanceof LValue) {
((LValue) type).assign(typeId); ((LValue) type).assign(typeId);

View File

@ -300,10 +300,9 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
Vector min = getMinimumPoint(); Vector min = getMinimumPoint();
Vector max = getMaximumPoint(); Vector max = getMaximumPoint();
for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) { for (int x = min.getBlockX() >> ChunkStore.CHUNK_SHIFTS; x <= max.getBlockX() >> ChunkStore.CHUNK_SHIFTS; ++x) {
for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) { for (int z = min.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; z <= max.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; ++z) {
chunks.add(new BlockVector2D(x >> ChunkStore.CHUNK_SHIFTS, chunks.add(new BlockVector2D(x, z));
z >> ChunkStore.CHUNK_SHIFTS));
} }
} }
@ -317,11 +316,10 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
Vector min = getMinimumPoint(); Vector min = getMinimumPoint();
Vector max = getMaximumPoint(); Vector max = getMaximumPoint();
for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) { for (int x = min.getBlockX() >> ChunkStore.CHUNK_SHIFTS; x <= max.getBlockX() >> ChunkStore.CHUNK_SHIFTS; ++x) {
for (int y = min.getBlockY(); y <= max.getBlockY(); ++y) { for (int z = min.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; z <= max.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; ++z) {
for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) { for (int y = min.getBlockY() >> ChunkStore.CHUNK_SHIFTS; y <= max.getBlockY() >> ChunkStore.CHUNK_SHIFTS; ++y) {
chunks.add(new BlockVector(x >> ChunkStore.CHUNK_SHIFTS, chunks.add(new BlockVector(x, y, z));
y >> ChunkStore.CHUNK_SHIFTS, z >> ChunkStore.CHUNK_SHIFTS));
} }
} }
} }

View File

@ -29,6 +29,7 @@ import java.util.ArrayDeque;
import java.util.Deque; import java.util.Deque;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.zip.ZipFile;
import static com.google.common.base.Preconditions.checkNotNull; 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 // 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<Closeable> stack = new ArrayDeque<Closeable>(4);
private final Deque<ZipFile> zipStack = new ArrayDeque<ZipFile>(4);
private Throwable thrown; private Throwable thrown;
@VisibleForTesting Closer(Suppressor suppressor) { @VisibleForTesting Closer(Suppressor suppressor) {
@ -73,6 +75,17 @@ public final class Closer implements Closeable {
return 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 * 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 * {@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) { if (thrown == null && throwable != null) {
Throwables.propagateIfPossible(throwable, IOException.class); 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 * 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. * 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(); static final LoggingSuppressor INSTANCE = new LoggingSuppressor();
@Override @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 // log to the same place as Closeables
logger.log(Level.WARNING, "Suppressing exception thrown when closing " + closeable, suppressed); logger.log(Level.WARNING, "Suppressing exception thrown when closing " + closeable, suppressed);
} }
@ -217,7 +242,7 @@ public final class Closer implements Closeable {
} }
@Override @Override
public void suppress(Closeable closeable, Throwable thrown, Throwable suppressed) { public void suppress(Object closeable, Throwable thrown, Throwable suppressed) {
// ensure no exceptions from addSuppressed // ensure no exceptions from addSuppressed
if (thrown == suppressed) { if (thrown == suppressed) {
return; return;

View File

@ -16,7 +16,7 @@ apply plugin: 'net.minecraftforge.gradle.forge'
dependencies { dependencies {
compile project(':worldedit-core') compile project(':worldedit-core')
compile 'org.spongepowered:spongeapi:3.1.0-SNAPSHOT' 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 { repositories {

View File

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