Modpack updates UI
This commit is contained in:
4
HMCLCore/gradlew
vendored
4
HMCLCore/gradlew
vendored
@@ -78,14 +78,14 @@ if [ -n "$JAVA_HOME" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
path of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
path of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
|
||||
4
HMCLCore/gradlew.bat
vendored
4
HMCLCore/gradlew.bat
vendored
@@ -27,7 +27,7 @@ echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo path of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
@@ -41,7 +41,7 @@ echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo path of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
|
||||
@@ -41,6 +41,14 @@ public class DefaultGameBuilder extends GameBuilder {
|
||||
this.downloadProvider = dependencyManager.getDownloadProvider();
|
||||
}
|
||||
|
||||
public DefaultDependencyManager getDependencyManager() {
|
||||
return dependencyManager;
|
||||
}
|
||||
|
||||
public DownloadProvider getDownloadProvider() {
|
||||
return downloadProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task buildAsync() {
|
||||
return new VersionJsonDownloadTask(gameVersion, dependencyManager).then(variables -> {
|
||||
@@ -50,7 +58,7 @@ public class DefaultGameBuilder extends GameBuilder {
|
||||
Task result = new ParallelTask(
|
||||
new GameAssetDownloadTask(dependencyManager, version),
|
||||
new GameLoggingDownloadTask(dependencyManager, version),
|
||||
new GameDownloadTask(dependencyManager, version),
|
||||
downloadGameAsync(gameVersion, version),
|
||||
new GameLibrariesTask(dependencyManager, version) // Game libraries will be downloaded for multiple times partly, this time is for vanilla libraries.
|
||||
).with(new VersionJsonSaveTask(dependencyManager.getGameRepository(), version)); // using [with] because download failure here are tolerant.
|
||||
|
||||
@@ -68,4 +76,8 @@ public class DefaultGameBuilder extends GameBuilder {
|
||||
return variables -> dependencyManager.installLibraryAsync(gameVersion, variables.get("version"), libraryId, toolVersions.get(libraryId));
|
||||
}
|
||||
|
||||
protected Task downloadGameAsync(String gameVersion, Version version) {
|
||||
return new GameDownloadTask(dependencyManager, version);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -310,4 +310,12 @@ public class DefaultGameRepository implements GameRepository {
|
||||
return loaded;
|
||||
}
|
||||
|
||||
public File getModpackConfiguration(String version) {
|
||||
return new File(getRunDirectory(version), "modpack.json");
|
||||
}
|
||||
|
||||
public boolean isModpack(String version) {
|
||||
return getModpackConfiguration(version).exists();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.download.GameBuilder;
|
||||
import org.jackhuang.hmcl.game.DefaultGameRepository;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.CompressingUtils;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.FileUtils;
|
||||
|
||||
@@ -32,7 +31,6 @@ import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Install a downloaded CurseForge modpack.
|
||||
@@ -68,7 +66,7 @@ public final class CurseInstallTask extends Task {
|
||||
this.repository = dependencyManager.getGameRepository();
|
||||
this.run = repository.getRunDirectory(name);
|
||||
|
||||
File json = new File(run, "modpack.json");
|
||||
File json = repository.getModpackConfiguration(name);
|
||||
if (repository.hasVersion(name) && !json.exists())
|
||||
throw new IllegalArgumentException("Version " + name + " already exists.");
|
||||
|
||||
@@ -80,8 +78,13 @@ public final class CurseInstallTask extends Task {
|
||||
|
||||
ModpackConfiguration<CurseManifest> config = null;
|
||||
try {
|
||||
if (json.exists())
|
||||
config = Constants.GSON.fromJson(FileUtils.readText(json), new TypeToken<ModpackConfiguration<CurseManifest>>(){}.getType());
|
||||
if (json.exists()) {
|
||||
config = Constants.GSON.fromJson(FileUtils.readText(json), new TypeToken<ModpackConfiguration<CurseManifest>>() {
|
||||
}.getType());
|
||||
|
||||
if (!MODPACK_TYPE.equals(config.getType()))
|
||||
throw new IllegalArgumentException("Version " + name + " is not a Curse modpack. Cannot update this version.");
|
||||
}
|
||||
} catch (JsonParseException | IOException ignore) {
|
||||
}
|
||||
this.config = config;
|
||||
@@ -110,7 +113,8 @@ public final class CurseInstallTask extends Task {
|
||||
}
|
||||
|
||||
dependencies.add(new CurseCompletionTask(dependencyManager, name));
|
||||
dependencies.add(new MinecraftInstanceTask<>(zipFile, manifest.getOverrides(), false, manifest, new File(run, "modpack.json")));
|
||||
dependencies.add(new MinecraftInstanceTask<>(zipFile, manifest.getOverrides(), manifest, MODPACK_TYPE, repository.getModpackConfiguration(name)));
|
||||
}
|
||||
|
||||
public static final String MODPACK_TYPE = "Curse";
|
||||
}
|
||||
|
||||
@@ -23,11 +23,12 @@ import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.DigestUtils;
|
||||
import org.jackhuang.hmcl.util.FileUtils;
|
||||
import org.jackhuang.hmcl.util.IOUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public final class MinecraftInstanceTask<T> extends Task {
|
||||
@@ -36,12 +37,14 @@ public final class MinecraftInstanceTask<T> extends Task {
|
||||
private final String subDirectory;
|
||||
private final File jsonFile;
|
||||
private final T manifest;
|
||||
private final String type;
|
||||
|
||||
public MinecraftInstanceTask(File zipFile, String subDirectory, T manifest, File jsonFile) {
|
||||
public MinecraftInstanceTask(File zipFile, String subDirectory, T manifest, String type, File jsonFile) {
|
||||
this.zipFile = zipFile;
|
||||
this.subDirectory = subDirectory;
|
||||
this.manifest = manifest;
|
||||
this.jsonFile = jsonFile;
|
||||
this.type = type;
|
||||
|
||||
if (!zipFile.exists())
|
||||
throw new IllegalArgumentException("File " + zipFile + " does not exist. Cannot parse this modpack.");
|
||||
@@ -49,9 +52,8 @@ public final class MinecraftInstanceTask<T> extends Task {
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
Map<String, ModpackConfiguration.FileInformation> overrides = new HashMap<>();
|
||||
List<ModpackConfiguration.FileInformation> overrides = new LinkedList<>();
|
||||
|
||||
byte[] buf = new byte[IOUtils.DEFAULT_BUFFER_SIZE];
|
||||
try (ZipArchiveInputStream zip = new ZipArchiveInputStream(new FileInputStream(zipFile), null, true, true)) {
|
||||
ArchiveEntry entry;
|
||||
while ((entry = zip.getNextEntry()) != null) {
|
||||
@@ -62,12 +64,10 @@ public final class MinecraftInstanceTask<T> extends Task {
|
||||
if (path.startsWith("/") || path.startsWith("\\"))
|
||||
path = path.substring(1);
|
||||
|
||||
overrides.put(path, new ModpackConfiguration.FileInformation(
|
||||
path, DigestUtils.sha1Hex(zip)
|
||||
));
|
||||
overrides.add(new ModpackConfiguration.FileInformation(path, DigestUtils.sha1Hex(zip)));
|
||||
}
|
||||
}
|
||||
|
||||
FileUtils.writeText(jsonFile, Constants.GSON.toJson(new ModpackConfiguration<>(manifest, overrides)));
|
||||
FileUtils.writeText(jsonFile, Constants.GSON.toJson(new ModpackConfiguration<>(manifest, type, overrides)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.mod;
|
||||
|
||||
public class MismatchedModpackTypeException extends Exception {
|
||||
private final String required;
|
||||
private final String found;
|
||||
|
||||
public MismatchedModpackTypeException(String required, String found) {
|
||||
super("Required " + required + ", but found " + found);
|
||||
|
||||
this.required = required;
|
||||
this.found = found;
|
||||
}
|
||||
}
|
||||
@@ -21,50 +21,56 @@ import com.google.gson.JsonParseException;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.Validation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
@Immutable
|
||||
public final class ModpackConfiguration<T> implements Validation {
|
||||
|
||||
private final T manifest;
|
||||
|
||||
private final Map<String, FileInformation> overrides;
|
||||
private final String type;
|
||||
private final List<FileInformation> overrides;
|
||||
|
||||
public ModpackConfiguration() {
|
||||
this(null, Collections.emptyMap());
|
||||
this(null, null, Collections.emptyList());
|
||||
}
|
||||
|
||||
public ModpackConfiguration(T manifest, Map<String, FileInformation> overrides) {
|
||||
public ModpackConfiguration(T manifest, String type, List<FileInformation> overrides) {
|
||||
this.manifest = manifest;
|
||||
this.overrides = overrides;
|
||||
this.type = type;
|
||||
this.overrides = new ArrayList<>(overrides);
|
||||
}
|
||||
|
||||
public T getManifest() {
|
||||
return manifest;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public ModpackConfiguration<T> setManifest(T manifest) {
|
||||
return new ModpackConfiguration<>(manifest, overrides);
|
||||
return new ModpackConfiguration<>(manifest, type, overrides);
|
||||
}
|
||||
|
||||
public ModpackConfiguration<T> setOverrides(Map<String, FileInformation> overrides) {
|
||||
return new ModpackConfiguration<>(manifest, overrides);
|
||||
public ModpackConfiguration<T> setOverrides(List<FileInformation> overrides) {
|
||||
return new ModpackConfiguration<>(manifest, type, overrides);
|
||||
}
|
||||
|
||||
public Map<String, FileInformation> getOverrides() {
|
||||
return Collections.unmodifiableMap(overrides);
|
||||
public List<FileInformation> getOverrides() {
|
||||
return Collections.unmodifiableList(overrides);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() throws JsonParseException {
|
||||
if (manifest == null)
|
||||
throw new JsonParseException("MinecraftInstanceConfiguration missing `manifest`");
|
||||
if (type == null)
|
||||
throw new JsonParseException("MinecraftInstanceConfiguration missing `type`");
|
||||
}
|
||||
|
||||
@Immutable
|
||||
public static class FileInformation implements Validation {
|
||||
private final String location; // relative
|
||||
private final String path; // relative
|
||||
private final String hash;
|
||||
private final String downloadURL;
|
||||
|
||||
@@ -72,18 +78,22 @@ public final class ModpackConfiguration<T> implements Validation {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
public FileInformation(String location, String hash) {
|
||||
this(location, hash, null);
|
||||
public FileInformation(String path, String hash) {
|
||||
this(path, hash, null);
|
||||
}
|
||||
|
||||
public FileInformation(String location, String hash, String downloadURL) {
|
||||
this.location = location;
|
||||
public FileInformation(String path, String hash, String downloadURL) {
|
||||
this.path = path;
|
||||
this.hash = hash;
|
||||
this.downloadURL = downloadURL;
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return location;
|
||||
/**
|
||||
* The relative path to Minecraft run directory
|
||||
* @return
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public String getDownloadURL() {
|
||||
@@ -96,8 +106,8 @@ public final class ModpackConfiguration<T> implements Validation {
|
||||
|
||||
@Override
|
||||
public void validate() throws JsonParseException {
|
||||
if (location == null)
|
||||
throw new JsonParseException("FileInformation missing `location`.");
|
||||
if (path == null)
|
||||
throw new JsonParseException("FileInformation missing `path`.");
|
||||
if (hash == null)
|
||||
throw new JsonParseException("FileInformation missing file hash code.");
|
||||
}
|
||||
|
||||
@@ -25,10 +25,7 @@ import org.jackhuang.hmcl.util.FileUtils;
|
||||
import org.jackhuang.hmcl.util.IOUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ModpackInstallTask<T> extends Task {
|
||||
@@ -36,7 +33,7 @@ public class ModpackInstallTask<T> extends Task {
|
||||
private final File modpackFile;
|
||||
private final File dest;
|
||||
private final String subDirectory;
|
||||
private final Map<String, ModpackConfiguration.FileInformation> overrides;
|
||||
private final List<ModpackConfiguration.FileInformation> overrides;
|
||||
private final Predicate<String> callback;
|
||||
|
||||
public ModpackInstallTask(File modpackFile, File dest, String subDirectory, Predicate<String> callback, ModpackConfiguration<T> oldConfiguration) {
|
||||
@@ -46,7 +43,7 @@ public class ModpackInstallTask<T> extends Task {
|
||||
this.callback = callback;
|
||||
|
||||
if (oldConfiguration == null)
|
||||
overrides = Collections.emptyMap();
|
||||
overrides = Collections.emptyList();
|
||||
else
|
||||
overrides = oldConfiguration.getOverrides();
|
||||
}
|
||||
@@ -57,6 +54,11 @@ public class ModpackInstallTask<T> extends Task {
|
||||
byte[] buf = new byte[IOUtils.DEFAULT_BUFFER_SIZE];
|
||||
if (!FileUtils.makeDirectory(dest))
|
||||
throw new IOException("Unable to make directory " + dest);
|
||||
|
||||
HashSet<String> files = new HashSet<>();
|
||||
for (ModpackConfiguration.FileInformation file : overrides)
|
||||
files.add(file.getPath());
|
||||
|
||||
try (ZipArchiveInputStream zipStream = new ZipArchiveInputStream(new FileInputStream(modpackFile), null, true, true)) {
|
||||
ArchiveEntry entry;
|
||||
while ((entry = zipStream.getNextEntry()) != null) {
|
||||
@@ -86,7 +88,7 @@ public class ModpackInstallTask<T> extends Task {
|
||||
IOUtils.copyTo(zipStream, os, buf);
|
||||
byte[] data = os.toByteArray();
|
||||
|
||||
if (!overrides.containsKey(path) || entryFile.exists()) {
|
||||
if (files.contains(path) && entryFile.exists()) {
|
||||
String oldHash = DigestUtils.sha1Hex(new FileInputStream(entryFile));
|
||||
String newHash = DigestUtils.sha1Hex(new ByteArrayInputStream(data));
|
||||
if (!oldHash.equals(newHash)) {
|
||||
@@ -94,15 +96,19 @@ public class ModpackInstallTask<T> extends Task {
|
||||
IOUtils.copyTo(new ByteArrayInputStream(data), fos, buf);
|
||||
}
|
||||
}
|
||||
} else if (!files.contains(path)) {
|
||||
try (FileOutputStream fos = new FileOutputStream(entryFile)) {
|
||||
IOUtils.copyTo(new ByteArrayInputStream(data), fos, buf);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (String path : overrides.keySet()) {
|
||||
File original = new File(dest, path);
|
||||
if (original.exists() && !entries.contains(path))
|
||||
for (ModpackConfiguration.FileInformation file : overrides) {
|
||||
File original = new File(dest, file.getPath());
|
||||
if (original.exists() && !entries.contains(file.getPath()))
|
||||
original.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public final class MultiMCModpackInstallTask extends Task {
|
||||
this.repository = dependencyManager.getGameRepository();
|
||||
this.run = repository.getRunDirectory(name);
|
||||
|
||||
File json = new File(run, "modpack.json");
|
||||
File json = repository.getModpackConfiguration(name);
|
||||
if (repository.hasVersion(name) && !json.exists())
|
||||
throw new IllegalArgumentException("Version " + name + " already exists.");
|
||||
dependents.add(dependencyManager.gameBuilder().name(name).gameVersion(manifest.getGameVersion()).buildAsync());
|
||||
@@ -69,8 +69,13 @@ public final class MultiMCModpackInstallTask extends Task {
|
||||
|
||||
ModpackConfiguration<MultiMCInstanceConfiguration> config = null;
|
||||
try {
|
||||
if (json.exists())
|
||||
config = Constants.GSON.fromJson(FileUtils.readText(json), new TypeToken<ModpackConfiguration<MultiMCInstanceConfiguration>>(){}.getType());
|
||||
if (json.exists()) {
|
||||
config = Constants.GSON.fromJson(FileUtils.readText(json), new TypeToken<ModpackConfiguration<MultiMCInstanceConfiguration>>() {
|
||||
}.getType());
|
||||
|
||||
if (!MODPACK_TYPE.equals(config.getType()))
|
||||
throw new IllegalArgumentException("Version " + name + " is not a MultiMC modpack. Cannot update this version.");
|
||||
}
|
||||
} catch (JsonParseException | IOException ignore) {
|
||||
}
|
||||
|
||||
@@ -110,7 +115,8 @@ public final class MultiMCModpackInstallTask extends Task {
|
||||
}
|
||||
|
||||
dependencies.add(new VersionJsonSaveTask(repository, version));
|
||||
dependencies.add(new MinecraftInstanceTask<>(zipFile, manifest.getName() + "/minecraft/", manifest, new File(run, "modpack.json")));
|
||||
dependencies.add(new MinecraftInstanceTask<>(zipFile, manifest.getName() + "/minecraft/", manifest, MODPACK_TYPE, repository.getModpackConfiguration(name)));
|
||||
}
|
||||
|
||||
|
||||
public static final String MODPACK_TYPE = "MultiMC";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.mod;
|
||||
|
||||
public class UnsupportedModpackException extends Exception {
|
||||
public UnsupportedModpackException() {
|
||||
}
|
||||
|
||||
public UnsupportedModpackException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public UnsupportedModpackException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public UnsupportedModpackException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -114,7 +114,7 @@ public class FileDownloadTask extends Task {
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
URL currentURL = url;
|
||||
Logging.LOG.log(Level.FINER, "Downloading {0}, to {1}", new Object[] { currentURL, file });
|
||||
Logging.LOG.log(Level.FINER, "Downloading {0} to {1}", new Object[] { currentURL, file });
|
||||
Exception exception = null;
|
||||
|
||||
for (int repeat = 0; repeat < retry; repeat++) {
|
||||
@@ -193,7 +193,7 @@ public class FileDownloadTask extends Task {
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
} else {
|
||||
if (file.exists() || !file.delete())
|
||||
if (file.exists() && !file.delete())
|
||||
throw new IOException("Unable to delete existent file " + file);
|
||||
if (!FileUtils.makeDirectory(file.getAbsoluteFile().getParentFile()))
|
||||
throw new IOException("Unable to make parent directory " + file);
|
||||
|
||||
Reference in New Issue
Block a user