From 91682aeafa5bc5127aa8dfa79fde2676fc390410 Mon Sep 17 00:00:00 2001 From: huanghongxun Date: Thu, 20 Feb 2020 00:02:56 +0800 Subject: [PATCH] add: redownload corrupt files when game crashed --- .../hmcl/game/HMCLGameRepository.java | 15 ++++++++ .../jackhuang/hmcl/game/LauncherHelper.java | 34 ++++++++++++------- .../hmcl/ui/construct/TaskListPane.java | 12 +++---- .../jackhuang/hmcl/ui/versions/Versions.java | 2 +- .../download/DefaultDependencyManager.java | 11 +++--- .../hmcl/download/DependencyManager.java | 4 +-- .../download/fabric/FabricInstallTask.java | 2 +- .../download/forge/ForgeNewInstallTask.java | 13 ++----- .../download/forge/ForgeOldInstallTask.java | 8 ++--- .../download/game/GameAssetDownloadTask.java | 19 ++++++++--- .../hmcl/download/game/GameInstallTask.java | 4 +-- .../hmcl/download/game/GameLibrariesTask.java | 32 +++++++++++++---- .../liteloader/LiteLoaderInstallTask.java | 9 ++--- .../optifine/OptiFineInstallTask.java | 11 ++---- .../org/jackhuang/hmcl/game/AssetObject.java | 10 ++++++ .../org/jackhuang/hmcl/game/DownloadInfo.java | 12 +++++-- 16 files changed, 122 insertions(+), 76 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java index 166095bda..45be78ddd 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java @@ -28,6 +28,7 @@ import org.jackhuang.hmcl.util.io.FileUtils; import java.io.File; import java.io.IOException; +import java.nio.file.Files; import java.util.*; import java.util.logging.Level; @@ -221,6 +222,20 @@ public class HMCLGameRepository extends DefaultGameRepository { beingModpackVersions.remove(id); } + public void markVersionLaunchedAbnormally(String id) { + try { + Files.createFile(getVersionRoot(id).toPath().resolve(".abnormal")); + } catch (IOException ignored) { + } + } + + public boolean unmarkVersionLaunchedAbnormally(String id) { + File file = new File(getVersionRoot(id), ".abnormal"); + boolean result = file.isFile(); + file.delete(); + return result; + } + private static final Gson GSON = new GsonBuilder() .setPrettyPrinting() .create(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java index c68b823ba..2ecb2522e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java @@ -135,7 +135,7 @@ public final class LauncherHelper { if (setting.isNotCheckGame()) return null; else - return dependencyManager.checkGameCompletionAsync(version); + return dependencyManager.checkGameCompletionAsync(version, repository.unmarkVersionLaunchedAbnormally(selectedVersion)); }), Task.composeAsync(null, () -> { try { ModpackConfiguration configuration = ModpackHelper.readModpackConfiguration(repository.getModpackConfiguration(selectedVersion)); @@ -168,7 +168,7 @@ public final class LauncherHelper { setting.toLaunchOptions(profile.getGameDir(), !setting.isNotCheckJVM()), launcherVisibility == LauncherVisibility.CLOSE ? null // Unnecessary to start listening to game process output when close launcher immediately after game launched. - : new HMCLProcessListener(authInfo, gameVersion.isPresent()) + : new HMCLProcessListener(repository, selectedVersion, authInfo, gameVersion.isPresent()) ); }).thenComposeAsync(launcher -> { // launcher is prev task's result if (scriptFile == null) { @@ -209,12 +209,12 @@ public final class LauncherHelper { @Override public void onStop(boolean success, TaskExecutor executor) { - if (!success && !Controllers.isStopped()) { - Platform.runLater(() -> { - // Check if the application has stopped - // because onStop will be invoked if tasks fail when the executor service shut down. - if (!Controllers.isStopped()) { - launchingStepsPane.fireEvent(new DialogCloseEvent()); + Platform.runLater(() -> { + // Check if the application has stopped + // because onStop will be invoked if tasks fail when the executor service shut down. + if (!Controllers.isStopped()) { + launchingStepsPane.fireEvent(new DialogCloseEvent()); + if (!success) { Exception ex = executor.getException(); if (ex != null) { String message; @@ -264,9 +264,9 @@ public final class LauncherHelper { MessageType.ERROR); } } - }); - } - launchingStepsPane.setExecutor(null); + } + launchingStepsPane.setExecutor(null); + }); } }); @@ -444,6 +444,8 @@ public final class LauncherHelper { */ class HMCLProcessListener implements ProcessListener { + private final HMCLGameRepository repository; + private final String version; private final Map forbiddenTokens; private ManagedProcess process; private boolean lwjgl; @@ -452,7 +454,9 @@ public final class LauncherHelper { private final LinkedList> logs; private final CountDownLatch latch = new CountDownLatch(1); - public HMCLProcessListener(AuthInfo authInfo, boolean detectWindow) { + public HMCLProcessListener(HMCLGameRepository repository, String version, AuthInfo authInfo, boolean detectWindow) { + this.repository = repository; + this.version = version; this.detectWindow = detectWindow; if (authInfo == null) @@ -559,6 +563,12 @@ public final class LauncherHelper { // Game crashed before opening the game window. if (!lwjgl) finishLaunch(); + launchingLatch.countDown(); + + if (exitType != ExitType.NORMAL) { + repository.markVersionLaunchedAbnormally(version); + } + if (exitType != ExitType.NORMAL && logWindow == null) Platform.runLater(() -> { logWindow = new LogWindow(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java index e489dd758..4e6ba665b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java @@ -132,9 +132,9 @@ public final class TaskListPane extends StackPane { task.setName(i18n("modpack.scan")); } - ProgressListNode node = new ProgressListNode(task); - nodes.put(task, node); Platform.runLater(() -> { + ProgressListNode node = new ProgressListNode(task); + nodes.put(task, node); StageNode stageNode = stageNodes.stream().filter(x -> x.stage.equals(task.getStage())).findAny().orElse(null); listBox.add(listBox.indexOf(stageNode) + 1, node); }); @@ -148,11 +148,11 @@ public final class TaskListPane extends StackPane { }); } - ProgressListNode node = nodes.remove(task); - if (node == null) - return; - node.unbind(); Platform.runLater(() -> { + ProgressListNode node = nodes.remove(task); + if (node == null) + return; + node.unbind(); listBox.remove(node); }); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java index 0c0794612..4e3e1f283 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java @@ -76,7 +76,7 @@ public class Versions { } public static void updateGameAssets(Profile profile, String version) { - TaskExecutor executor = new GameAssetDownloadTask(profile.getDependency(), profile.getRepository().getVersion(version), GameAssetDownloadTask.DOWNLOAD_INDEX_FORCIBLY) + TaskExecutor executor = new GameAssetDownloadTask(profile.getDependency(), profile.getRepository().getVersion(version), GameAssetDownloadTask.DOWNLOAD_INDEX_FORCIBLY, true) .executor(); Controllers.taskDialog(executor, i18n("version.manage.redownload_assets_index")); executor.start(); 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 6a453a81f..d5fe5012d 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java @@ -25,7 +25,6 @@ import org.jackhuang.hmcl.download.optifine.OptiFineInstallTask; import org.jackhuang.hmcl.game.DefaultGameRepository; import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.util.function.ExceptionalFunction; import java.io.IOException; import java.nio.file.Path; @@ -76,7 +75,7 @@ public class DefaultDependencyManager extends AbstractDependencyManager { } @Override - public Task checkGameCompletionAsync(Version original) { + public Task checkGameCompletionAsync(Version original, boolean integrityCheck) { Version version = original.resolve(repository); return Task.allOf( Task.composeAsync(() -> { @@ -85,14 +84,14 @@ public class DefaultDependencyManager extends AbstractDependencyManager { else return null; }), - new GameAssetDownloadTask(this, version, GameAssetDownloadTask.DOWNLOAD_INDEX_IF_NECESSARY), - new GameLibrariesTask(this, version) + new GameAssetDownloadTask(this, version, GameAssetDownloadTask.DOWNLOAD_INDEX_IF_NECESSARY, integrityCheck), + new GameLibrariesTask(this, version, integrityCheck) ); } @Override - public Task checkLibraryCompletionAsync(Version version) { - return new GameLibrariesTask(this, version, version.getLibraries()); + public Task checkLibraryCompletionAsync(Version version, boolean integrityCheck) { + return new GameLibrariesTask(this, version, integrityCheck, version.getLibraries()); } @Override diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DependencyManager.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DependencyManager.java index 9e7c3288e..5c89edd3c 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DependencyManager.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DependencyManager.java @@ -46,7 +46,7 @@ public interface DependencyManager { * * @return the task to check game completion. */ - Task checkGameCompletionAsync(Version version); + Task checkGameCompletionAsync(Version version, boolean integrityCheck); /** * Check if the game is complete. @@ -54,7 +54,7 @@ public interface DependencyManager { * * @return the task to check game completion. */ - Task checkLibraryCompletionAsync(Version version); + Task checkLibraryCompletionAsync(Version version, boolean integrityCheck); /** * The builder to build a brand new game then libraries such as Forge, LiteLoader and OptiFine. 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 c30431c75..e62a9d9ff 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 @@ -84,7 +84,7 @@ public final class FabricInstallTask extends Task { public void execute() { setResult(getPatch(JsonUtils.GSON.fromJson(launchMetaTask.getResult(), FabricInfo.class), remote.getGameVersion(), remote.getSelfVersion())); - dependencies.add(dependencyManager.checkLibraryCompletionAsync(getResult())); + dependencies.add(dependencyManager.checkLibraryCompletionAsync(getResult(), true)); } private static String getLaunchMetaUrl(String gameVersion, String loaderVersion) { 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 428397f5a..7ce18dc92 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 @@ -45,14 +45,7 @@ import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.zip.ZipException; @@ -133,7 +126,7 @@ public class ForgeNewInstallTask extends Task { } } - dependents.add(new GameLibrariesTask(dependencyManager, version, profile.getLibraries())); + dependents.add(new GameLibrariesTask(dependencyManager, version, true, profile.getLibraries())); } @Override @@ -273,7 +266,7 @@ public class ForgeNewInstallTask extends Task { .setPriority(30000) .setId(LibraryAnalyzer.LibraryType.FORGE.getPatchId()) .setVersion(selfVersion)); - dependencies.add(dependencyManager.checkLibraryCompletionAsync(forgeVersion)); + dependencies.add(dependencyManager.checkLibraryCompletionAsync(forgeVersion, true)); FileUtils.deleteDirectory(temp.toFile()); } 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 d0b37ee89..d7eefd85a 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 @@ -27,11 +27,7 @@ import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.IOUtils; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import java.io.*; import java.nio.file.Path; import java.util.LinkedList; import java.util.List; @@ -90,7 +86,7 @@ public class ForgeOldInstallTask extends Task { .setPriority(30000) .setId(LibraryAnalyzer.LibraryType.FORGE.getPatchId()) .setVersion(selfVersion)); - dependencies.add(dependencyManager.checkLibraryCompletionAsync(installProfile.getVersionInfo())); + dependencies.add(dependencyManager.checkLibraryCompletionAsync(installProfile.getVersionInfo(), true)); } catch (ZipException ex) { throw new ArtifactMalformedException("Malformed forge installer file", ex); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetDownloadTask.java index 65946da19..37ebb4dd5 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetDownloadTask.java @@ -27,6 +27,7 @@ import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.CacheRepository; +import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.NetworkUtils; @@ -37,6 +38,7 @@ import java.net.URL; import java.util.Collection; import java.util.LinkedList; import java.util.List; +import java.util.logging.Level; import java.util.stream.Collectors; /** @@ -49,6 +51,7 @@ public final class GameAssetDownloadTask extends Task { private final Version version; private final AssetIndexInfo assetIndexInfo; private final File assetIndexFile; + private final boolean integrityCheck; private final List> dependents = new LinkedList<>(); private final List> dependencies = new LinkedList<>(); @@ -58,11 +61,12 @@ public final class GameAssetDownloadTask extends Task { * @param dependencyManager the dependency manager that can provides {@link org.jackhuang.hmcl.game.GameRepository} * @param version the game version */ - public GameAssetDownloadTask(AbstractDependencyManager dependencyManager, Version version, boolean forceDownloadingIndex) { + public GameAssetDownloadTask(AbstractDependencyManager dependencyManager, Version version, boolean forceDownloadingIndex, boolean integrityCheck) { this.dependencyManager = dependencyManager; this.version = version.resolve(dependencyManager.getGameRepository()); this.assetIndexInfo = this.version.getAssetIndex(); this.assetIndexFile = dependencyManager.getGameRepository().getIndexFile(version.getId(), assetIndexInfo.getId()); + this.integrityCheck = integrityCheck; if (!assetIndexFile.exists() || forceDownloadingIndex) { dependents.add(new GameAssetIndexDownloadTask(dependencyManager, this.version)); @@ -101,9 +105,14 @@ public final class GameAssetDownloadTask extends Task { throw new InterruptedException(); File file = dependencyManager.getGameRepository().getAssetObject(version.getId(), assetIndexInfo.getId(), assetObject); - if (file.isFile()) - dependencyManager.getCacheRepository().tryCacheFile(file.toPath(), CacheRepository.SHA1, assetObject.getHash()); - else { + boolean download = !file.isFile(); + try { + if (!download && integrityCheck && !assetObject.validateChecksum(file.toPath(), true)) + download = true; + } catch (IOException e) { + Logging.LOG.log(Level.WARNING, "Unable to calc hash value of file " + file.toPath(), e); + } + if (download) { List urls = dependencyManager.getPreferredDownloadProviders().stream() .map(downloadProvider -> downloadProvider.getAssetBaseURL() + assetObject.getLocation()) .map(NetworkUtils::toURL) @@ -116,6 +125,8 @@ public final class GameAssetDownloadTask extends Task { .setCaching(true) .setCandidate(dependencyManager.getCacheRepository().getCommonDirectory() .resolve("assets").resolve("objects").resolve(assetObject.getLocation()))); + } else { + dependencyManager.getCacheRepository().tryCacheFile(file.toPath(), CacheRepository.SHA1, assetObject.getHash()); } updateProgress(++progress, index.getObjects().size()); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameInstallTask.java index 8bada4526..703303e4a 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameInstallTask.java @@ -71,8 +71,8 @@ public class GameInstallTask extends Task { 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) + new GameAssetDownloadTask(dependencyManager, version, GameAssetDownloadTask.DOWNLOAD_INDEX_FORCIBLY, true), + new GameLibrariesTask(dependencyManager, version, true) ).withStage("hmcl.install.assets").withComposeAsync(gameRepository.save(version)))); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameLibrariesTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameLibrariesTask.java index 773c0dadb..8675d1c53 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameLibrariesTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameLibrariesTask.java @@ -21,10 +21,14 @@ import org.jackhuang.hmcl.download.AbstractDependencyManager; import org.jackhuang.hmcl.game.Library; import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.util.Logging; import java.io.File; +import java.io.IOException; +import java.nio.file.Path; import java.util.LinkedList; import java.util.List; +import java.util.logging.Level; /** * This task is to download game libraries. @@ -36,6 +40,7 @@ public final class GameLibrariesTask extends Task { private final AbstractDependencyManager dependencyManager; private final Version version; + private final boolean integrityCheck; private final List libraries; private final List> dependencies = new LinkedList<>(); @@ -43,21 +48,22 @@ public final class GameLibrariesTask extends Task { * Constructor. * * @param dependencyManager the dependency manager that can provides {@link org.jackhuang.hmcl.game.GameRepository} - * @param version the game version + * @param version the game version */ - public GameLibrariesTask(AbstractDependencyManager dependencyManager, Version version) { - this(dependencyManager, version, version.resolve(dependencyManager.getGameRepository()).getLibraries()); + public GameLibrariesTask(AbstractDependencyManager dependencyManager, Version version, boolean integrityCheck) { + this(dependencyManager, version, integrityCheck, version.resolve(dependencyManager.getGameRepository()).getLibraries()); } /** * Constructor. * * @param dependencyManager the dependency manager that can provides {@link org.jackhuang.hmcl.game.GameRepository} - * @param version the game version + * @param version the game version */ - public GameLibrariesTask(AbstractDependencyManager dependencyManager, Version version, List libraries) { + public GameLibrariesTask(AbstractDependencyManager dependencyManager, Version version, boolean integrityCheck, List libraries) { this.dependencyManager = dependencyManager; this.version = version; + this.integrityCheck = integrityCheck; this.libraries = libraries; setSignificance(TaskSignificance.MODERATE); @@ -72,10 +78,22 @@ public final class GameLibrariesTask extends Task { public void execute() { libraries.stream().filter(Library::appliesToCurrentEnvironment).forEach(library -> { File file = dependencyManager.getGameRepository().getLibraryFile(version, library); - if (!file.exists()) + Path jar = file.toPath(); + boolean download = !file.isFile(); + try { + if (!download && integrityCheck && !library.getDownload().validateChecksum(jar, true)) download = true; + if (!download && integrityCheck && + library.getChecksums() != null && !library.getChecksums().isEmpty() && + !LibraryDownloadTask.checksumValid(jar.toFile(), library.getChecksums())) download = true; + } catch (IOException e) { + Logging.LOG.log(Level.WARNING, "Unable to calc hash value of file " + jar, e); + } + + if (download) { dependencies.add(new LibraryDownloadTask(dependencyManager, file, library)); - else + } else { dependencyManager.getCacheRepository().tryCacheLibrary(library, file.toPath()); + } }); } 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 bdddb1cec..1c6cac1b2 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 @@ -19,12 +19,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; -import org.jackhuang.hmcl.game.Version; +import org.jackhuang.hmcl.game.*; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.Lang; @@ -79,7 +74,7 @@ public final class LiteLoaderInstallTask extends Task { .setLogging(Collections.emptyMap()) // Mods may log in malformed format, causing XML parser to crash. So we suppress using official log4j configuration ); - dependencies.add(dependencyManager.checkLibraryCompletionAsync(getResult())); + dependencies.add(dependencyManager.checkLibraryCompletionAsync(getResult(), true)); } } 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 bffde4ff5..f5a964003 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 @@ -20,14 +20,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.Artifact; -import org.jackhuang.hmcl.game.DefaultGameRepository; -import org.jackhuang.hmcl.game.GameVersion; -import org.jackhuang.hmcl.game.LibrariesDownloadInfo; -import org.jackhuang.hmcl.game.Library; -import org.jackhuang.hmcl.game.LibraryDownloadInfo; -import org.jackhuang.hmcl.game.Version; +import org.jackhuang.hmcl.game.*; import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.io.CompressingUtils; @@ -184,7 +177,7 @@ public final class OptiFineInstallTask extends Task { libraries )); - dependencies.add(dependencyManager.checkLibraryCompletionAsync(getResult())); + dependencies.add(dependencyManager.checkLibraryCompletionAsync(getResult(), true)); } public static class UnsupportedOptiFineInstallationException extends Exception { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/AssetObject.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/AssetObject.java index 66a5fbe8e..fb5207641 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/AssetObject.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/AssetObject.java @@ -18,9 +18,14 @@ package org.jackhuang.hmcl.game; import com.google.gson.JsonParseException; +import org.jackhuang.hmcl.util.DigestUtils; +import org.jackhuang.hmcl.util.Hex; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.gson.Validation; +import java.io.IOException; +import java.nio.file.Path; + /** * * @author huangyuhui @@ -56,4 +61,9 @@ public final class AssetObject implements Validation { if (StringUtils.isBlank(hash) || hash.length() < 2) throw new JsonParseException("AssetObject hash cannot be blank."); } + + public boolean validateChecksum(Path file, boolean defaultValue) throws IOException { + if (hash == null) return defaultValue; + return Hex.encodeHex(DigestUtils.digest("SHA-1", file)).equalsIgnoreCase(hash); + } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/DownloadInfo.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/DownloadInfo.java index 2c398039e..5164ec836 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/DownloadInfo.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/DownloadInfo.java @@ -19,12 +19,13 @@ package org.jackhuang.hmcl.game; import com.google.gson.JsonParseException; import com.google.gson.annotations.SerializedName; -import org.jackhuang.hmcl.util.Immutable; -import org.jackhuang.hmcl.util.StringUtils; -import org.jackhuang.hmcl.util.ToStringBuilder; +import org.jackhuang.hmcl.util.*; import org.jackhuang.hmcl.util.gson.TolerableValidationException; import org.jackhuang.hmcl.util.gson.Validation; +import java.io.IOException; +import java.nio.file.Path; + /** * * @author huangyuhui @@ -79,4 +80,9 @@ public class DownloadInfo implements Validation { if (StringUtils.isBlank(url)) throw new TolerableValidationException(); } + + public boolean validateChecksum(Path file, boolean defaultValue) throws IOException { + if (getSha1() == null) return defaultValue; + return Hex.encodeHex(DigestUtils.digest("SHA-1", file)).equalsIgnoreCase(getSha1()); + } }