Upstream Merge

This commit is contained in:
MattBDev
2020-01-10 22:32:12 -05:00
parent b2be1ea9fb
commit 0d2fff2cd2
81 changed files with 2528 additions and 23695 deletions

View File

@ -127,9 +127,8 @@ public class PropertiesConfiguration extends LocalConfiguration {
LocalSession.MAX_HISTORY_SIZE = Math.max(15, getInt("history-size", 15));
String snapshotsDir = getString("snapshots-dir", "");
if (!snapshotsDir.isEmpty()) {
snapshotRepo = new SnapshotRepository(snapshotsDir);
}
boolean experimentalSnapshots = getBool("snapshots-experimental", false);
initializeSnapshotConfiguration(snapshotsDir, experimentalSnapshots);
path.getParentFile().mkdirs();
try (OutputStream output = new FileOutputStream(path)) {

View File

@ -19,8 +19,6 @@
package com.sk89q.worldedit.util.collection;
import com.google.common.collect.Iterators;
import com.sk89q.worldedit.WorldEdit;
import com.google.common.collect.Iterators;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.math.BlockVector3;

View File

@ -0,0 +1,83 @@
/*
* 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.util.collection;
import com.google.common.collect.AbstractIterator;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static java.util.Objects.requireNonNull;
/**
* Additionally stream facilities.
*/
public class MoreStreams {
/**
* Emit elements from {@code stream} until {@code predicate} returns {@code false}.
*/
public static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<T> predicate) {
return takeUntil(stream, predicate.negate());
}
/**
* Emit elements from {@code stream} until {@code predicate} returns {@code true}.
*/
public static <T> Stream<T> takeUntil(Stream<T> stream, Predicate<T> predicate) {
Spliterator<T> spliterator = stream.spliterator();
Iterator<T> iter = new AbstractIterator<T>() {
private Iterator<T> source = Spliterators.iterator(spliterator);
@Override
protected T computeNext() {
Iterator<T> src = requireNonNull(source);
if (!src.hasNext()) {
return done();
}
T next = src.next();
if (predicate.test(next)) {
return done();
}
return next;
}
private T done() {
// allow GC of source
source = null;
return endOfData();
}
};
int chars = spliterator.characteristics();
// Not SIZED, Not SUBSIZED
chars &= ~(Spliterator.SIZED | Spliterator.SUBSIZED);
return StreamSupport.stream(Spliterators.spliterator(
iter, spliterator.estimateSize(), chars
), stream.isParallel()).onClose(stream::close);
}
private MoreStreams() {
}
}

View File

@ -71,4 +71,5 @@ public class LazyReference<T> {
refInfo.lock.unlock();
}
}
}

View File

@ -20,8 +20,6 @@
package com.sk89q.worldedit.util.eventbus;
import com.google.common.collect.HashMultimap;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap;
import org.slf4j.Logger;
@ -37,6 +35,8 @@ import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Dispatches events to listeners, and provides ways for listeners to register
* themselves.

View File

@ -47,6 +47,7 @@ public class TextUtils {
}
return builder.build();
}
/**
* Gets a Java Locale object by the Minecraft locale tag.
*

View File

@ -0,0 +1,32 @@
/*
* 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.util.function;
import java.io.IOException;
/**
* I/O runnable type.
*/
@FunctionalInterface
public interface IORunnable {
void run() throws IOException;
}

View File

@ -51,4 +51,4 @@ public class ResourceLoader {
}
return url;
}
}
}

View File

@ -0,0 +1,40 @@
/*
* 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.util.io.file;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.util.Optional;
/**
* Something that can provide access to an archive file as a file system.
*/
public interface ArchiveNioSupport {
/**
* Try to open the given archive as a file system.
*
* @param archive the archive to open
* @return the path for the root of the archive, if available
*/
Optional<Path> tryOpenAsDir(Path archive) throws IOException;
}

View File

