Support fabric auto-installation

This commit is contained in:
huanghongxun
2019-08-16 12:35:56 +08:00
parent d53d56d93a
commit eb6baa8ad1
31 changed files with 484 additions and 176 deletions

View File

@@ -17,6 +17,7 @@
*/
package org.jackhuang.hmcl.download;
import org.jackhuang.hmcl.download.fabric.FabricVersionList;
import org.jackhuang.hmcl.download.forge.ForgeBMCLVersionList;
import org.jackhuang.hmcl.download.game.GameVersionList;
import org.jackhuang.hmcl.download.liteloader.LiteLoaderBMCLVersionList;
@@ -43,6 +44,8 @@ public class BMCLAPIDownloadProvider implements DownloadProvider {
switch (id) {
case "game":
return GameVersionList.INSTANCE;
case "fabric":
return FabricVersionList.INSTANCE;
case "forge":
return ForgeBMCLVersionList.INSTANCE;
case "liteloader":

View File

@@ -18,14 +18,10 @@
package org.jackhuang.hmcl.download;
import org.jackhuang.hmcl.download.forge.ForgeInstallTask;
import org.jackhuang.hmcl.download.forge.ForgeRemoteVersion;
import org.jackhuang.hmcl.download.game.GameAssetDownloadTask;
import org.jackhuang.hmcl.download.game.GameDownloadTask;
import org.jackhuang.hmcl.download.game.GameLibrariesTask;
import org.jackhuang.hmcl.download.liteloader.LiteLoaderInstallTask;
import org.jackhuang.hmcl.download.liteloader.LiteLoaderRemoteVersion;
import org.jackhuang.hmcl.download.optifine.OptiFineInstallTask;
import org.jackhuang.hmcl.download.optifine.OptiFineRemoteVersion;
import org.jackhuang.hmcl.game.DefaultGameRepository;
import org.jackhuang.hmcl.game.Library;
import org.jackhuang.hmcl.game.Version;
@@ -93,30 +89,21 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
}
@Override
public Task<Version> installLibraryAsync(String gameVersion, Version version, String libraryId, String libraryVersion) {
if (version.isResolved()) throw new IllegalArgumentException("Version should not be resolved");
public Task<Version> installLibraryAsync(String gameVersion, Version baseVersion, String libraryId, String libraryVersion) {
if (baseVersion.isResolved()) throw new IllegalArgumentException("Version should not be resolved");
VersionList<?> versionList = getVersionList(libraryId);
return versionList.loadAsync(gameVersion, getDownloadProvider())
.thenComposeAsync(() -> installLibraryAsync(version, versionList.getVersion(gameVersion, libraryVersion)
.thenComposeAsync(() -> installLibraryAsync(baseVersion, versionList.getVersion(gameVersion, libraryVersion)
.orElseThrow(() -> new IllegalStateException("Remote library " + libraryId + " has no version " + libraryVersion))));
}
@Override
public Task<Version> installLibraryAsync(Version oldVersion, RemoteVersion libraryVersion) {
if (oldVersion.isResolved()) throw new IllegalArgumentException("Version should not be resolved");
public Task<Version> installLibraryAsync(Version baseVersion, RemoteVersion libraryVersion) {
if (baseVersion.isResolved()) throw new IllegalArgumentException("Version should not be resolved");
Task<Version> task;
if (libraryVersion instanceof ForgeRemoteVersion)
task = new ForgeInstallTask(this, oldVersion, (ForgeRemoteVersion) libraryVersion);
else if (libraryVersion instanceof LiteLoaderRemoteVersion)
task = new LiteLoaderInstallTask(this, oldVersion, (LiteLoaderRemoteVersion) libraryVersion);
else if (libraryVersion instanceof OptiFineRemoteVersion)
task = new OptiFineInstallTask(this, oldVersion, (OptiFineRemoteVersion) libraryVersion);
else
throw new IllegalArgumentException("Remote library " + libraryVersion + " is unrecognized.");
return task
.thenApplyAsync(oldVersion::addPatch)
return libraryVersion.getInstallTask(this, baseVersion)
.thenApplyAsync(baseVersion::addPatch)
.thenComposeAsync(repository::save);
}
@@ -163,19 +150,19 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
switch (libraryId) {
case "forge":
analyzer.ifPresent(LibraryAnalyzer.LibraryType.FORGE, (library, libraryVersion) -> newList.remove(library));
version = version.removePatchById("net.minecraftforge");
version = version.removePatchById(LibraryAnalyzer.LibraryType.FORGE.getPatchId());
break;
case "liteloader":
analyzer.ifPresent(LibraryAnalyzer.LibraryType.LITELOADER, (library, libraryVersion) -> newList.remove(library));
version = version.removePatchById("com.mumfrey.liteloader");
version = version.removePatchById(LibraryAnalyzer.LibraryType.LITELOADER.getPatchId());
break;
case "optifine":
analyzer.ifPresent(LibraryAnalyzer.LibraryType.OPTIFINE, (library, libraryVersion) -> newList.remove(library));
version = version.removePatchById("net.optifine");
version = version.removePatchById(LibraryAnalyzer.LibraryType.OPTIFINE.getPatchId());
break;
case "fabric":
analyzer.ifPresent(LibraryAnalyzer.LibraryType.FABRIC, (library, libraryVersion) -> newList.remove(library));
version = version.removePatchById("net.fabricmc");
version = version.removePatchById(LibraryAnalyzer.LibraryType.FABRIC.getPatchId());
break;
}
return new MaintainTask(version.setLibraries(newList));

View File

@@ -26,6 +26,8 @@ import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.function.ExceptionalFunction;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import java.util.Map;
/**
*
* @author huangyuhui
@@ -60,12 +62,8 @@ public class DefaultGameBuilder extends GameBuilder {
Task<Version> libraryTask = vanillaTask.thenSupplyAsync(() -> version);
if (toolVersions.containsKey("forge"))
libraryTask = libraryTask.thenComposeAsync(libraryTaskHelper(gameVersion, "forge"));
if (toolVersions.containsKey("liteloader"))
libraryTask = libraryTask.thenComposeAsync(libraryTaskHelper(gameVersion, "liteloader"));
if (toolVersions.containsKey("optifine"))
libraryTask = libraryTask.thenComposeAsync(libraryTaskHelper(gameVersion, "optifine"));
for (Map.Entry<String, String> entry : toolVersions.entrySet())
libraryTask = libraryTask.thenComposeAsync(libraryTaskHelper(gameVersion, entry.getKey(), entry.getValue()));
for (RemoteVersion remoteVersion : remoteVersions)
libraryTask = libraryTask.thenComposeAsync(dependencyManager.installLibraryAsync(remoteVersion));
@@ -77,8 +75,8 @@ public class DefaultGameBuilder extends GameBuilder {
});
}
private ExceptionalFunction<Version, Task<Version>, ?> libraryTaskHelper(String gameVersion, String libraryId) {
return version -> dependencyManager.installLibraryAsync(gameVersion, version, libraryId, toolVersions.get(libraryId));
private ExceptionalFunction<Version, Task<Version>, ?> libraryTaskHelper(String gameVersion, String libraryId, String libraryVersion) {
return version -> dependencyManager.installLibraryAsync(gameVersion, version, libraryId, libraryVersion);
}
protected Task<Void> downloadGameAsync(String gameVersion, Version version) {

View File

@@ -66,22 +66,22 @@ public interface DependencyManager {
* **Note**: Installing a library may change the version.json.
*
* @param gameVersion the Minecraft version that the library relies on.
* @param version the version.json.
* @param baseVersion the version.json.
* @param libraryId the type of being installed library. i.e. "forge", "liteloader", "optifine"
* @param libraryVersion the version of being installed library.
* @return the task to install the specific library.
*/
Task<?> installLibraryAsync(String gameVersion, Version version, String libraryId, String libraryVersion);
Task<?> installLibraryAsync(String gameVersion, Version baseVersion, String libraryId, String libraryVersion);
/**
* Install a library to a version.
* **Note**: Installing a library may change the version.json.
*
* @param version the version.json.\
* @param baseVersion the version.json.
* @param libraryVersion the remote version of being installed library.
* @return the task to install the specific library.
*/
Task<?> installLibraryAsync(Version version, RemoteVersion libraryVersion);
Task<?> installLibraryAsync(Version baseVersion, RemoteVersion libraryVersion);
/**
* Get registered version list.

View File

@@ -84,10 +84,10 @@ public final class LibraryAnalyzer {
}
public enum LibraryType {
FORGE(true, "net.minecraftforge", Pattern.compile("net\\.minecraftforge"), Pattern.compile("forge")),
LITELOADER(true, "com.mumfrey.liteloader", Pattern.compile("com\\.mumfrey"), Pattern.compile("liteloader")),
OPTIFINE(false, "net.optifine", Pattern.compile("(net\\.)?optifine"), Pattern.compile(".*")),
FABRIC(true, "net.fabricmc", Pattern.compile("net\\.fabricmc"), Pattern.compile("fabric-loader"));
FABRIC(true, "fabric", Pattern.compile("net\\.fabricmc"), Pattern.compile("fabric-loader")),
FORGE(true, "forge", Pattern.compile("net\\.minecraftforge"), Pattern.compile("forge")),
LITELOADER(true, "liteloader", Pattern.compile("com\\.mumfrey"), Pattern.compile("liteloader")),
OPTIFINE(false, "optifine", Pattern.compile("(net\\.)?optifine"), Pattern.compile("^(?!.*launchwrapper).*$"));
private final boolean modLoader;
private final String patchId;
@@ -103,5 +103,9 @@ public final class LibraryAnalyzer {
public boolean isModLoader() {
return modLoader;
}
public String getPatchId() {
return patchId;
}
}
}

View File

@@ -40,6 +40,7 @@ public class MaintainTask extends Task<Version> {
} else {
// Vanilla Minecraft does not need maintain
// Forge 1.13 support not implemented, not compatible with OptiFine currently.
// Fabric does not need maintain, nothing compatible with fabric now.
return version;
}
}

View File

@@ -17,6 +17,7 @@
*/
package org.jackhuang.hmcl.download;
import org.jackhuang.hmcl.download.fabric.FabricVersionList;
import org.jackhuang.hmcl.download.forge.ForgeBMCLVersionList;
import org.jackhuang.hmcl.download.game.GameVersionList;
import org.jackhuang.hmcl.download.liteloader.LiteLoaderVersionList;
@@ -43,6 +44,8 @@ public class MojangDownloadProvider implements DownloadProvider {
switch (id) {
case "game":
return GameVersionList.INSTANCE;
case "fabric":
return FabricVersionList.INSTANCE;
case "forge":
return ForgeBMCLVersionList.INSTANCE;
case "liteloader":

View File

@@ -17,6 +17,8 @@
*/
package org.jackhuang.hmcl.download;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.ToStringBuilder;
import org.jackhuang.hmcl.util.versioning.VersionNumber;
@@ -75,6 +77,10 @@ public class RemoteVersion implements Comparable<RemoteVersion> {
return type;
}
public Task<Version> getInstallTask(DefaultDependencyManager dependencyManager, Version baseVersion) {
throw new UnsupportedOperationException(toString() + " cannot be installed yet");
}
@Override
public boolean equals(Object obj) {
return obj instanceof RemoteVersion && Objects.equals(selfVersion, ((RemoteVersion) obj).selfVersion);

View File

@@ -0,0 +1,132 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2019 huangyuhui <huanghongxun2008@126.com> and contributors
*
* 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 <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.download.fabric;
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.Library;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.task.GetTask;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.NetworkUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
/**
* <b>Note</b>: Fabric should be installed first.
*
* @author huangyuhui
*/
public final class FabricInstallTask extends Task<Version> {
private final DefaultDependencyManager dependencyManager;
private final Version version;
private final FabricRemoteVersion remote;
private final GetTask launchMetaTask;
private final List<Task<?>> dependencies = new LinkedList<>();
public FabricInstallTask(DefaultDependencyManager dependencyManager, Version version, FabricRemoteVersion remoteVersion) {
this.dependencyManager = dependencyManager;
this.version = version;
this.remote = remoteVersion;
launchMetaTask = new GetTask(NetworkUtils.toURL(getLaunchMetaUrl(remote.getSelfVersion())))
.setCacheRepository(dependencyManager.getCacheRepository());
}
@Override
public boolean doPreExecute() {
return true;
}
@Override
public void preExecute() {
if (!Objects.equals("net.minecraft.client.main.Main", version.getMainClass()))
throw new UnsupportedFabricInstallationException();
}
@Override
public Collection<Task<?>> getDependents() {
return Collections.singleton(launchMetaTask);
}
@Override
public Collection<Task<?>> getDependencies() {
return dependencies;
}
@Override
public boolean isRelyingOnDependencies() {
return false;
}
@Override
public void execute() throws IOException {
setResult(getPatch(JsonUtils.GSON.fromJson(launchMetaTask.getResult(), JsonObject.class), remote.getGameVersion(), remote.getSelfVersion()));
dependencies.add(dependencyManager.checkLibraryCompletionAsync(getResult()));
}
private static String getLaunchMetaUrl(String loaderVersion) {
return String.format("%s/%s/%s/%s/%3$s-%4$s.json", "https://maven.fabricmc.net/", "net/fabricmc", "fabric-loader", loaderVersion);
}
private Version getPatch(JsonObject jsonObject, String gameVersion, String loaderVersion) {
Arguments arguments = new Arguments();
String mainClass;
if (!jsonObject.get("mainClass").isJsonObject()) {
mainClass = jsonObject.get("mainClass").getAsString();
} else {
mainClass = jsonObject.get("mainClass").getAsJsonObject().get("client").getAsString();
}
if (jsonObject.has("launchwrapper")) {
String clientTweaker = jsonObject.get("launchwrapper").getAsJsonObject().get("tweakers").getAsJsonObject().get("client").getAsJsonArray().get(0).getAsString();
arguments = arguments.addGameArguments("--tweakClass", clientTweaker);
}
JsonObject librariesObject = jsonObject.getAsJsonObject("libraries");
List<Library> libraries = new ArrayList<>();
// "common, server" is hard coded in fabric installer.
// Don't know the purpose of ignoring client libraries.
for (String side : new String[]{"common", "server"}) {
for (JsonElement element : librariesObject.getAsJsonArray(side)) {
libraries.add(JsonUtils.GSON.fromJson(element, Library.class));
}
}
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));
return new Version("net.fabricmc", loaderVersion, 30000, arguments, mainClass, libraries);
}
public static class UnsupportedFabricInstallationException extends UnsupportedOperationException {
}
}

View File

@@ -0,0 +1,41 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2019 huangyuhui <huanghongxun2008@126.com> and contributors
*
* 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 <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.download.fabric;
import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.RemoteVersion;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.task.Task;
public class FabricRemoteVersion extends RemoteVersion {
/**
* Constructor.
*
* @param gameVersion the Minecraft version that this remote version suits.
* @param selfVersion the version string of the remote version.
* @param url the installer or universal jar URL.
*/
FabricRemoteVersion(String gameVersion, String selfVersion, String url) {
super(gameVersion, selfVersion, url);
}
@Override
public Task<Version> getInstallTask(DefaultDependencyManager dependencyManager, Version baseVersion) {
return new FabricInstallTask(dependencyManager, baseVersion, this);
}
}

View File

@@ -0,0 +1,119 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2019 huangyuhui <huanghongxun2008@126.com> and contributors
*
* 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 <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.download.fabric;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.DownloadProvider;
import org.jackhuang.hmcl.download.VersionList;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.NetworkUtils;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public final class FabricVersionList extends VersionList<FabricRemoteVersion> {
public static final FabricVersionList INSTANCE = new FabricVersionList();
private FabricVersionList() {
}
@Override
public boolean hasType() {
return false;
}
@Override
public Task<?> refreshAsync(DownloadProvider downloadProvider) {
return new Task<Void>() {
@Override
public void execute() throws IOException, XMLStreamException {
List<String> gameVersions = getGameVersions(META_URL);
List<String> loaderVersions = getVersions(FABRIC_MAVEN_URL, FABRIC_PACKAGE_NAME, FABRIC_JAR_NAME);
lock.writeLock().lock();
try {
for (String gameVersion : gameVersions)
for (String loaderVersion : loaderVersions)
versions.put(gameVersion, new FabricRemoteVersion(gameVersion, loaderVersion, ""));
} finally {
lock.writeLock().unlock();
}
}
};
}
private static final String META_URL = "https://meta.fabricmc.net/v2/versions/game";
private static final String FABRIC_MAVEN_URL = "https://maven.fabricmc.net/";
private static final String FABRIC_PACKAGE_NAME = "net/fabricmc";
private static final String FABRIC_JAR_NAME = "fabric-loader";
private List<String> getVersions(String mavenServerURL, String packageName, String jarName) throws IOException, XMLStreamException {
List<String> versions = new ArrayList<>();
URL url = new URL(mavenServerURL + packageName + "/" + jarName + "/maven-metadata.xml");
XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(url.openStream());
while(reader.hasNext()) {
if (reader.next() == 1 && reader.getLocalName().equals("version")) {
String text = reader.getElementText();
versions.add(text);
}
}
reader.close();
Collections.reverse(versions);
return versions;
}
private List<String> getGameVersions(String metaUrl) throws IOException {
String json = NetworkUtils.doGet(NetworkUtils.toURL(metaUrl));
return JsonUtils.GSON.<ArrayList<GameVersion>>fromJson(json, new TypeToken<ArrayList<GameVersion>>() {
}.getType()).stream().map(GameVersion::getVersion).collect(Collectors.toList());
}
private static class GameVersion {
private final String version;
private final boolean stable;
public GameVersion() {
this("", false);
}
public GameVersion(String version, boolean stable) {
this.version = version;
this.stable = stable;
}
public String getVersion() {
return version;
}
public boolean isStable() {
return stable;
}
}
}

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.VersionMismatchException;
import org.jackhuang.hmcl.game.GameVersion;
import org.jackhuang.hmcl.game.Version;
@@ -80,8 +81,8 @@ public final class ForgeInstallTask extends Task<Version> {
public void postExecute() throws Exception {
Files.deleteIfExists(installer);
setResult(dependency.getResult()
.setPriority(10000)
.setId("net.minecraftforge")
.setPriority(30000)
.setId(LibraryAnalyzer.LibraryType.FORGE.getPatchId())
.setVersion(remote.getSelfVersion()));
}

View File

@@ -134,7 +134,7 @@ public class ForgeNewInstallTask extends Task<Version> {
@Override
public void execute() throws Exception {
if ("net.minecraft.launchwrapper.Launch".equals(version.getMainClass()))
if ("net.minecraft.launchwrapper.Launch".equals(version.resolve(dependencyManager.getGameRepository()).getMainClass()))
throw new OptiFineInstallTask.UnsupportedOptiFineInstallationException();
Path temp = Files.createTempDirectory("forge_installer");

View File

@@ -17,7 +17,10 @@
*/
package org.jackhuang.hmcl.download.forge;
import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.RemoteVersion;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.task.Task;
public class ForgeRemoteVersion extends RemoteVersion {
/**
@@ -30,4 +33,9 @@ public class ForgeRemoteVersion extends RemoteVersion {
public ForgeRemoteVersion(String gameVersion, String selfVersion, String url) {
super(gameVersion, selfVersion, url);
}
@Override
public Task<Version> getInstallTask(DefaultDependencyManager dependencyManager, Version baseVersion) {
return new ForgeInstallTask(dependencyManager, baseVersion, this);
}
}

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.game.Arguments;
import org.jackhuang.hmcl.game.LibrariesDownloadInfo;
import org.jackhuang.hmcl.game.Library;
@@ -68,9 +69,9 @@ public final class LiteLoaderInstallTask extends Task<Version> {
new LibrariesDownloadInfo(new LibraryDownloadInfo(null, remote.getUrl()))
);
setResult(new Version("com.mumfrey.liteloader",
setResult(new Version(LibraryAnalyzer.LibraryType.LITELOADER.getPatchId(),
remote.getSelfVersion(),
20000,
60000,
new Arguments().addGameArguments("--tweakClass", "com.mumfrey.liteloader.launch.LiteLoaderTweaker"),
"net.minecraft.launchwrapper.Launch",
Lang.merge(remote.getLibraries(), Collections.singleton(library)))

View File

@@ -17,8 +17,11 @@
*/
package org.jackhuang.hmcl.download.liteloader;
import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.RemoteVersion;
import org.jackhuang.hmcl.game.Library;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.task.Task;
import java.util.Collection;
@@ -47,4 +50,8 @@ public class LiteLoaderRemoteVersion extends RemoteVersion {
return tweakClass;
}
@Override
public Task<Version> getInstallTask(DefaultDependencyManager dependencyManager, Version baseVersion) {
return new LiteLoaderInstallTask(dependencyManager, baseVersion, this);
}
}

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.VersionMismatchException;
import org.jackhuang.hmcl.game.Arguments;
import org.jackhuang.hmcl.game.GameVersion;
@@ -97,7 +98,7 @@ public final class OptiFineInstallTask extends Task<Version> {
public void preExecute() throws Exception {
if (!Arrays.asList("net.minecraft.client.main.Main",
"net.minecraft.launchwrapper.Launch")
.contains(version.getMainClass()))
.contains(version.resolve(dependencyManager.getGameRepository()).getMainClass()))
throw new UnsupportedOptiFineInstallationException();
@@ -156,9 +157,9 @@ public final class OptiFineInstallTask extends Task<Version> {
}
setResult(new Version(
"net.optifine",
LibraryAnalyzer.LibraryType.OPTIFINE.getPatchId(),
remote.getSelfVersion(),
30000,
90000,
new Arguments().addGameArguments("--tweakClass", "optifine.OptiFineTweaker"),
"net.minecraft.launchwrapper.Launch",
libraries

View File

@@ -17,7 +17,10 @@
*/
package org.jackhuang.hmcl.download.optifine;
import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.RemoteVersion;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.task.Task;
import java.util.function.Supplier;
@@ -34,4 +37,9 @@ public class OptiFineRemoteVersion extends RemoteVersion {
public String getUrl() {
return url.get();
}
@Override
public Task<Version> getInstallTask(DefaultDependencyManager dependencyManager, Version baseVersion) {
return new OptiFineInstallTask(dependencyManager, baseVersion, this);
}
}

View File

@@ -65,17 +65,17 @@ public class Version implements Comparable<Version>, Validation {
private final ReleaseType type;
private final Date time;
private final Date releaseTime;
private final int minimumLauncherVersion;
private final Integer minimumLauncherVersion;
private final Boolean hidden;
private final List<Version> patches;
private transient final boolean resolved;
public Version(String id, String version, int priority, Arguments arguments, String mainClass, List<Library> libraries) {
this(false, id, version, priority, null, arguments, mainClass, null, null, null, null, libraries, null, null, null, null, null, null, 0, null, null);
this(false, id, version, priority, null, arguments, mainClass, null, null, null, null, libraries, 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<Library> libraries, List<CompatibilityRule> compatibilityRules, Map<DownloadType, DownloadInfo> downloads, Map<DownloadType, LoggingInfo> logging, ReleaseType type, Date time, Date releaseTime, int minimumLauncherVersion, Boolean hidden, List<Version> 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<Library> libraries, List<CompatibilityRule> compatibilityRules, Map<DownloadType, DownloadInfo> downloads, Map<DownloadType, LoggingInfo> logging, ReleaseType type, Date time, Date releaseTime, Integer minimumLauncherVersion, Boolean hidden, List<Version> patches) {
this.resolved = resolved;
this.id = id;
this.version = version;
@@ -150,7 +150,7 @@ public class Version implements Comparable<Version>, Validation {
}
public int getMinimumLauncherVersion() {
return minimumLauncherVersion;
return minimumLauncherVersion == null ? 0 : minimumLauncherVersion;
}
public boolean isHidden() {
@@ -222,7 +222,7 @@ public class Version implements Comparable<Version>, Validation {
type,
time,
releaseTime,
Math.max(minimumLauncherVersion, parent.minimumLauncherVersion),
Lang.merge(minimumLauncherVersion, parent.minimumLauncherVersion, Math::max),
hidden,
Lang.merge(parent.patches, patches));
}

View File

@@ -24,6 +24,7 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -95,6 +96,12 @@ public final class Lang {
return index < 0 || index >= a.size() ? defaultValue : a.get(index);
}
public static <T> T merge(T a, T b, BinaryOperator<T> operator) {
if (a == null) return b;
if (b == null) return a;
return operator.apply(a, b);
}
/**
* Join two collections into one list.
*