From a853374a884834d8cff5805b601297cfd7ce421e Mon Sep 17 00:00:00 2001 From: huangyuhui Date: Sat, 7 Jul 2018 00:48:48 +0800 Subject: [PATCH] Support new MultiMC modpack --- .../download/game/LibraryDownloadTask.java | 3 +- .../mod/MultiMCInstanceConfiguration.java | 16 +- .../jackhuang/hmcl/mod/MultiMCManifest.java | 152 ++++++++++++++++++ .../hmcl/mod/MultiMCModpackInstallTask.java | 21 ++- 4 files changed, 187 insertions(+), 5 deletions(-) create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MultiMCManifest.java diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java index fcc569197..e979f008f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java @@ -49,7 +49,8 @@ public final class LibraryDownloadTask extends Task { setSignificance(TaskSignificance.MODERATE); task = new FileDownloadTask(NetworkUtils.toURL(url), - file, dependencyManager.getProxy(), new IntegrityCheck("SHA-1", library.getDownload().getSha1())); + file, dependencyManager.getProxy(), + library.getDownload().getSha1() != null ? new IntegrityCheck("SHA-1", library.getDownload().getSha1()) : null); } @Override diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MultiMCInstanceConfiguration.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MultiMCInstanceConfiguration.java index f5d71b5e9..bbdf22222 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MultiMCInstanceConfiguration.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MultiMCInstanceConfiguration.java @@ -58,12 +58,17 @@ public final class MultiMCInstanceConfiguration { private final boolean overrideCommands; // OverrideCommands private final boolean overrideWindow; // OverrideWindow - public MultiMCInstanceConfiguration(String defaultName, InputStream contentStream) throws IOException { + private final MultiMCManifest mmcPack; + + private MultiMCInstanceConfiguration(String defaultName, InputStream contentStream, MultiMCManifest mmcPack) throws IOException { Properties p = new Properties(); p.load(contentStream); + this.mmcPack = mmcPack; + autoCloseConsole = Boolean.parseBoolean(p.getProperty("AutoCloseConsole")); - gameVersion = p.getProperty("IntendedVersion"); + gameVersion = mmcPack != null ? mmcPack.getComponents().stream().filter(e -> "net.minecraft".equals(e.getUid())).findAny() + .orElseThrow(() -> new IOException("Malformed mmc-pack.json")).getVersion() : p.getProperty("IntendedVersion"); javaPath = p.getProperty("JavaPath"); jvmArgs = p.getProperty("JvmArgs"); fullscreen = Boolean.parseBoolean(p.getProperty("LaunchMaximized")); @@ -253,6 +258,10 @@ public final class MultiMCInstanceConfiguration { return overrideWindow; } + public MultiMCManifest getMmcPack() { + return mmcPack; + } + public static Modpack readMultiMCModpackManifest(File f) throws IOException { try (ZipFile zipFile = new ZipFile(f)) { ZipArchiveEntry firstEntry = zipFile.getEntries().nextElement(); @@ -260,7 +269,8 @@ public final class MultiMCInstanceConfiguration { ZipArchiveEntry entry = zipFile.getEntry(name + "/instance.cfg"); if (entry == null) throw new IOException("`instance.cfg` not found, " + f + " is not a valid MultiMC modpack."); - MultiMCInstanceConfiguration cfg = new MultiMCInstanceConfiguration(name, zipFile.getInputStream(entry)); + MultiMCManifest manifest = MultiMCManifest.readMultiMCModpackManifest(f); + MultiMCInstanceConfiguration cfg = new MultiMCInstanceConfiguration(name, zipFile.getInputStream(entry), manifest); return new Modpack(cfg.getName(), "", "", cfg.getGameVersion(), cfg.getNotes(), cfg); } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MultiMCManifest.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MultiMCManifest.java new file mode 100644 index 000000000..933d99695 --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MultiMCManifest.java @@ -0,0 +1,152 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * 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; + +import com.google.gson.JsonParseException; +import com.google.gson.annotations.SerializedName; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; +import org.apache.commons.compress.archivers.zip.ZipFile; +import org.jackhuang.hmcl.util.*; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +@Immutable +public final class MultiMCManifest { + + @SerializedName("formatVersion") + private final int formatVersion; + + @SerializedName("components") + private final List components; + + public MultiMCManifest(int formatVersion, List components) { + this.formatVersion = formatVersion; + this.components = components; + } + + public int getFormatVersion() { + return formatVersion; + } + + public List getComponents() { + return components; + } + + public static MultiMCManifest readMultiMCModpackManifest(File f) throws IOException { + try (ZipFile zipFile = new ZipFile(f)) { + ZipArchiveEntry firstEntry = zipFile.getEntries().nextElement(); + String name = StringUtils.substringBefore(firstEntry.getName(), '/'); + ZipArchiveEntry entry = zipFile.getEntry(name + "/mmc-pack.json"); + if (entry == null) + return null; + String json = IOUtils.readFullyAsString(zipFile.getInputStream(entry)); + MultiMCManifest manifest = JsonUtils.fromNonNullJson(json, MultiMCManifest.class); + + if (manifest != null && manifest.getComponents() == null) + throw new IOException("mmc-pack.json malformed."); + + return manifest; + } + } + + public static final class MultiMCManifestCachedRequires { + @SerializedName("equals") + private final String equalsVersion; + + @SerializedName("uid") + private final String uid; + + @SerializedName("suggests") + private final String suggests; + + + + public MultiMCManifestCachedRequires(String equalsVersion, String uid, String suggests) { + this.equalsVersion = equalsVersion; + this.uid = uid; + this.suggests = suggests; + } + + public String getEqualsVersion() { + return equalsVersion; + } + + public String getUid() { + return uid; + } + + public String getSuggests() { + return suggests; + } + } + + public static final class MultiMCManifestComponent { + @SerializedName("cachedName") + private final String cachedName; + + @SerializedName("cachedRequires") + private final List cachedRequires; + + @SerializedName("cachedVersion") + private final String cachedVersion; + + @SerializedName("important") + private final boolean important; + + @SerializedName("uid") + private final String uid; + + @SerializedName("version") + private final String version; + + public MultiMCManifestComponent(String cachedName, List cachedRequires, String cachedVersion, boolean important, String uid, String version) { + this.cachedName = cachedName; + this.cachedRequires = cachedRequires; + this.cachedVersion = cachedVersion; + this.important = important; + this.uid = uid; + this.version = version; + } + + public String getCachedName() { + return cachedName; + } + + public List getCachedRequires() { + return cachedRequires; + } + + public String getCachedVersion() { + return cachedVersion; + } + + public boolean isImportant() { + return important; + } + + public String getUid() { + return uid; + } + + public String getVersion() { + return version; + } + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MultiMCModpackInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MultiMCModpackInstallTask.java index 692390880..eb7f291e8 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MultiMCModpackInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MultiMCModpackInstallTask.java @@ -22,6 +22,7 @@ import com.google.gson.reflect.TypeToken; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipFile; import org.jackhuang.hmcl.download.DefaultDependencyManager; +import org.jackhuang.hmcl.download.GameBuilder; import org.jackhuang.hmcl.download.game.VersionJsonSaveTask; import org.jackhuang.hmcl.game.Arguments; import org.jackhuang.hmcl.game.DefaultGameRepository; @@ -37,6 +38,7 @@ import java.io.IOException; import java.util.LinkedList; import java.util.List; import java.util.Objects; +import java.util.Optional; /** * @@ -61,7 +63,24 @@ public final class MultiMCModpackInstallTask extends Task { 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()); + + GameBuilder builder = dependencyManager.gameBuilder().name(name).gameVersion(manifest.getGameVersion()); + + if (manifest.getMmcPack() != null) { + Optional forge = manifest.getMmcPack().getComponents().stream().filter(e -> e.getUid().equals("net.minecraftforge")).findAny(); + forge.ifPresent(c -> { + if (c.getVersion() != null) + builder.version("forge", c.getVersion()); + }); + + Optional liteLoader = manifest.getMmcPack().getComponents().stream().filter(e -> e.getUid().equals("com.mumfrey.liteloader")).findAny(); + liteLoader.ifPresent(c -> { + if (c.getVersion() != null) + builder.version("liteloader", c.getVersion()); + }); + } + + dependents.add(builder.buildAsync()); onDone().register(event -> { if (event.isFailed()) repository.removeVersionFromDisk(name);