Datapack resolving

This commit is contained in:
Yuhui Huang
2018-09-14 15:44:40 +08:00
parent 2bfc85b18f
commit 1753b4d27e
13 changed files with 434 additions and 7 deletions

View File

@@ -15,6 +15,7 @@ import org.tukaani.xz.XZInputStream;
import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.jar.JarEntry;
@@ -75,7 +76,7 @@ public class LibraryDownloadTask extends Task {
else
throw new LibraryDownloadException(library, t);
} else {
if (xz) unpackLibrary(jar, FileUtils.readBytes(xzFile));
if (xz) unpackLibrary(jar, Files.readAllBytes(xzFile.toPath()));
if (!checksumValid(jar, library.getChecksums())) {
jar.delete();
throw new IOException("Checksum failed for " + library);
@@ -125,7 +126,7 @@ public class LibraryDownloadTask extends Task {
if (checksums == null || checksums.isEmpty()) {
return true;
}
byte[] fileData = FileUtils.readBytes(libPath);
byte[] fileData = Files.readAllBytes(libPath.toPath());
boolean valid = checksums.contains(encodeHex(digest("SHA-1", fileData)));
if (!valid && libPath.getName().endsWith(".jar")) {
valid = validateJar(fileData, checksums);

View File

@@ -0,0 +1,4 @@
package org.jackhuang.hmcl.game;
public class World {
}

View File

@@ -0,0 +1,185 @@
package org.jackhuang.hmcl.mod;
import com.google.gson.JsonParseException;
import com.google.gson.annotations.SerializedName;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import org.jackhuang.hmcl.util.*;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
public class Datapack {
private final Path path;
private final List<Pack> info;
private Datapack(Path path, List<Pack> info) {
this.path = path;
this.info = Collections.unmodifiableList(info);
for (Pack pack : info) {
pack.datapack = this;
}
}
public Path getPath() {
return path;
}
public List<Pack> getInfo() {
return info;
}
public void installTo(Path worldPath) throws IOException {
Path datapacks = worldPath.resolve("datapacks");
Set<String> packs = new HashSet<>();
for (Pack pack : info) packs.add(pack.getId());
for (Path datapack : Files.newDirectoryStream(datapacks)) {
if (packs.contains(FileUtils.getName(datapack)))
FileUtils.deleteDirectory(datapack.toFile());
}
new Unzipper(path, worldPath).setReplaceExistentFile(true).unzip();
}
public static Datapack fromZip(Path path) throws IOException {
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(path)) {
Datapack datapack = fromDir(fs.getPath("/datapacks/"));
return new Datapack(path, datapack.info);
}
}
/**
*
* @param dir
* @return
* @throws IOException
*/
public static Datapack fromDir(Path dir) throws IOException {
List<Pack> info = new LinkedList<>();
for (Path subDir : Files.newDirectoryStream(dir)) {
Path mcmeta = subDir.resolve("pack.mcmeta");
if (!Files.exists(mcmeta))
continue;
PackMcMeta pack = JsonUtils.fromNonNullJson(FileUtils.readText(mcmeta), PackMcMeta.class);
info.add(new Pack(mcmeta, FileUtils.getName(subDir), pack.getPackInfo().getDescription()));
}
return new Datapack(dir, info);
}
public static class Pack {
private Path packMcMeta;
private final BooleanProperty active;
private final String id;
private final String description;
private Datapack datapack;
public Pack(Path packMcMeta, String id, String description) {
this.packMcMeta = packMcMeta;
this.id = id;
this.description = description;
active = new SimpleBooleanProperty(this, "active", !DISABLED_EXT.equals(FileUtils.getExtension(packMcMeta))) {
@Override
protected void invalidated() {
Path f = Pack.this.packMcMeta.toAbsolutePath(), newF;
if (DISABLED_EXT.equals(FileUtils.getExtension(f)))
newF = f.getParent().resolve(FileUtils.getNameWithoutExtension(f));
else
newF = f.getParent().resolve(FileUtils.getName(f) + DISABLED_EXT);
try {
Files.move(f, newF);
Pack.this.packMcMeta = newF;
} catch (IOException e) {
// Mod file is occupied.
Logging.LOG.warning("Unable to rename file " + f + " to " + newF);
}
}
};
}
public String getId() {
return id;
}
public String getDescription() {
return description;
}
public Datapack getDatapack() {
return datapack;
}
public BooleanProperty activeProperty() {
return active;
}
public boolean isActive() {
return active.get();
}
public void setActive(boolean active) {
this.active.set(active);
}
}
private static class PackMcMeta implements Validation {
@SerializedName("pack")
private final PackInfo pack;
public PackMcMeta() {
this(new PackInfo());
}
public PackMcMeta(PackInfo packInfo) {
this.pack = packInfo;
}
public PackInfo getPackInfo() {
return pack;
}
@Override
public void validate() throws JsonParseException {
if (pack == null)
throw new JsonParseException("pack cannot be null");
}
public static class PackInfo {
@SerializedName("pack_format")
private final int packFormat;
@SerializedName("description")
private final String description;
public PackInfo() {
this(0, "");
}
public PackInfo(int packFormat, String description) {
this.packFormat = packFormat;
this.description = description;
}
public int getPackFormat() {
return packFormat;
}
public String getDescription() {
return description;
}
}
}
private static final String DISABLED_EXT = ".disabled";
}

View File

@@ -43,10 +43,18 @@ public final class FileUtils {
return StringUtils.substringBeforeLast(file.getName(), '.');
}
public static String getNameWithoutExtension(Path file) {
return StringUtils.substringBeforeLast(getName(file), '.');
}
public static String getExtension(File file) {
return StringUtils.substringAfterLast(file.getName(), '.');
}
public static String getExtension(Path file) {
return StringUtils.substringAfterLast(getName(file), '.');
}
/**
* This method is for normalizing ZipPath since Path.normalize of ZipFileSystem does not work properly.
*/
@@ -63,11 +71,15 @@ public final class FileUtils {
}
public static String readText(File file, Charset charset) throws IOException {
return new String(readBytes(file), charset);
return new String(Files.readAllBytes(file.toPath()), charset);
}
public static byte[] readBytes(File file) throws IOException {
return Files.readAllBytes(file.toPath());
public static String readText(Path file) throws IOException {
return readText(file, UTF_8);
}
public static String readText(Path file, Charset charset) throws IOException {
return new String(Files.readAllBytes(file), charset);
}
public static void writeText(File file, String text) throws IOException {