Fix HMCL import

This commit is contained in:
huanghongxun 2019-09-09 15:32:55 +08:00
parent 2f9955febd
commit e69d149c34
14 changed files with 101 additions and 53 deletions

View File

@ -74,7 +74,7 @@ public class HMCLModpackExportTask extends Task<Void> {
return false;
});
Version mv = repository.getResolvedVersion(version);
Version mv = repository.getResolvedPreservingPatchesVersion(version);
String gameVersion = GameVersion.minecraftVersion(repository.getVersionJar(version))
.orElseThrow(() -> new IOException("Cannot parse the version of " + version));
zip.putTextFile(JsonUtils.GSON.toJson(mv.setJar(gameVersion)), "minecraft/pack.json"); // Making "jar" to gameVersion is to be compatible with old HMCL.

View File

@ -19,7 +19,8 @@ package org.jackhuang.hmcl.game;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.DependencyManager;
import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.mod.MinecraftInstanceTask;
import org.jackhuang.hmcl.mod.Modpack;
import org.jackhuang.hmcl.mod.ModpackConfiguration;
@ -39,12 +40,13 @@ public final class HMCLModpackInstallTask extends Task<Void> {
private final File zipFile;
private final String name;
private final HMCLGameRepository repository;
private final DefaultDependencyManager dependency;
private final Modpack modpack;
private final List<Task<?>> dependencies = new LinkedList<>();
private final List<Task<?>> dependents = new LinkedList<>();
public HMCLModpackInstallTask(Profile profile, File zipFile, Modpack modpack, String name) {
DependencyManager dependency = profile.getDependency();
dependency = profile.getDependency();
repository = profile.getRepository();
this.zipFile = zipFile;
this.name = name;
@ -88,8 +90,18 @@ public final class HMCLModpackInstallTask extends Task<Void> {
@Override
public void execute() throws Exception {
String json = CompressingUtils.readTextZipEntry(zipFile, "minecraft/pack.json");
Version version = JsonUtils.GSON.fromJson(json, Version.class).setId(name).setJar(null);
dependencies.add(repository.save(version));
Version originalVersion = JsonUtils.GSON.fromJson(json, Version.class).setId(name).setJar(null);
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(originalVersion);
Task<Version> libraryTask = Task.supplyAsync(() -> originalVersion);
// reinstall libraries
// libraries of Forge and OptiFine should be obtained by installation.
for (LibraryAnalyzer.LibraryMark mark : analyzer) {
if (LibraryAnalyzer.LibraryType.MINECRAFT.getPatchId().equals(mark.getLibraryId()))
continue;
libraryTask = libraryTask.thenComposeAsync(version -> dependency.installLibraryAsync(modpack.getGameVersion(), version, mark.getLibraryId(), mark.getLibraryVersion()));
}
dependencies.add(libraryTask.thenComposeAsync(repository::save));
dependencies.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), "/minecraft", modpack, MODPACK_TYPE, repository.getModpackConfiguration(name)));
}

View File