@ -0,0 +1,99 @@
/*
* 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.util.io.file;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.stream.Stream;
public class ArchiveNioSupports {
private static final List<ArchiveNioSupport> SUPPORTS;
static {
ImmutableList.Builder<ArchiveNioSupport> builder = ImmutableList.builder();
try {
builder.add(TrueVfsArchiveNioSupport.getInstance());
} catch (NoClassDefFoundError ignore) {
// No TrueVFS available. That's OK.
}
SUPPORTS = builder.add(ZipArchiveNioSupport.getInstance())
.addAll(ServiceLoader.load(ArchiveNioSupport.class))
.build();
}
public static Optional<Path> tryOpenAsDir(Path archive) throws IOException {
for (ArchiveNioSupport support : SUPPORTS) {
Optional<Path> fs = support.tryOpenAsDir(archive);
if (fs.isPresent()) {
return fs;
}
}
return Optional.empty();
}
private static final ArchiveNioSupport COMBINED = ArchiveNioSupports::tryOpenAsDir;
/**
* Get an {@link ArchiveNioSupport} that combines all known instances.
* @return a combined {@link ArchiveNioSupport} instance
*/
public static ArchiveNioSupport combined() {
return COMBINED;
}
/**
* If root contains a folder with the same name as {@code name}, and no regular files,
* returns the path to that folder. Otherwise, return the root path.
*
* <p>
* This method is used to provide equal outputs for archives that do and do not contain
* their name as part of their root folder.
* </p>
*
* @param root the root path
* @param name the name that might exist inside root
* @return the corrected path
*/
public static Path skipRootSameName(Path root, String name) throws IOException {
Path innerDir = root.resolve(name);
if (Files.isDirectory(innerDir)) {
try (Stream<Path> files = Files.list(root)) {
// The reason we check this, is that macOS creates a __MACOSX directory inside
// its zip files. We want to allow this to pass if that exists, or a similar
// mechanism, but fail if there are regular files, since that indicates that
// it may not be the right thing to do.
if (files.allMatch(Files::isDirectory)) {
return innerDir;
}
}
}
return root;
}
private ArchiveNioSupports() {
}
}

View File

@ -0,0 +1,68 @@
/*
* 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.util.io.file;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Streams;
import java.nio.file.Path;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import java.util.Spliterator;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class MorePaths {
/**
* Starting with the first path element, add elements until reaching this path.
*/
public static Stream<Path> iterPaths(Path path) {
Deque<Path> parents = new ArrayDeque<>(path.getNameCount());
// Push parents to the front of the stack, so the "root" is at the front
Path next = path;
while (next != null) {
parents.addFirst(next);
next = next.getParent();
}
// now just iterate straight over them
return ImmutableList.copyOf(parents).stream();
}
/**
* Create an efficiently-splittable spliterator for the given path elements.
*
* <p>
* Since paths are so small, this is only useful for preventing heavy computations
* on later parts of the stream from occurring when using
* {@link Streams#findLast(IntStream)}, and not for parallelism.
* </p>
*
* @param path the path to create a spliterator for
* @return the spliterator
*/
public static Spliterator<Path> optimizedSpliterator(Path path) {
return Arrays.spliterator(Streams.stream(path).toArray(Path[]::new));
}
private MorePaths() {
}
}

View File

