mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-16 07:16:27 -04:00
Support changing game version
This commit is contained in:
parent
a2ac3c1f18
commit
11e66ac13c
@ -26,11 +26,14 @@ import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import org.jackhuang.hmcl.download.forge.ForgeInstallTask;
|
||||
import org.jackhuang.hmcl.download.game.GameAssetDownloadTask;
|
||||
import org.jackhuang.hmcl.download.game.GameInstallTask;
|
||||
import org.jackhuang.hmcl.download.liteloader.LiteLoaderInstallTask;
|
||||
import org.jackhuang.hmcl.download.optifine.OptiFineInstallTask;
|
||||
import org.jackhuang.hmcl.game.HMCLModpackExportTask;
|
||||
import org.jackhuang.hmcl.game.HMCLModpackInstallTask;
|
||||
import org.jackhuang.hmcl.mod.*;
|
||||
import org.jackhuang.hmcl.mod.MinecraftInstanceTask;
|
||||
import org.jackhuang.hmcl.mod.ModpackInstallTask;
|
||||
import org.jackhuang.hmcl.mod.ModpackUpdateTask;
|
||||
import org.jackhuang.hmcl.mod.curse.CurseCompletionTask;
|
||||
import org.jackhuang.hmcl.mod.curse.CurseInstallTask;
|
||||
import org.jackhuang.hmcl.mod.multimc.MultiMCModpackInstallTask;
|
||||
@ -86,6 +89,8 @@ public final class TaskListPane extends StackPane {
|
||||
|
||||
if (task instanceof GameAssetDownloadTask) {
|
||||
task.setName(i18n("assets.download_all"));
|
||||
} else if (task instanceof GameInstallTask) {
|
||||
task.setName(i18n("install.installer.install", i18n("install.installer.game")));
|
||||
} else if (task instanceof ForgeInstallTask) {
|
||||
task.setName(i18n("install.installer.install", i18n("install.installer.forge")));
|
||||
} else if (task instanceof LiteLoaderInstallTask) {
|
||||
|
@ -34,6 +34,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.MINECRAFT;
|
||||
import static org.jackhuang.hmcl.util.Lang.handleUncaught;
|
||||
import static org.jackhuang.hmcl.util.Lang.threadPool;
|
||||
import static org.jackhuang.hmcl.util.StringUtils.removePrefix;
|
||||
@ -60,6 +61,7 @@ public class GameItem extends Control {
|
||||
StringBuilder libraries = new StringBuilder(game);
|
||||
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(profile.getRepository().getResolvedPreservingPatchesVersion(id));
|
||||
analyzer.forEachLibrary((libraryId, libraryVersion) -> {
|
||||
if (libraryId.equals(MINECRAFT.getPatchId())) return;
|
||||
if (I18n.hasKey("install.installer." + libraryId)) {
|
||||
libraries.append(", ").append(i18n("install.installer." + libraryId));
|
||||
if (libraryVersion != null)
|
||||
|
@ -88,13 +88,14 @@ public class InstallerListPage extends ListPageBase<InstallerItem> {
|
||||
itemsProperty().clear();
|
||||
analyzer.forEachLibrary((libraryId, libraryVersion) -> {
|
||||
String title = I18n.hasKey("install.installer." + libraryId) ? i18n("install.installer." + libraryId) : libraryId;
|
||||
if (Lang.test(() -> profile.getDependency().getVersionList(libraryId)))
|
||||
Consumer<InstallerItem> action = "game".equals(libraryId) ? null : removeAction.apply(libraryId);
|
||||
if (libraryVersion != null && Lang.test(() -> profile.getDependency().getVersionList(libraryId)))
|
||||
itemsProperty().add(
|
||||
new InstallerItem(title, libraryVersion, () -> {
|
||||
Controllers.getDecorator().startWizard(new UpdateInstallerWizardProvider(profile, gameVersion, version, libraryId, libraryVersion));
|
||||
}, removeAction.apply(libraryId)));
|
||||
new InstallerItem(title, libraryVersion, () -> {
|
||||
Controllers.getDecorator().startWizard(new UpdateInstallerWizardProvider(profile, gameVersion, version, libraryId, libraryVersion));
|
||||
}, action));
|
||||
else
|
||||
itemsProperty().add(new InstallerItem(title, libraryVersion, null, removeAction.apply(libraryId)));
|
||||
itemsProperty().add(new InstallerItem(title, libraryVersion, null, action));
|
||||
});
|
||||
}).start();
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ import javafx.stage.FileChooser;
|
||||
import org.jackhuang.hmcl.download.game.GameAssetDownloadTask;
|
||||
import org.jackhuang.hmcl.game.GameRepository;
|
||||
import org.jackhuang.hmcl.game.LauncherHelper;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.setting.Accounts;
|
||||
import org.jackhuang.hmcl.setting.EnumGameDirectory;
|
||||
import org.jackhuang.hmcl.setting.Profile;
|
||||
@ -77,8 +76,7 @@ public class Versions {
|
||||
}
|
||||
|
||||
public static void updateGameAssets(Profile profile, String version) {
|
||||
Version resolvedVersion = profile.getRepository().getResolvedVersion(version);
|
||||
TaskExecutor executor = new GameAssetDownloadTask(profile.getDependency(), resolvedVersion, GameAssetDownloadTask.DOWNLOAD_INDEX_FORCIBLY)
|
||||
TaskExecutor executor = new GameAssetDownloadTask(profile.getDependency(), profile.getRepository().getVersion(version), GameAssetDownloadTask.DOWNLOAD_INDEX_FORCIBLY)
|
||||
.executor();
|
||||
Controllers.taskDialog(executor, i18n("version.manage.redownload_assets_index"));
|
||||
executor.start();
|
||||
|
@ -68,7 +68,8 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task<?> checkGameCompletionAsync(Version version) {
|
||||
public Task<?> checkGameCompletionAsync(Version original) {
|
||||
Version version = original.resolve(repository);
|
||||
return Task.allOf(
|
||||
Task.composeAsync(() -> {
|
||||
if (!repository.getVersionJar(version).exists())
|
||||
|
@ -17,14 +17,9 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.download;
|
||||
|
||||
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.game.VersionJsonDownloadTask;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.function.ExceptionalFunction;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ -52,24 +47,16 @@ public class DefaultGameBuilder extends GameBuilder {
|
||||
|
||||
@Override
|
||||
public Task<?> buildAsync() {
|
||||
return new VersionJsonDownloadTask(gameVersion, dependencyManager).thenComposeAsync(rawJson -> {
|
||||
Version original = JsonUtils.GSON.fromJson(rawJson, Version.class);
|
||||
Version version = original.setId(name).setJar(null);
|
||||
Task<?> vanillaTask = downloadGameAsync(gameVersion, version).thenComposeAsync(Task.allOf(
|
||||
new GameAssetDownloadTask(dependencyManager, version, GameAssetDownloadTask.DOWNLOAD_INDEX_FORCIBLY),
|
||||
new GameLibrariesTask(dependencyManager, version) // Game libraries will be downloaded for multiple times partly, this time is for vanilla libraries.
|
||||
).withComposeAsync(dependencyManager.getGameRepository().save(version))); // using [with] because download failure here are tolerant.
|
||||
Task<Version> libraryTask = Task.supplyAsync(() -> new Version(name));
|
||||
libraryTask = libraryTask.thenComposeAsync(libraryTaskHelper(gameVersion, "game", gameVersion));
|
||||
|
||||
Task<Version> libraryTask = vanillaTask.thenSupplyAsync(() -> version);
|
||||
for (Map.Entry<String, String> entry : toolVersions.entrySet())
|
||||
libraryTask = libraryTask.thenComposeAsync(libraryTaskHelper(gameVersion, entry.getKey(), entry.getValue()));
|
||||
|
||||
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));
|
||||
|
||||
for (RemoteVersion remoteVersion : remoteVersions)
|
||||
libraryTask = libraryTask.thenComposeAsync(dependencyManager.installLibraryAsync(remoteVersion));
|
||||
|
||||
return libraryTask;
|
||||
}).whenComplete(exception -> {
|
||||
return libraryTask.whenComplete(exception -> {
|
||||
if (exception != null)
|
||||
dependencyManager.getGameRepository().removeVersionFromDisk(name);
|
||||
});
|
||||
@ -78,9 +65,4 @@ public class DefaultGameBuilder extends GameBuilder {
|
||||
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) {
|
||||
return new GameDownloadTask(dependencyManager, gameVersion, version);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -56,7 +56,9 @@ public class MaintainTask extends Task<Version> {
|
||||
if (version.getInheritsFrom() != null)
|
||||
throw new IllegalArgumentException("MaintainTask requires independent game version");
|
||||
|
||||
if (version.resolve(null).getMainClass().contains("launchwrapper")) {
|
||||
String mainClass = version.resolve(null).getMainClass();
|
||||
|
||||
if (mainClass != null && mainClass.contains("launchwrapper")) {
|
||||
return maintainOptiFineLibrary(repository, maintainGameWithLaunchWrapper(unique(version)));
|
||||
} else {
|
||||
// Vanilla Minecraft does not need maintain
|
||||
|
@ -51,16 +51,16 @@ public final class GameAssetDownloadTask extends Task<Void> {
|
||||
* Constructor.
|
||||
*
|
||||
* @param dependencyManager the dependency manager that can provides {@link org.jackhuang.hmcl.game.GameRepository}
|
||||
* @param version the <b>resolved</b> version
|
||||
* @param version the game version
|
||||
*/
|
||||
public GameAssetDownloadTask(AbstractDependencyManager dependencyManager, Version version, boolean forceDownloadingIndex) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.version = version;
|
||||
this.assetIndexInfo = version.getAssetIndex();
|
||||
this.version = version.resolve(dependencyManager.getGameRepository());
|
||||
this.assetIndexInfo = this.version.getAssetIndex();
|
||||
this.assetIndexFile = dependencyManager.getGameRepository().getIndexFile(version.getId(), assetIndexInfo.getId());
|
||||
|
||||
if (!assetIndexFile.exists() || forceDownloadingIndex)
|
||||
dependents.add(new GameAssetIndexDownloadTask(dependencyManager, version));
|
||||
dependents.add(new GameAssetIndexDownloadTask(dependencyManager, this.version));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -43,7 +43,7 @@ public final class GameDownloadTask extends Task<Void> {
|
||||
public GameDownloadTask(DefaultDependencyManager dependencyManager, String gameVersion, Version version) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.gameVersion = gameVersion;
|
||||
this.version = version;
|
||||
this.version = version.resolve(dependencyManager.getGameRepository());
|
||||
|
||||
setSignificance(TaskSignificance.MODERATE);
|
||||
}
|
||||
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.game;
|
||||
|
||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.game.DefaultGameRepository;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.MINECRAFT;
|
||||
|
||||
public class GameInstallTask extends Task<Version> {
|
||||
|
||||
private final DefaultGameRepository gameRepository;
|
||||
private final DefaultDependencyManager dependencyManager;
|
||||
private final Version version;
|
||||
private final GameRemoteVersion remote;
|
||||
private final VersionJsonDownloadTask downloadTask;
|
||||
private final List<Task<?>> dependencies = new LinkedList<>();
|
||||
|
||||
public GameInstallTask(DefaultDependencyManager dependencyManager, Version version, GameRemoteVersion remoteVersion) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.gameRepository = dependencyManager.getGameRepository();
|
||||
this.version = version;
|
||||
this.remote = remoteVersion;
|
||||
this.downloadTask = new VersionJsonDownloadTask(remoteVersion.getGameVersion(), dependencyManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task<?>> getDependents() {
|
||||
return Collections.singleton(downloadTask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task<?>> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRelyingOnDependencies() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
Version patch = JsonUtils.GSON.fromJson(downloadTask.getResult(), Version.class)
|
||||
.setId(MINECRAFT.getPatchId()).setVersion(remote.getGameVersion()).setJar(null).setPriority(0);
|
||||
setResult(patch);
|
||||
|
||||
Version version = new Version(this.version.getId()).addPatch(patch);
|
||||
dependencies.add(new GameDownloadTask(dependencyManager, remote.getGameVersion(), version)
|
||||
.thenComposeAsync(Task.allOf(
|
||||
new GameAssetDownloadTask(dependencyManager, version, GameAssetDownloadTask.DOWNLOAD_INDEX_FORCIBLY),
|
||||
new GameLibrariesTask(dependencyManager, version)
|
||||
).withComposeAsync(gameRepository.save(version))));
|
||||
}
|
||||
|
||||
}
|
@ -43,17 +43,17 @@ public final class GameLibrariesTask extends Task<Void> {
|
||||
* Constructor.
|
||||
*
|
||||
* @param dependencyManager the dependency manager that can provides {@link org.jackhuang.hmcl.game.GameRepository}
|
||||
* @param version the <b>resolved</b> version
|
||||
* @param version the game version
|
||||
*/
|
||||
public GameLibrariesTask(AbstractDependencyManager dependencyManager, Version version) {
|
||||
this(dependencyManager, version, version.getLibraries());
|
||||
this(dependencyManager, version, version.resolve(dependencyManager.getGameRepository()).getLibraries());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param dependencyManager the dependency manager that can provides {@link org.jackhuang.hmcl.game.GameRepository}
|
||||
* @param version the <b>resolved</b> version
|
||||
* @param version the game version
|
||||
*/
|
||||
public GameLibrariesTask(AbstractDependencyManager dependencyManager, Version version, List<Library> libraries) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
|
@ -17,8 +17,11 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.game;
|
||||
|
||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||
import org.jackhuang.hmcl.game.ReleaseType;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
import java.util.Date;
|
||||
@ -47,6 +50,11 @@ public final class GameRemoteVersion extends RemoteVersion {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task<Version> getInstallTask(DefaultDependencyManager dependencyManager, Version baseVersion) {
|
||||
return new GameInstallTask(dependencyManager, baseVersion, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(RemoteVersion o) {
|
||||
if (!(o instanceof GameRemoteVersion))
|
||||
|
@ -21,7 +21,6 @@ import org.jackhuang.hmcl.download.DownloadProvider;
|
||||
import org.jackhuang.hmcl.download.VersionList;
|
||||
import org.jackhuang.hmcl.task.GetTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.NetworkUtils;
|
||||
|
||||
@ -48,7 +47,7 @@ public final class GameVersionList extends VersionList<GameRemoteVersion> {
|
||||
protected Collection<GameRemoteVersion> getVersionsImpl(String gameVersion) {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
return StringUtils.isBlank(gameVersion) ? versions.values() : versions.get(gameVersion);
|
||||
return versions.values();
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ public final class VersionJsonDownloadTask extends Task<String> {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
RemoteVersion remoteVersion = gameVersionList.getVersions(gameVersion).stream().findFirst()
|
||||
RemoteVersion remoteVersion = gameVersionList.getVersion(gameVersion, gameVersion)
|
||||
.orElseThrow(() -> new IllegalStateException("Cannot find specific version " + gameVersion + " in remote repository"));
|
||||
String jsonURL = dependencyManager.getDownloadProvider().injectURL(remoteVersion.getUrl());
|
||||
dependencies.add(new GetTask(NetworkUtils.toURL(jsonURL)).storeTo(this::setResult));
|
||||
|
@ -160,7 +160,7 @@ public class DefaultGameRepository implements GameRepository {
|
||||
}
|
||||
|
||||
if (fromVersion.getId().equals(fromVersion.getJar()))
|
||||
fromVersion = fromVersion.setJar(to);
|
||||
fromVersion = fromVersion.setJar(null);
|
||||
FileUtils.writeText(toJson, JsonUtils.GSON.toJson(fromVersion.setId(to)));
|
||||
return true;
|
||||
} catch (IOException | JsonParseException | VersionNotFoundException e) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user