@ -113,16 +113,14 @@ class AdditionalInstallersPage extends StackPane implements WizardPage {
String liteLoader = analyzer.getVersion(LITELOADER).orElse(null);
String optiFine = analyzer.getVersion(OPTIFINE).orElse(null);
JFXButton[] buttons = new JFXButton[]{btnFabric, btnForge, btnLiteLoader, btnOptiFine};
Label[] labels = new Label[]{lblFabric, lblForge, lblLiteLoader, lblOptiFine};
String[] libraryIds = new String[]{"fabric", "forge", "liteloader", "optifine"};
String[] versions = new String[]{fabric, forge, liteLoader, optiFine};
for (int i = 0; i < libraryIds.length; ++i) {
String libraryId = libraryIds[i];
buttons[i].setDisable(versions[i] != null);
if (versions[i] != null || controller.getSettings().containsKey(libraryId))
labels[i].setText(i18n("install.installer.version", i18n("install.installer." + libraryId)) + ": " + Lang.nonNull(versions[i], getVersion(libraryId)));
labels[i].setText(i18n("install.installer.version", i18n("install.installer." + libraryId)) + ": " + Lang.nonNull(getVersion(libraryId), versions[i]));
else
labels[i].setText(i18n("install.installer.not_installed", i18n("install.installer." + libraryId)));
}

View File

@ -58,8 +58,7 @@ public final class UpdateInstallerWizardProvider implements WizardProvider {
// We remove library but not save it,
// so if installation failed will not break down current version.
return profile.getDependency().removeLibraryWithoutSavingAsync(version.getId(), libraryId)
.thenComposeAsync(profile.getDependency().installLibraryAsync((RemoteVersion) settings.get(libraryId)))
return profile.getDependency().installLibraryAsync(version, (RemoteVersion) settings.get(libraryId))
.thenComposeAsync(profile.getRepository().refreshVersionsAsync());
}

View File

@ -60,14 +60,16 @@ public class GameItem extends Control {
.thenAcceptAsync(game -> {
StringBuilder libraries = new StringBuilder(game);
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(profile.getRepository().getResolvedPreservingPatchesVersion(id));
analyzer.forEachLibrary((libraryId, libraryVersion) -> {
if (libraryId.equals(MINECRAFT.getPatchId())) return;
for (LibraryAnalyzer.LibraryMark mark : analyzer) {
String libraryId = mark.getLibraryId();
String libraryVersion = mark.getLibraryVersion();
if (libraryId.equals(MINECRAFT.getPatchId())) continue;
if (I18n.hasKey("install.installer." + libraryId)) {
libraries.append(", ").append(i18n("install.installer." + libraryId));
if (libraryVersion != null)
libraries.append(": ").append(modifyVersion("", libraryVersion.replaceAll("(?i)" + libraryId, "")));
}
});
}
subtitle.set(libraries.toString());
}, Platform::runLater)

View File

@ -79,14 +79,17 @@ public class InstallerListPage extends ListPageBase<InstallerItem> {
return LibraryAnalyzer.analyze(profile.getRepository().getResolvedPreservingPatchesVersion(versionId));
}).thenAcceptAsync(Schedulers.javafx(), analyzer -> {
Function<String, Consumer<InstallerItem>> removeAction = libraryId -> x -> {
profile.getDependency().removeLibraryAsync(version.getId(), libraryId)
profile.getDependency().removeLibraryAsync(version, libraryId)
.thenComposeAsync(profile.getRepository()::save)
.withComposeAsync(profile.getRepository().refreshVersionsAsync())
.withRunAsync(Schedulers.javafx(), () -> loadVersion(this.profile, this.versionId))
.start();
};
itemsProperty().clear();
analyzer.forEachLibrary((libraryId, libraryVersion) -> {
for (LibraryAnalyzer.LibraryMark mark : analyzer) {
String libraryId = mark.getLibraryId();
String libraryVersion = mark.getLibraryVersion();
String title = I18n.hasKey("install.installer." + libraryId) ? i18n("install.installer." + libraryId) : libraryId;
Consumer<InstallerItem> action = "game".equals(libraryId) ? null : removeAction.apply(libraryId);
if (libraryVersion != null && Lang.test(() -> profile.getDependency().getVersionList(libraryId)))
@ -96,7 +99,7 @@ public class InstallerListPage extends ListPageBase<InstallerItem> {
}, action));
else
itemsProperty().add(new InstallerItem(title, libraryVersion, null, action));
});
}
}).start();
}

View File

