From 7aee7e33d06bce8f39b20b84d346df479c6dbefa Mon Sep 17 00:00:00 2001 From: huanghongxun Date: Tue, 20 Aug 2019 00:53:36 +0800 Subject: [PATCH] Making versions whose library being removed pure patched --- .../download/DefaultDependencyManager.java | 3 +- .../jackhuang/hmcl/download/MaintainTask.java | 10 +- .../download/fabric/FabricInstallTask.java | 7 +- .../download/forge/ForgeNewInstallTask.java | 2 +- .../download/forge/ForgeOldInstallTask.java | 2 +- .../liteloader/LiteLoaderInstallTask.java | 3 +- .../optifine/OptiFineInstallTask.java | 9 +- .../org/jackhuang/hmcl/game/Artifact.java | 57 ++++-- .../jackhuang/hmcl/game/ClassicVersion.java | 6 +- .../java/org/jackhuang/hmcl/game/Library.java | 185 ++++++++---------- .../java/org/jackhuang/hmcl/game/Version.java | 63 +++--- .../jackhuang/hmcl/mod/ModpackUpdateTask.java | 2 + .../org/jackhuang/hmcl/util/io/FileUtils.java | 4 +- 13 files changed, 187 insertions(+), 166 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java index 35b71fb33..f20c88dcc 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java @@ -146,8 +146,7 @@ public class DefaultDependencyManager extends AbstractDependencyManager { // So resolving this game version to preserve all information in this version.json is necessary. Version version = repository.getResolvedPreservingPatchesVersion(versionId); - return Task.supplyAsync(() -> MaintainTask.maintain(repository, LibraryAnalyzer.analyze(version) - .removeLibrary(libraryId).build())); + return Task.supplyAsync(() -> LibraryAnalyzer.analyze(version).removeLibrary(libraryId).build()); } /** diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MaintainTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MaintainTask.java index 1feb9abcf..40d3a6f51 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MaintainTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MaintainTask.java @@ -17,6 +17,7 @@ */ package org.jackhuang.hmcl.download; +import org.jackhuang.hmcl.game.Artifact; import org.jackhuang.hmcl.game.CompatibilityRule; import org.jackhuang.hmcl.game.GameRepository; import org.jackhuang.hmcl.game.Library; @@ -37,10 +38,11 @@ import java.util.stream.Collectors; import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.*; public class MaintainTask extends Task { - + private final GameRepository repository; private final Version version; - public MaintainTask(Version version) { + public MaintainTask(GameRepository repository, Version version) { + this.repository = repository; this.version = version; if (version.getInheritsFrom() != null) @@ -49,7 +51,7 @@ public class MaintainTask extends Task { @Override public void execute() { - setResult(maintain(null, version)); + setResult(maintain(repository, version)); } public static Version maintain(GameRepository repository, Version version) { @@ -115,7 +117,7 @@ public class MaintainTask extends Task { for (int i = 0; i < version.getLibraries().size(); ++i) { Library library = libraries.get(i); if (library.is("optifine", "OptiFine")) { - Library newLibrary = new Library("optifine", "OptiFine", library.getVersion(), "installer", null, null); + Library newLibrary = new Library(new Artifact("optifine", "OptiFine", library.getVersion(), "installer")); if (repository.getLibraryFile(version, newLibrary).exists()) { libraries.set(i, null); // OptiFine should be loaded after Forge in classpath. diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricInstallTask.java index 16c3a047f..832065e76 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricInstallTask.java @@ -21,6 +21,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.game.Arguments; +import org.jackhuang.hmcl.game.Artifact; import org.jackhuang.hmcl.game.Library; import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.task.GetTask; @@ -65,7 +66,7 @@ public final class FabricInstallTask extends Task { @Override public void preExecute() { - if (!Objects.equals("net.minecraft.client.main.Main", version.getMainClass())) + if (!Objects.equals("net.minecraft.client.main.Main", version.resolve(dependencyManager.getGameRepository()).getMainClass())) throw new UnsupportedFabricInstallationException(); } @@ -121,8 +122,8 @@ public final class FabricInstallTask extends Task { } } - libraries.add(new Library("net.fabricmc", "intermediary", gameVersion, null, "https://maven.fabricmc.net/", null)); - libraries.add(new Library("net.fabricmc", "fabric-loader", loaderVersion, null, "https://maven.fabricmc.net/", null)); + libraries.add(new Library(new Artifact("net.fabricmc", "intermediary", gameVersion), "https://maven.fabricmc.net/", null)); + libraries.add(new Library(new Artifact("net.fabricmc", "fabric-loader", loaderVersion), "https://maven.fabricmc.net/", null)); return new Version("net.fabricmc", loaderVersion, 30000, arguments, mainClass, libraries); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java index c88d6ae9f..3b5eb6f92 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java @@ -88,7 +88,7 @@ public class ForgeNewInstallTask extends Task { else if (StringUtils.isSurrounded(literal, "'", "'")) return StringUtils.removeSurrounding(literal, "'"); else if (StringUtils.isSurrounded(literal, "[", "]")) - return gameRepository.getArtifactFile(version, new Artifact(StringUtils.removeSurrounding(literal, "[", "]"))).toString(); + return gameRepository.getArtifactFile(version, Artifact.fromDescriptor(StringUtils.removeSurrounding(literal, "[", "]"))).toString(); else return plainConverter.apply(literal); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeOldInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeOldInstallTask.java index 987542eb3..db74f5c2d 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeOldInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeOldInstallTask.java @@ -74,7 +74,7 @@ public class ForgeOldInstallTask extends Task { ForgeInstallProfile installProfile = JsonUtils.fromNonNullJson(json, ForgeInstallProfile.class); // unpack the universal jar in the installer file. - Library forgeLibrary = Library.fromName(installProfile.getInstall().getPath().toString()); + Library forgeLibrary = new Library(installProfile.getInstall().getPath()); File forgeFile = dependencyManager.getGameRepository().getLibraryFile(version, forgeLibrary); if (!FileUtils.makeFile(forgeFile)) throw new IOException("Cannot make directory " + forgeFile.getParent()); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderInstallTask.java index f6a655938..ca3fb661b 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderInstallTask.java @@ -20,6 +20,7 @@ package org.jackhuang.hmcl.download.liteloader; import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.game.Arguments; +import org.jackhuang.hmcl.game.Artifact; import org.jackhuang.hmcl.game.LibrariesDownloadInfo; import org.jackhuang.hmcl.game.Library; import org.jackhuang.hmcl.game.LibraryDownloadInfo; @@ -64,7 +65,7 @@ public final class LiteLoaderInstallTask extends Task { @Override public void execute() { Library library = new Library( - "com.mumfrey", "liteloader", remote.getSelfVersion(), null, + new Artifact("com.mumfrey", "liteloader", remote.getSelfVersion()), "http://dl.liteloader.com/versions/", new LibrariesDownloadInfo(new LibraryDownloadInfo(null, remote.getUrl())) ); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java index 342eadd2c..9fff32b54 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java @@ -21,6 +21,7 @@ import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.download.VersionMismatchException; import org.jackhuang.hmcl.game.Arguments; +import org.jackhuang.hmcl.game.Artifact; import org.jackhuang.hmcl.game.DefaultGameRepository; import org.jackhuang.hmcl.game.GameVersion; import org.jackhuang.hmcl.game.LibrariesDownloadInfo; @@ -84,10 +85,10 @@ public final class OptiFineInstallTask extends Task { String mavenVersion = remote.getGameVersion() + "_" + remote.getSelfVersion(); - optiFineLibrary = new Library("optifine", "OptiFine", mavenVersion); + optiFineLibrary = new Library(new Artifact("optifine", "OptiFine", mavenVersion)); optiFineInstallerLibrary = new Library( - "optifine", "OptiFine", mavenVersion, "installer", null, + new Artifact("optifine", "OptiFine", mavenVersion, "installer"), null, new LibrariesDownloadInfo(new LibraryDownloadInfo( "optifine/OptiFine/" + mavenVersion + "/OptiFine-" + mavenVersion + "-installer.jar", remote.getUrl())) @@ -158,7 +159,7 @@ public final class OptiFineInstallTask extends Task { String launchWrapperVersion = FileUtils.readText(launchWrapperVersionText).trim(); Path launchWrapperJar = fs.getPath("launchwrapper-of-" + launchWrapperVersion + ".jar"); - Library launchWrapper = new Library("optifine", "launchwrapper-of", launchWrapperVersion); + Library launchWrapper = new Library(new Artifact("optifine", "launchwrapper-of", launchWrapperVersion)); if (Files.exists(launchWrapperJar)) { File launchWrapperFile = gameRepository.getLibraryFile(version, launchWrapper); @@ -172,7 +173,7 @@ public final class OptiFineInstallTask extends Task { } if (!hasLaunchWrapper) { - libraries.add(new Library("net.minecraft", "launchwrapper", "1.12")); + libraries.add(new Library(new Artifact("net.minecraft", "launchwrapper", "1.12"))); } setResult(new Version( diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Artifact.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Artifact.java index 3fe42e943..62369ebf0 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Artifact.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Artifact.java @@ -17,7 +17,14 @@ */ package org.jackhuang.hmcl.game; -import com.google.gson.*; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; import com.google.gson.annotations.JsonAdapter; import org.jackhuang.hmcl.util.Immutable; @@ -38,9 +45,34 @@ public final class Artifact { private final String fileName; private final String path; - public Artifact(String descriptor) { - this.descriptor = descriptor; + public Artifact(String group, String name, String version) { + this(group, name, version, null); + } + public Artifact(String group, String name, String version, String classifier) { + this(group, name, version, classifier, null); + } + + public Artifact(String group, String name, String version, String classifier, String extension) { + this.group = group; + this.name = name; + this.version = version; + this.classifier = classifier; + this.extension = extension == null ? "jar" : extension; + + String fileName = this.name + "-" + this.version; + if (classifier != null) fileName += "-" + this.classifier; + this.fileName = fileName + "." + this.extension; + this.path = String.format("%s/%s/%s/%s", this.group.replace(".", "/"), this.name, this.version, this.fileName); + + // group:name:version:classifier@extension + String descriptor = String.format("%s:%s:%s", group, name, version); + if (classifier != null) descriptor += ":" + classifier; + if (!"jar".equals(this.extension)) descriptor += "@" + this.extension; + this.descriptor = descriptor; + } + + public static Artifact fromDescriptor(String descriptor) { String[] arr = descriptor.split(":", 4); if (arr.length != 3 && arr.length != 4) throw new IllegalArgumentException("Artifact name is malformed"); @@ -55,16 +87,7 @@ public final class Artifact { throw new IllegalArgumentException("Artifact name is malformed"); } - this.group = arr[0].replace("\\", "/"); - this.name = arr[1]; - this.version = arr[2]; - this.classifier = arr.length >= 4 ? arr[3] : null; - this.extension = ext == null ? "jar" : ext; - - String fileName = this.name + "-" + this.version; - if (classifier != null) fileName += "-" + this.classifier; - this.fileName = fileName + "." + this.extension; - this.path = String.format("%s/%s/%s/%s", this.group.replace(".", "/"), this.name, this.version, this.fileName); + return new Artifact(arr[0].replace("\\", "/"), arr[1], arr[2], arr.length >= 4 ? arr[3] : null, ext); } public String getGroup() { @@ -83,6 +106,10 @@ public final class Artifact { return classifier; } + public Artifact setClassifier(String classifier) { + return new Artifact(group, name, version, classifier, extension); + } + public String getExtension() { return extension; } @@ -91,6 +118,8 @@ public final class Artifact { return fileName; } + public String getPath() { return path; } + public Path getPath(Path root) { return root.resolve(path); } @@ -108,7 +137,7 @@ public final class Artifact { @Override public Artifact deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - return json.isJsonPrimitive() ? new Artifact(json.getAsJsonPrimitive().getAsString()) : null; + return json.isJsonPrimitive() ? fromDescriptor(json.getAsJsonPrimitive().getAsString()) : null; } } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/ClassicVersion.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/ClassicVersion.java index b3d07568f..2263f3400 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/ClassicVersion.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/ClassicVersion.java @@ -32,15 +32,15 @@ public class ClassicVersion extends Version { super(true, "Classic", null, null, "${auth_player_name} ${auth_session} --workDir ${game_directory}", null, "net.minecraft.client.Minecraft", null, null, null, null, Arrays.asList(new ClassicLibrary("lwjgl"), new ClassicLibrary("jinput"), new ClassicLibrary("lwjgl_util")), - null, null, null, ReleaseType.UNKNOWN, new Date(), new Date(), 0, false, null); + null, null, null, ReleaseType.UNKNOWN, new Date(), new Date(), 0, false, false, null); } private static class ClassicLibrary extends Library { public ClassicLibrary(String name) { - super("", "", "", null, null, + super(new Artifact("", "", ""), null, new LibrariesDownloadInfo(new LibraryDownloadInfo("bin/" + name + ".jar"), null), - null, null, null, null); + null, null, null, null, null, null); } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Library.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Library.java index 73e8a9de3..b430d7a40 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Library.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Library.java @@ -17,15 +17,16 @@ */ package org.jackhuang.hmcl.game; -import com.google.gson.*; -import com.google.gson.annotations.JsonAdapter; -import com.google.gson.reflect.TypeToken; +import com.google.gson.JsonParseException; +import com.google.gson.annotations.SerializedName; import org.jackhuang.hmcl.util.Constants; +import org.jackhuang.hmcl.util.Immutable; import org.jackhuang.hmcl.util.ToStringBuilder; +import org.jackhuang.hmcl.util.gson.TolerableValidationException; +import org.jackhuang.hmcl.util.gson.Validation; import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.Platform; -import java.lang.reflect.Type; import java.util.List; import java.util.Map; import java.util.Objects; @@ -36,83 +37,68 @@ import java.util.Optional; * * @author huangyuhui */ -@JsonAdapter(Library.Serializer.class) -public class Library implements Comparable { +@Immutable +public class Library implements Comparable, Validation { - private final String groupId; - private final String artifactId; - private final String version; - private final String classifier; + @SerializedName("name") + private final Artifact artifact; private final String url; private final LibrariesDownloadInfo downloads; - private transient final LibraryDownloadInfo download; private final ExtractRules extract; private final Map natives; private final List rules; private final List checksums; - private transient final String path; + @SerializedName(value = "hint", alternate = {"MMC-hint"}) + private final String hint; - public Library(String groupId, String artifactId, String version) { - this(groupId, artifactId, version, null, null, null); + @SerializedName(value = "filename", alternate = {"MMC-filename"}) + private final String fileName; + + public Library(Artifact artifact) { + this(artifact, null, null); } - public Library(String groupId, String artifactId, String version, String classifier, String url, LibrariesDownloadInfo downloads) { - this(groupId, artifactId, version, classifier, url, downloads, null, null, null, null); + public Library(Artifact artifact, String url, LibrariesDownloadInfo downloads) { + this(artifact, url, downloads, null, null, null, null, null, null); } - public Library(String groupId, String artifactId, String version, String classifier, String url, LibrariesDownloadInfo downloads, List checksums, ExtractRules extract, Map natives, List rules) { - this.groupId = groupId; - this.artifactId = artifactId; - this.version = version; - if (classifier == null) - if (natives != null && natives.containsKey(OperatingSystem.CURRENT_OS)) - this.classifier = natives.get(OperatingSystem.CURRENT_OS).replace("${arch}", Platform.PLATFORM.getBit()); - else - this.classifier = null; - else - this.classifier = classifier; + public Library(Artifact artifact, String url, LibrariesDownloadInfo downloads, List checksums, ExtractRules extract, Map natives, List rules, String hint, String filename) { + this.artifact = artifact; this.url = url; this.downloads = downloads; this.extract = extract; this.natives = natives; this.rules = rules; this.checksums = checksums; - - LibraryDownloadInfo temp = null; - if (downloads != null) - if (isNative()) - temp = downloads.getClassifiers().get(this.classifier); - else - temp = downloads.getArtifact(); - - if (temp != null && temp.getPath() != null) - path = temp.getPath(); - else - path = String.format("%s/%s/%s/%s-%s", groupId.replace(".", "/"), artifactId, version, artifactId, version) - + (this.classifier == null ? "" : "-" + this.classifier) + ".jar"; - - download = new LibraryDownloadInfo(path, - Optional.ofNullable(temp).map(LibraryDownloadInfo::getUrl).orElse(Optional.ofNullable(url).orElse(Constants.DEFAULT_LIBRARY_URL) + path), - temp != null ? temp.getSha1() : null, - temp != null ? temp.getSize() : 0 - ); + this.hint = hint; + this.fileName = filename; } public String getGroupId() { - return groupId; + return artifact.getGroup(); } public String getArtifactId() { - return artifactId; + return artifact.getName(); } public String getName() { - return groupId + ":" + artifactId + ":" + version; + return artifact.toString(); } public String getVersion() { - return version; + return artifact.getVersion(); + } + + public String getClassifier() { + if (artifact.getClassifier() == null) + if (natives != null && natives.containsKey(OperatingSystem.CURRENT_OS)) + return natives.get(OperatingSystem.CURRENT_OS).replace("${arch}", Platform.PLATFORM.getBit()); + else + return null; + else + return artifact.getClassifier(); } public ExtractRules getExtract() { @@ -127,12 +113,33 @@ public class Library implements Comparable { return natives != null && appliesToCurrentEnvironment(); } + protected LibraryDownloadInfo getRawDownloadInfo() { + if (downloads != null) { + if (isNative()) + return downloads.getClassifiers().get(getClassifier()); + else + return downloads.getArtifact(); + } else { + return null; + } + } + public String getPath() { - return path; + LibraryDownloadInfo temp = getRawDownloadInfo(); + if (temp != null && temp.getPath() != null) + return temp.getPath(); + else + return artifact.setClassifier(getClassifier()).getPath(); } public LibraryDownloadInfo getDownload() { - return download; + LibraryDownloadInfo temp = getRawDownloadInfo(); + String path = getPath(); + return new LibraryDownloadInfo(path, + Optional.ofNullable(temp).map(LibraryDownloadInfo::getUrl).orElse(Optional.ofNullable(url).orElse(Constants.DEFAULT_LIBRARY_URL) + path), + temp != null ? temp.getSha1() : null, + temp != null ? temp.getSize() : 0 + ); } public List getChecksums() { @@ -143,8 +150,24 @@ public class Library implements Comparable { return rules; } + /** + * Hint for how to locate the library file. + * @return null for default, "local" for location in version/<version>/libraries/filename + */ + public String getHint() { + return hint; + } + + /** + * Available when hint is "local" + * @return the filename of the local library in version/<version>/libraries/$filename + */ + public String getFileName() { + return fileName; + } + public boolean is(String groupId, String artifactId) { - return this.groupId.equals(groupId) && this.artifactId.equals(artifactId); + return getGroupId().equals(groupId) && getArtifactId().equals(artifactId); } @Override @@ -175,58 +198,12 @@ public class Library implements Comparable { } public Library setClassifier(String classifier) { - return new Library(groupId, artifactId, version, classifier, url, downloads, checksums, extract, natives, rules); + return new Library(artifact.setClassifier(classifier), url, downloads, checksums, extract, natives, rules, hint, fileName); } - public static Library fromName(String name) { - return fromName(name, null, null, null, null, null, null); - } - - public static Library fromName(String name, String url, LibrariesDownloadInfo downloads, List checksums, ExtractRules extract, Map natives, List rules) { - String[] arr = name.split(":", 4); - if (arr.length != 3 && arr.length != 4) - throw new IllegalArgumentException("Library name is malformed. Correct example: group:artifact:version(:classifier)."); - - return new Library(arr[0].replace("\\", "/"), arr[1], arr[2], arr.length >= 4 ? arr[3] : null, url, downloads, checksums, extract, natives, rules); - } - - public static class Serializer implements JsonDeserializer, JsonSerializer { - @Override - public Library deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException { - if (json == null || json == JsonNull.INSTANCE) - return null; - JsonObject jsonObject = json.getAsJsonObject(); - if (!jsonObject.has("name")) - throw new JsonParseException("Library name not found."); - return fromName( - jsonObject.get("name").getAsString(), - jsonObject.has("url") ? jsonObject.get("url").getAsString() : null, - context.deserialize(jsonObject.get("downloads"), LibrariesDownloadInfo.class), - context.deserialize(jsonObject.get("checksums"), new TypeToken>() { - }.getType()), - context.deserialize(jsonObject.get("extract"), ExtractRules.class), - context.deserialize(jsonObject.get("natives"), new TypeToken>() { - }.getType()), - context.deserialize(jsonObject.get("rules"), new TypeToken>() { - }.getType())); - } - - @Override - public JsonElement serialize(Library src, Type type, JsonSerializationContext context) { - if (src == null) - return JsonNull.INSTANCE; - JsonObject obj = new JsonObject(); - obj.addProperty("name", src.getName()); - obj.addProperty("url", src.url); - obj.add("downloads", context.serialize(src.downloads)); - obj.add("checksums", context.serialize(src.getChecksums())); - obj.add("extract", context.serialize(src.extract)); - obj.add("natives", context.serialize(src.natives, new TypeToken>() { - }.getType())); - obj.add("rules", context.serialize(src.rules, new TypeToken>() { - }.getType())); - return obj; - } - + @Override + public void validate() throws JsonParseException, TolerableValidationException { + if (artifact == null) + throw new JsonParseException("Library.name cannot be null"); } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Version.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Version.java index 99b30a6b5..7f912f011 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Version.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Version.java @@ -66,13 +66,14 @@ public class Version implements Comparable, Validation { private final Date time; private final Date releaseTime; private final Integer minimumLauncherVersion; + private final Boolean root; private final Boolean hidden; private final List patches; private transient final boolean resolved; public Version(String id) { - this(false, id, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, false, null); + this(false, id, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, false, true, null); } /** @@ -85,10 +86,10 @@ public class Version implements Comparable, Validation { * @param libraries additional libraries */ public Version(String id, String version, int priority, Arguments arguments, String mainClass, List libraries) { - this(false, id, version, priority, null, arguments, mainClass, null, null, null, null, libraries, null, null, null, null, null, null, null, null, null); + this(false, id, version, priority, null, arguments, mainClass, null, null, null, null, libraries, null, null, null, null, null, null, null, null, null, null); } - public Version(boolean resolved, String id, String version, Integer priority, String minecraftArguments, Arguments arguments, String mainClass, String inheritsFrom, String jar, AssetIndexInfo assetIndex, String assets, List libraries, List compatibilityRules, Map downloads, Map logging, ReleaseType type, Date time, Date releaseTime, Integer minimumLauncherVersion, Boolean hidden, List patches) { + public Version(boolean resolved, String id, String version, Integer priority, String minecraftArguments, Arguments arguments, String mainClass, String inheritsFrom, String jar, AssetIndexInfo assetIndex, String assets, List libraries, List compatibilityRules, Map downloads, Map logging, ReleaseType type, Date time, Date releaseTime, Integer minimumLauncherVersion, Boolean hidden, Boolean root, List patches) { this.resolved = resolved; this.id = id; this.version = version; @@ -109,6 +110,7 @@ public class Version implements Comparable, Validation { this.releaseTime = releaseTime == null ? null : (Date) releaseTime.clone(); this.minimumLauncherVersion = minimumLauncherVersion; this.hidden = hidden; + this.root = root; this.patches = Lang.copyList(patches); } @@ -170,6 +172,8 @@ public class Version implements Comparable, Validation { return hidden == null ? false : hidden; } + public boolean isRoot() { return root == null ? false : root; } + public boolean isResolved() { return resolved; } @@ -219,7 +223,7 @@ public class Version implements Comparable, Validation { return resolve(provider, new HashSet<>()).setResolved(); } - protected Version merge(Version parent) { + protected Version merge(Version parent, boolean isPatch) { return new Version( true, id, @@ -241,7 +245,8 @@ public class Version implements Comparable, Validation { releaseTime, Lang.merge(minimumLauncherVersion, parent.minimumLauncherVersion, Math::max), hidden, - Lang.merge(Lang.merge(parent.patches, Collections.singleton(this.clearPatches().setHidden(true).setId("resolved." + getId()))), patches)); + false, + isPatch ? parent.patches : Lang.merge(Lang.merge(parent.patches, Collections.singleton(toPatch())), patches)); } protected Version resolve(VersionProvider provider, Set resolvedSoFar) throws VersionNotFoundException { @@ -256,7 +261,7 @@ public class Version implements Comparable, Validation { thisVersion = this.jar == null ? this.setJar(id) : this; } else { // It is supposed to auto install an version in getVersion. - thisVersion = merge(provider.getVersion(inheritsFrom).resolve(provider, resolvedSoFar)); + thisVersion = merge(provider.getVersion(inheritsFrom).resolve(provider, resolvedSoFar), false); } } @@ -266,13 +271,17 @@ public class Version implements Comparable, Validation { .sorted(Comparator.comparing(Version::getPriority)) .collect(Collectors.toList()); for (Version patch : sortedPatches) { - thisVersion = patch.setJar(null).merge(thisVersion); + thisVersion = patch.setJar(null).merge(thisVersion, true); } } return thisVersion.setId(id); } + private Version toPatch() { + return this.clearPatches().setHidden(true).setId("resolved." + getId()); + } + /** * Resolve the version preserving all dependencies and patches. */ @@ -281,19 +290,19 @@ public class Version implements Comparable, Validation { } protected Version mergePreservingPatches(Version parent) { - return parent.addPatch(this.clearPatches().setHidden(true).setId("resolved." + getId())).addPatches(patches); + return parent.addPatch(toPatch()).addPatches(patches); } protected Version resolvePreservingPatches(VersionProvider provider, Set resolvedSoFar) throws VersionNotFoundException { - Version thisVersion; + Version thisVersion = isRoot() ? this : new Version(id).addPatch(toPatch()).addPatches(getPatches()); if (inheritsFrom == null) { - thisVersion = this; + // keep thisVersion } else { // To maximize the compatibility. if (!resolvedSoFar.add(id)) { Logging.LOG.log(Level.WARNING, "Found circular dependency versions: " + resolvedSoFar); - thisVersion = this; + // keep thisVersion } else { // It is supposed to auto install an version in getVersion. thisVersion = mergePreservingPatches(provider.getVersion(inheritsFrom).resolvePreservingPatches(provider, resolvedSoFar)); @@ -304,55 +313,55 @@ public class Version implements Comparable, Validation { } private Version setResolved() { - return new Version(true, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, patches); + return new Version(true, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, patches); } private Version setHidden(Boolean hidden) { - return new Version(true, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, patches); + return new Version(true, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, patches); } public Version setId(String id) { - return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, patches); + return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, patches); } public Version setVersion(String version) { - return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, patches); + return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, patches); } public Version setPriority(Integer priority) { - return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, patches); + return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, patches); } public Version setMinecraftArguments(String minecraftArguments) { - return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, patches); + return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, patches); } public Version setArguments(Arguments arguments) { - return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, patches); + return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, patches); } public Version setMainClass(String mainClass) { - return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, patches); + return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, patches); } public Version setInheritsFrom(String inheritsFrom) { - return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, patches); + return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, patches); } public Version setJar(String jar) { - return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, patches); + return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, patches); } public Version setLibraries(List libraries) { - return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, patches); + return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, patches); } public Version setLogging(Map logging) { - return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, patches); + return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, patches); } public Version setPatches(List patches) { - return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, patches); + return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, patches); } public Version addPatch(Version... additional) { @@ -360,15 +369,15 @@ public class Version implements Comparable, Validation { } public Version addPatches(List additional) { - return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, Lang.merge(patches, additional)); + return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, Lang.merge(patches, additional)); } public Version clearPatches() { - return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, null); + return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root,null); } public Version removePatchById(String patchId) { - return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, + return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, patches == null ? null : patches.stream().filter(patch -> !patchId.equals(patch.getId())).collect(Collectors.toList())); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModpackUpdateTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModpackUpdateTask.java index 608f81692..e36af42d0 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModpackUpdateTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModpackUpdateTask.java @@ -72,6 +72,8 @@ public class ModpackUpdateTask extends Task { repository.removeVersionFromDisk(id); FileUtils.copyDirectory(backupFolder, repository.getVersionRoot(id).toPath()); + + repository.refreshVersionsAsync().start(); } } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/FileUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/FileUtils.java index 077ae0ca0..c02d580da 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/FileUtils.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/FileUtils.java @@ -199,7 +199,7 @@ public final class FileUtils { Files.walkFileTree(src, new SimpleFileVisitor(){ @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - Path destFile = dest.resolve(src.relativize(file)); + Path destFile = dest.resolve(src.relativize(file).toString()); Files.copy(file, destFile, StandardCopyOption.REPLACE_EXISTING); return FileVisitResult.CONTINUE; @@ -207,7 +207,7 @@ public final class FileUtils { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - Path destDir = dest.resolve(src.relativize(dir)); + Path destDir = dest.resolve(src.relativize(dir).toString()); Files.createDirectories(destDir); return FileVisitResult.CONTINUE;