@ -0,0 +1,59 @@
/*
* 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.util.io.file;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import net.java.truevfs.access.TArchiveDetector;
import net.java.truevfs.access.TPath;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
import java.util.Set;
public final class TrueVfsArchiveNioSupport implements ArchiveNioSupport {
private static final TrueVfsArchiveNioSupport INSTANCE = new TrueVfsArchiveNioSupport();
public static TrueVfsArchiveNioSupport getInstance() {
return INSTANCE;
}
private static final Set<String> ALLOWED_EXTENSIONS = ImmutableSet.copyOf(
Splitter.on('|').split(TArchiveDetector.ALL.getExtensions())
);
private TrueVfsArchiveNioSupport() {
}
@Override
public Optional<Path> tryOpenAsDir(Path archive) throws IOException {
String fileName = archive.getFileName().toString();
int dot = fileName.indexOf('.');
if (dot < 0 || dot >= fileName.length() || !ALLOWED_EXTENSIONS.contains(fileName.substring(dot + 1))) {
return Optional.empty();
}
TPath root = new TPath(archive).getFileSystem().getPath("/");
return Optional.of(ArchiveNioSupports.skipRootSameName(
root, fileName.substring(0, dot)
));
}
}

View File

@ -0,0 +1,53 @@
/*
* 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.util.io.file;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.Optional;
public final class ZipArchiveNioSupport implements ArchiveNioSupport {
private static final ZipArchiveNioSupport INSTANCE = new ZipArchiveNioSupport();
public static ZipArchiveNioSupport getInstance() {
return INSTANCE;
}
private ZipArchiveNioSupport() {
}
@Override
public Optional<Path> tryOpenAsDir(Path archive) throws IOException {
if (!archive.getFileName().toString().endsWith(".zip")) {
return Optional.empty();
}
FileSystem zipFs = FileSystems.newFileSystem(
archive, getClass().getClassLoader()
);
return Optional.of(ArchiveNioSupports.skipRootSameName(
zipFs.getPath("/"), archive.getFileName().toString()
.replaceFirst("\\.zip$", "")
));
}
}

View File

@ -0,0 +1,110 @@
/*
* 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.util.time;
import com.google.common.collect.Streams;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.util.io.file.MorePaths;
import javax.annotation.Nullable;
import java.nio.file.Path;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
/**
* Parses date-times by looking at the file name. File names without a time
* will use 00:00:00.
*
* <p>
* Elements may be separated by a space, dash, or colon.
* The date and time may additionally be separated by a 'T'.
* Only the year must have all digits, others may omit padding
* zeroes.
* </p>
*
* <p>
* Valid file name examples:
* <ul>
* <li>{@code 2019-06-15}</li>
* <li>{@code 2019-06-15 10:20:30}</li>
* <li>{@code 2019-06-15 10:20:30}</li>
* <li>{@code 2019-06-15T10:20:30}</li>
* <li>{@code 2019 06 15 10 20 30}</li>
* <li>{@code 2019-06-15-10-20-30}</li>
* <li>{@code 2019-6-1-1-2-3}</li>
* </ul>
* </p>
*/
public class FileNameDateTimeParser implements SnapshotDateTimeParser {
private static final FileNameDateTimeParser INSTANCE = new FileNameDateTimeParser();
public static FileNameDateTimeParser getInstance() {
return INSTANCE;
}
private static final String SEP = "[ \\-_:]";
private static final Pattern BASIC_FILTER = Pattern.compile(
"^(?<year>\\d{4})" + SEP + "(?<month>\\d{1,2})" + SEP + "(?<day>\\d{1,2})" +
// Optionally:
"(?:" + "[ \\-_:T]" +
"(?<hour>\\d{1,2})" + SEP + "(?<minute>\\d{1,2})" + SEP + "(?<second>\\d{1,2})" +
")?"
);
private FileNameDateTimeParser() {
}
@Nullable
@Override
public ZonedDateTime detectDateTime(Path path) {
// Make this perform a little better:
Matcher matcher = Streams.findLast(
StreamSupport.stream(MorePaths.optimizedSpliterator(path), false)
.map(p -> BASIC_FILTER.matcher(p.toString()))
.filter(Matcher::find)
).orElse(null);
if (matcher != null) {
int year = matchAndParseOrZero(matcher, "year");
int month = matchAndParseOrZero(matcher, "month");
int day = matchAndParseOrZero(matcher, "day");
int hour = matchAndParseOrZero(matcher, "hour");
int minute = matchAndParseOrZero(matcher, "minute");
int second = matchAndParseOrZero(matcher, "second");
return ZonedDateTime.of(year, month, day, hour, minute, second,
0, ZoneId.systemDefault());
}
return null;
}
private static int matchAndParseOrZero(Matcher matcher, String group) {
String match = matcher.group(group);
if (match == null) {
return 0;
}
return Integer.parseInt(match);
}
}

View File

@ -0,0 +1,52 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.util.time;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class ModificationDateTimeParser implements SnapshotDateTimeParser {
private static final ModificationDateTimeParser INSTANCE = new ModificationDateTimeParser();
public static ModificationDateTimeParser getInstance() {
return INSTANCE;
}
private ModificationDateTimeParser() {
}
@Override
public ZonedDateTime detectDateTime(Path path) {
if (!Files.exists(path)) {
return null;
}
try {
return Files.getLastModifiedTime(path).toInstant().atZone(ZoneId.systemDefault());
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}

View File

@ -0,0 +1,45 @@
/*
* 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.util.time;
import javax.annotation.Nullable;
import java.nio.file.Path;
import java.time.ZonedDateTime;
/**
* Instances of this interface try to determine an {@link ZonedDateTime} from a given
* {@link Path}.
*/
public interface SnapshotDateTimeParser {
/**
* Attempt to detect an ZonedDateTime from a path.
*
* <p>
* The path is not guaranteed to exist.
* </p>
*
* @param path the path
* @return date-time, if it can be parsed
*/
@Nullable
ZonedDateTime detectDateTime(Path path);
}

View File

@ -19,8 +19,6 @@
package com.sk89q.worldedit.util.translation;
import static java.util.stream.Collectors.toMap;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@ -29,6 +27,7 @@ import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.renderer.FriendlyComponentRenderer;
import com.sk89q.worldedit.util.io.ResourceLoader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@ -43,6 +42,8 @@ import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import static java.util.stream.Collectors.toMap;
/**
* Handles translations for the plugin.
*