@ -101,12 +101,12 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
public Task<Version> installLibraryAsync(Version baseVersion, RemoteVersion libraryVersion) {
if (baseVersion.isResolved()) throw new IllegalArgumentException("Version should not be resolved");
return libraryVersion.getInstallTask(this, baseVersion)
return removeLibraryAsync(baseVersion.resolvePreservingPatches(repository), libraryVersion.getLibraryId())
.thenComposeAsync(version -> libraryVersion.getInstallTask(this, version))
.thenApplyAsync(baseVersion::addPatch)
.thenComposeAsync(repository::save);
}
public ExceptionalFunction<Version, Task<Version>, ?> installLibraryAsync(RemoteVersion libraryVersion) {
return version -> installLibraryAsync(version, libraryVersion);
}
@ -139,28 +139,19 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
* Remove installed library.
* Will try to remove libraries and patches.
*
* @param versionId version id
* @param version not resolved version
* @param libraryId forge/liteloader/optifine/fabric
* @return task to remove the specified library
*/
public Task<Version> removeLibraryWithoutSavingAsync(String versionId, String libraryId) {
public Task<Version> removeLibraryAsync(Version version, String libraryId) {
// MaintainTask requires version that does not inherits from any version.
// If we want to remove a library in dependent version, we should keep the dependents not changed
// So resolving this game version to preserve all information in this version.json is necessary.
Version version = repository.getResolvedPreservingPatchesVersion(versionId);
if (version.isResolved())
throw new IllegalArgumentException("removeLibraryWithoutSavingAsync requires non-resolved version");
Version independentVersion = version.resolvePreservingPatches(repository);
return Task.supplyAsync(() -> LibraryAnalyzer.analyze(version).removeLibrary(libraryId).build());
return Task.supplyAsync(() -> LibraryAnalyzer.analyze(independentVersion).removeLibrary(libraryId).build());
}
/**
* Remove installed library.
* Will try to remove libraries and patches.
*
* @param versionId version id
* @param libraryId forge/liteloader/optifine/fabric
* @return task to remove the specified library
*/
public Task<Version> removeLibraryAsync(String versionId, String libraryId) {
return removeLibraryWithoutSavingAsync(versionId, libraryId).thenComposeAsync(repository::save);
}
}

View File

@ -20,19 +20,17 @@ package org.jackhuang.hmcl.download;
import org.jackhuang.hmcl.game.Library;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public final class LibraryAnalyzer {
import static org.jackhuang.hmcl.util.Pair.pair;
public final class LibraryAnalyzer implements Iterable<LibraryAnalyzer.LibraryMark> {
private Version version;
private final Map<String, Pair<Library, String>> libraries;
@ -49,9 +47,23 @@ public final class LibraryAnalyzer {
return Optional.ofNullable(libraries.get(type)).map(Pair::getValue);
}
public void forEachLibrary(BiConsumer<String, @Nullable String> callback) {
for (Map.Entry<String, Pair<Library, String>> entry : libraries.entrySet())
callback.accept(entry.getKey(), entry.getValue().getValue());
@NotNull
@Override
public Iterator<LibraryMark> iterator() {
return new Iterator<LibraryMark>() {
Iterator<Map.Entry<String, Pair<Library, String>>> impl = libraries.entrySet().iterator();
@Override
public boolean hasNext() {
return impl.hasNext();
}
@Override
public LibraryMark next() {
Map.Entry<String, Pair<Library, String>> entry = impl.next();
return new LibraryMark(entry.getKey(), entry.getValue().getValue());
}
};
}
public boolean has(LibraryType type) {
@ -122,7 +134,7 @@ public final class LibraryAnalyzer {
for (LibraryType type : LibraryType.values()) {
if (type.group.matcher(groupId).matches() && type.artifact.matcher(artifactId).matches()) {
libraries.put(type.getPatchId(), Pair.pair(library, library.getVersion()));
libraries.put(type.getPatchId(), pair(library, library.getVersion()));
break;
}
}
@ -130,7 +142,7 @@ public final class LibraryAnalyzer {
for (Version patch : version.getPatches()) {
if (patch.isHidden()) continue;
libraries.put(patch.getId(), Pair.pair(null, patch.getVersion()));
libraries.put(patch.getId(), pair(null, patch.getVersion()));
}
return new LibraryAnalyzer(version, libraries);
@ -169,4 +181,24 @@ public final class LibraryAnalyzer {
return null;
}
}
public static class LibraryMark {
private final String libraryId;
private final String libraryVersion;
public LibraryMark(@NotNull String libraryId, @Nullable String libraryVersion) {
this.libraryId = libraryId;
this.libraryVersion = libraryVersion;
}
@NotNull
public String getLibraryId() {
return libraryId;
}
@Nullable
public String getLibraryVersion() {
return libraryVersion;
}
}
}

View File

@ -31,6 +31,7 @@ import java.util.Objects;
*/
public class RemoteVersion implements Comparable<RemoteVersion> {
private final String libraryId;
private final String gameVersion;
private final String selfVersion;
private final String url;
@ -43,8 +44,8 @@ public class RemoteVersion implements Comparable<RemoteVersion> {
* @param selfVersion the version string of the remote version.
* @param url the installer or universal jar URL.
*/
public RemoteVersion(String gameVersion, String selfVersion, String url) {
this(gameVersion, selfVersion, url, Type.UNCATEGORIZED);
public RemoteVersion(String libraryId, String gameVersion, String selfVersion, String url) {
this(libraryId, gameVersion, selfVersion, url, Type.UNCATEGORIZED);
}
/**
@ -54,13 +55,18 @@ public class RemoteVersion implements Comparable<RemoteVersion> {
* @param selfVersion the version string of the remote version.
* @param url the installer or universal jar URL.
*/
public RemoteVersion(String gameVersion, String selfVersion, String url, Type type) {
public RemoteVersion(String libraryId, String gameVersion, String selfVersion, String url, Type type) {
this.libraryId = Objects.requireNonNull(libraryId);
this.gameVersion = Objects.requireNonNull(gameVersion);
this.selfVersion = Objects.requireNonNull(selfVersion);
this.url = Objects.requireNonNull(url);
this.type = Objects.requireNonNull(type);
}
public String getLibraryId() {
return libraryId;
}
public String getGameVersion() {
return gameVersion;
}

View File

@ -18,6 +18,7 @@
package org.jackhuang.hmcl.download.fabric;
import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.download.RemoteVersion;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.task.Task;
@ -31,7 +32,7 @@ public class FabricRemoteVersion extends RemoteVersion {
* @param url the installer or universal jar URL.
*/
FabricRemoteVersion(String gameVersion, String selfVersion, String url) {
super(gameVersion, selfVersion, url);
super(LibraryAnalyzer.LibraryType.FABRIC.getPatchId(), gameVersion, selfVersion, url);
}
@Override

View File

@ -18,6 +18,7 @@
package org.jackhuang.hmcl.download.forge;
import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.download.RemoteVersion;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.task.Task;
@ -31,7 +32,7 @@ public class ForgeRemoteVersion extends RemoteVersion {
* @param url the installer or universal jar URL.
*/
public ForgeRemoteVersion(String gameVersion, String selfVersion, String url) {
super(gameVersion, selfVersion, url);
super(LibraryAnalyzer.LibraryType.FORGE.getPatchId(), gameVersion, selfVersion, url);
}
@Override

View File

@ -18,6 +18,7 @@
package org.jackhuang.hmcl.download.game;
import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.download.RemoteVersion;
import org.jackhuang.hmcl.game.ReleaseType;
import org.jackhuang.hmcl.game.Version;
@ -37,7 +38,7 @@ public final class GameRemoteVersion extends RemoteVersion {
private final Date time;
public GameRemoteVersion(String gameVersion, String selfVersion, String url, ReleaseType type, Date time) {
super(gameVersion, selfVersion, url, getReleaseType(type));
super(LibraryAnalyzer.LibraryType.MINECRAFT.getPatchId(), gameVersion, selfVersion, url, getReleaseType(type));
this.type = type;
this.time = time;
}

View File

@ -18,6 +18,7 @@
package org.jackhuang.hmcl.download.liteloader;
import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.download.RemoteVersion;
import org.jackhuang.hmcl.game.Library;
import org.jackhuang.hmcl.game.Version;
@ -36,7 +37,7 @@ public class LiteLoaderRemoteVersion extends RemoteVersion {
* @param url the installer or universal jar URL.
*/
LiteLoaderRemoteVersion(String gameVersion, String selfVersion, String url, String tweakClass, Collection<Library> libraries) {
super(gameVersion, selfVersion, url);
super(LibraryAnalyzer.LibraryType.LITELOADER.getPatchId(), gameVersion, selfVersion, url);
this.tweakClass = tweakClass;
this.libraries = libraries;

View File

@ -18,6 +18,7 @@
package org.jackhuang.hmcl.download.optifine;
import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.download.RemoteVersion;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.task.Task;
@ -28,7 +29,7 @@ public class OptiFineRemoteVersion extends RemoteVersion {
private final Supplier<String> url;
public OptiFineRemoteVersion(String gameVersion, String selfVersion, Supplier<String> url, boolean snapshot) {
super(gameVersion, selfVersion, "", snapshot ? Type.SNAPSHOT : Type.RELEASE);
super(LibraryAnalyzer.LibraryType.OPTIFINE.getPatchId(), gameVersion, selfVersion, "", snapshot ? Type.SNAPSHOT : Type.RELEASE);
this.url = url;
}