add: redownload corrupt files when game crashed
This commit is contained in:
@@ -28,6 +28,7 @@ import org.jackhuang.hmcl.util.io.FileUtils;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
@@ -221,6 +222,20 @@ public class HMCLGameRepository extends DefaultGameRepository {
|
|||||||
beingModpackVersions.remove(id);
|
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()
|
private static final Gson GSON = new GsonBuilder()
|
||||||
.setPrettyPrinting()
|
.setPrettyPrinting()
|
||||||
.create();
|
.create();
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ public final class LauncherHelper {
|
|||||||
if (setting.isNotCheckGame())
|
if (setting.isNotCheckGame())
|
||||||
return null;
|
return null;
|
||||||
else
|
else
|
||||||
return dependencyManager.checkGameCompletionAsync(version);
|
return dependencyManager.checkGameCompletionAsync(version, repository.unmarkVersionLaunchedAbnormally(selectedVersion));
|
||||||
}), Task.composeAsync(null, () -> {
|
}), Task.composeAsync(null, () -> {
|
||||||
try {
|
try {
|
||||||
ModpackConfiguration<?> configuration = ModpackHelper.readModpackConfiguration(repository.getModpackConfiguration(selectedVersion));
|
ModpackConfiguration<?> configuration = ModpackHelper.readModpackConfiguration(repository.getModpackConfiguration(selectedVersion));
|
||||||
@@ -168,7 +168,7 @@ public final class LauncherHelper {
|
|||||||
setting.toLaunchOptions(profile.getGameDir(), !setting.isNotCheckJVM()),
|
setting.toLaunchOptions(profile.getGameDir(), !setting.isNotCheckJVM()),
|
||||||
launcherVisibility == LauncherVisibility.CLOSE
|
launcherVisibility == LauncherVisibility.CLOSE
|
||||||
? null // Unnecessary to start listening to game process output when close launcher immediately after game launched.
|
? 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
|
}).thenComposeAsync(launcher -> { // launcher is prev task's result
|
||||||
if (scriptFile == null) {
|
if (scriptFile == null) {
|
||||||
@@ -209,12 +209,12 @@ public final class LauncherHelper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop(boolean success, TaskExecutor executor) {
|
public void onStop(boolean success, TaskExecutor executor) {
|
||||||
if (!success && !Controllers.isStopped()) {
|
Platform.runLater(() -> {
|
||||||
Platform.runLater(() -> {
|
// Check if the application has stopped
|
||||||
// Check if the application has stopped
|
// because onStop will be invoked if tasks fail when the executor service shut down.
|
||||||
// because onStop will be invoked if tasks fail when the executor service shut down.
|
if (!Controllers.isStopped()) {
|
||||||
if (!Controllers.isStopped()) {
|
launchingStepsPane.fireEvent(new DialogCloseEvent());
|
||||||
launchingStepsPane.fireEvent(new DialogCloseEvent());
|
if (!success) {
|
||||||
Exception ex = executor.getException();
|
Exception ex = executor.getException();
|
||||||
if (ex != null) {
|
if (ex != null) {
|
||||||
String message;
|
String message;
|
||||||
@@ -264,9 +264,9 @@ public final class LauncherHelper {
|
|||||||
MessageType.ERROR);
|
MessageType.ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
launchingStepsPane.setExecutor(null);
|
||||||
launchingStepsPane.setExecutor(null);
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -444,6 +444,8 @@ public final class LauncherHelper {
|
|||||||
*/
|
*/
|
||||||
class HMCLProcessListener implements ProcessListener {
|
class HMCLProcessListener implements ProcessListener {
|
||||||
|
|
||||||
|
private final HMCLGameRepository repository;
|
||||||
|
private final String version;
|
||||||
private final Map<String, String> forbiddenTokens;
|
private final Map<String, String> forbiddenTokens;
|
||||||
private ManagedProcess process;
|
private ManagedProcess process;
|
||||||
private boolean lwjgl;
|
private boolean lwjgl;
|
||||||
@@ -452,7 +454,9 @@ public final class LauncherHelper {
|
|||||||
private final LinkedList<Pair<String, Log4jLevel>> logs;
|
private final LinkedList<Pair<String, Log4jLevel>> logs;
|
||||||
private final CountDownLatch latch = new CountDownLatch(1);
|
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;
|
this.detectWindow = detectWindow;
|
||||||
|
|
||||||
if (authInfo == null)
|
if (authInfo == null)
|
||||||
@@ -559,6 +563,12 @@ public final class LauncherHelper {
|
|||||||
// Game crashed before opening the game window.
|
// Game crashed before opening the game window.
|
||||||
if (!lwjgl) finishLaunch();
|
if (!lwjgl) finishLaunch();
|
||||||
|
|
||||||
|
launchingLatch.countDown();
|
||||||
|
|
||||||
|
if (exitType != ExitType.NORMAL) {
|
||||||
|
repository.markVersionLaunchedAbnormally(version);
|
||||||
|
}
|
||||||
|
|
||||||
if (exitType != ExitType.NORMAL && logWindow == null)
|
if (exitType != ExitType.NORMAL && logWindow == null)
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
logWindow = new LogWindow();
|
logWindow = new LogWindow();
|
||||||
|
|||||||
@@ -132,9 +132,9 @@ public final class TaskListPane extends StackPane {
|
|||||||
task.setName(i18n("modpack.scan"));
|
task.setName(i18n("modpack.scan"));
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgressListNode node = new ProgressListNode(task);
|
|
||||||
nodes.put(task, node);
|
|
||||||
Platform.runLater(() -> {
|
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);
|
StageNode stageNode = stageNodes.stream().filter(x -> x.stage.equals(task.getStage())).findAny().orElse(null);
|
||||||
listBox.add(listBox.indexOf(stageNode) + 1, node);
|
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(() -> {
|
Platform.runLater(() -> {
|
||||||
|
ProgressListNode node = nodes.remove(task);
|
||||||
|
if (node == null)
|
||||||
|
return;
|
||||||
|
node.unbind();
|
||||||
listBox.remove(node);
|
listBox.remove(node);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ public class Versions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void updateGameAssets(Profile profile, String version) {
|
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();
|
.executor();
|
||||||
Controllers.taskDialog(executor, i18n("version.manage.redownload_assets_index"));
|
Controllers.taskDialog(executor, i18n("version.manage.redownload_assets_index"));
|
||||||
executor.start();
|
executor.start();
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import org.jackhuang.hmcl.download.optifine.OptiFineInstallTask;
|
|||||||
import org.jackhuang.hmcl.game.DefaultGameRepository;
|
import org.jackhuang.hmcl.game.DefaultGameRepository;
|
||||||
import org.jackhuang.hmcl.game.Version;
|
import org.jackhuang.hmcl.game.Version;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.util.function.ExceptionalFunction;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@@ -76,7 +75,7 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Task<?> checkGameCompletionAsync(Version original) {
|
public Task<?> checkGameCompletionAsync(Version original, boolean integrityCheck) {
|
||||||
Version version = original.resolve(repository);
|
Version version = original.resolve(repository);
|
||||||
return Task.allOf(
|
return Task.allOf(
|
||||||
Task.composeAsync(() -> {
|
Task.composeAsync(() -> {
|
||||||
@@ -85,14 +84,14 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
|
|||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
new GameAssetDownloadTask(this, version, GameAssetDownloadTask.DOWNLOAD_INDEX_IF_NECESSARY),
|
new GameAssetDownloadTask(this, version, GameAssetDownloadTask.DOWNLOAD_INDEX_IF_NECESSARY, integrityCheck),
|
||||||
new GameLibrariesTask(this, version)
|
new GameLibrariesTask(this, version, integrityCheck)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Task<?> checkLibraryCompletionAsync(Version version) {
|
public Task<?> checkLibraryCompletionAsync(Version version, boolean integrityCheck) {
|
||||||
return new GameLibrariesTask(this, version, version.getLibraries());
|
return new GameLibrariesTask(this, version, integrityCheck, version.getLibraries());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public interface DependencyManager {
|
|||||||
*
|
*
|
||||||
* @return the task to check game completion.
|
* @return the task to check game completion.
|
||||||
*/
|
*/
|
||||||
Task<?> checkGameCompletionAsync(Version version);
|
Task<?> checkGameCompletionAsync(Version version, boolean integrityCheck);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the game is complete.
|
* Check if the game is complete.
|
||||||
@@ -54,7 +54,7 @@ public interface DependencyManager {
|
|||||||
*
|
*
|
||||||
* @return the task to check game completion.
|
* @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.
|
* The builder to build a brand new game then libraries such as Forge, LiteLoader and OptiFine.
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ public final class FabricInstallTask extends Task<Version> {
|
|||||||
public void execute() {
|
public void execute() {
|
||||||
setResult(getPatch(JsonUtils.GSON.fromJson(launchMetaTask.getResult(), FabricInfo.class), remote.getGameVersion(), remote.getSelfVersion()));
|
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) {
|
private static String getLaunchMetaUrl(String gameVersion, String loaderVersion) {
|
||||||
|
|||||||
@@ -45,14 +45,7 @@ import java.nio.file.FileSystem;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
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.jar.Attributes;
|
import java.util.jar.Attributes;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
import java.util.zip.ZipException;
|
import java.util.zip.ZipException;
|
||||||
@@ -133,7 +126,7 @@ public class ForgeNewInstallTask extends Task<Version> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependents.add(new GameLibrariesTask(dependencyManager, version, profile.getLibraries()));
|
dependents.add(new GameLibrariesTask(dependencyManager, version, true, profile.getLibraries()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -273,7 +266,7 @@ public class ForgeNewInstallTask extends Task<Version> {
|
|||||||
.setPriority(30000)
|
.setPriority(30000)
|
||||||
.setId(LibraryAnalyzer.LibraryType.FORGE.getPatchId())
|
.setId(LibraryAnalyzer.LibraryType.FORGE.getPatchId())
|
||||||
.setVersion(selfVersion));
|
.setVersion(selfVersion));
|
||||||
dependencies.add(dependencyManager.checkLibraryCompletionAsync(forgeVersion));
|
dependencies.add(dependencyManager.checkLibraryCompletionAsync(forgeVersion, true));
|
||||||
|
|
||||||
FileUtils.deleteDirectory(temp.toFile());
|
FileUtils.deleteDirectory(temp.toFile());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,11 +27,7 @@ import org.jackhuang.hmcl.util.gson.JsonUtils;
|
|||||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||||
import org.jackhuang.hmcl.util.io.IOUtils;
|
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -90,7 +86,7 @@ public class ForgeOldInstallTask extends Task<Version> {
|
|||||||
.setPriority(30000)
|
.setPriority(30000)
|
||||||
.setId(LibraryAnalyzer.LibraryType.FORGE.getPatchId())
|
.setId(LibraryAnalyzer.LibraryType.FORGE.getPatchId())
|
||||||
.setVersion(selfVersion));
|
.setVersion(selfVersion));
|
||||||
dependencies.add(dependencyManager.checkLibraryCompletionAsync(installProfile.getVersionInfo()));
|
dependencies.add(dependencyManager.checkLibraryCompletionAsync(installProfile.getVersionInfo(), true));
|
||||||
} catch (ZipException ex) {
|
} catch (ZipException ex) {
|
||||||
throw new ArtifactMalformedException("Malformed forge installer file", ex);
|
throw new ArtifactMalformedException("Malformed forge installer file", ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import org.jackhuang.hmcl.game.Version;
|
|||||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.util.CacheRepository;
|
import org.jackhuang.hmcl.util.CacheRepository;
|
||||||
|
import org.jackhuang.hmcl.util.Logging;
|
||||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||||
import org.jackhuang.hmcl.util.io.NetworkUtils;
|
import org.jackhuang.hmcl.util.io.NetworkUtils;
|
||||||
@@ -37,6 +38,7 @@ import java.net.URL;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,6 +51,7 @@ public final class GameAssetDownloadTask extends Task<Void> {
|
|||||||
private final Version version;
|
private final Version version;
|
||||||
private final AssetIndexInfo assetIndexInfo;
|
private final AssetIndexInfo assetIndexInfo;
|
||||||
private final File assetIndexFile;
|
private final File assetIndexFile;
|
||||||
|
private final boolean integrityCheck;
|
||||||
private final List<Task<?>> dependents = new LinkedList<>();
|
private final List<Task<?>> dependents = new LinkedList<>();
|
||||||
private final List<Task<?>> dependencies = new LinkedList<>();
|
private final List<Task<?>> dependencies = new LinkedList<>();
|
||||||
|
|
||||||
@@ -58,11 +61,12 @@ public final class GameAssetDownloadTask extends Task<Void> {
|
|||||||
* @param dependencyManager the dependency manager that can provides {@link org.jackhuang.hmcl.game.GameRepository}
|
* @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 GameAssetDownloadTask(AbstractDependencyManager dependencyManager, Version version, boolean forceDownloadingIndex) {
|
public GameAssetDownloadTask(AbstractDependencyManager dependencyManager, Version version, boolean forceDownloadingIndex, boolean integrityCheck) {
|
||||||
this.dependencyManager = dependencyManager;
|
this.dependencyManager = dependencyManager;
|
||||||
this.version = version.resolve(dependencyManager.getGameRepository());
|
this.version = version.resolve(dependencyManager.getGameRepository());
|
||||||
this.assetIndexInfo = this.version.getAssetIndex();
|
this.assetIndexInfo = this.version.getAssetIndex();
|
||||||
this.assetIndexFile = dependencyManager.getGameRepository().getIndexFile(version.getId(), assetIndexInfo.getId());
|
this.assetIndexFile = dependencyManager.getGameRepository().getIndexFile(version.getId(), assetIndexInfo.getId());
|
||||||
|
this.integrityCheck = integrityCheck;
|
||||||
|
|
||||||
if (!assetIndexFile.exists() || forceDownloadingIndex) {
|
if (!assetIndexFile.exists() || forceDownloadingIndex) {
|
||||||
dependents.add(new GameAssetIndexDownloadTask(dependencyManager, this.version));
|
dependents.add(new GameAssetIndexDownloadTask(dependencyManager, this.version));
|
||||||
@@ -101,9 +105,14 @@ public final class GameAssetDownloadTask extends Task<Void> {
|
|||||||
throw new InterruptedException();
|
throw new InterruptedException();
|
||||||
|
|
||||||
File file = dependencyManager.getGameRepository().getAssetObject(version.getId(), assetIndexInfo.getId(), assetObject);
|
File file = dependencyManager.getGameRepository().getAssetObject(version.getId(), assetIndexInfo.getId(), assetObject);
|
||||||
if (file.isFile())
|
boolean download = !file.isFile();
|
||||||
dependencyManager.getCacheRepository().tryCacheFile(file.toPath(), CacheRepository.SHA1, assetObject.getHash());
|
try {
|
||||||
else {
|
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<URL> urls = dependencyManager.getPreferredDownloadProviders().stream()
|
List<URL> urls = dependencyManager.getPreferredDownloadProviders().stream()
|
||||||
.map(downloadProvider -> downloadProvider.getAssetBaseURL() + assetObject.getLocation())
|
.map(downloadProvider -> downloadProvider.getAssetBaseURL() + assetObject.getLocation())
|
||||||
.map(NetworkUtils::toURL)
|
.map(NetworkUtils::toURL)
|
||||||
@@ -116,6 +125,8 @@ public final class GameAssetDownloadTask extends Task<Void> {
|
|||||||
.setCaching(true)
|
.setCaching(true)
|
||||||
.setCandidate(dependencyManager.getCacheRepository().getCommonDirectory()
|
.setCandidate(dependencyManager.getCacheRepository().getCommonDirectory()
|
||||||
.resolve("assets").resolve("objects").resolve(assetObject.getLocation())));
|
.resolve("assets").resolve("objects").resolve(assetObject.getLocation())));
|
||||||
|
} else {
|
||||||
|
dependencyManager.getCacheRepository().tryCacheFile(file.toPath(), CacheRepository.SHA1, assetObject.getHash());
|
||||||
}
|
}
|
||||||
|
|
||||||
updateProgress(++progress, index.getObjects().size());
|
updateProgress(++progress, index.getObjects().size());
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ public class GameInstallTask extends Task<Version> {
|
|||||||
Version version = new Version(this.version.getId()).addPatch(patch);
|
Version version = new Version(this.version.getId()).addPatch(patch);
|
||||||
dependencies.add(new GameDownloadTask(dependencyManager, remote.getGameVersion(), version)
|
dependencies.add(new GameDownloadTask(dependencyManager, remote.getGameVersion(), version)
|
||||||
.thenComposeAsync(Task.allOf(
|
.thenComposeAsync(Task.allOf(
|
||||||
new GameAssetDownloadTask(dependencyManager, version, GameAssetDownloadTask.DOWNLOAD_INDEX_FORCIBLY),
|
new GameAssetDownloadTask(dependencyManager, version, GameAssetDownloadTask.DOWNLOAD_INDEX_FORCIBLY, true),
|
||||||
new GameLibrariesTask(dependencyManager, version)
|
new GameLibrariesTask(dependencyManager, version, true)
|
||||||
).withStage("hmcl.install.assets").withComposeAsync(gameRepository.save(version))));
|
).withStage("hmcl.install.assets").withComposeAsync(gameRepository.save(version))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,10 +21,14 @@ import org.jackhuang.hmcl.download.AbstractDependencyManager;
|
|||||||
import org.jackhuang.hmcl.game.Library;
|
import org.jackhuang.hmcl.game.Library;
|
||||||
import org.jackhuang.hmcl.game.Version;
|
import org.jackhuang.hmcl.game.Version;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
|
import org.jackhuang.hmcl.util.Logging;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This task is to download game libraries.
|
* This task is to download game libraries.
|
||||||
@@ -36,6 +40,7 @@ public final class GameLibrariesTask extends Task<Void> {
|
|||||||
|
|
||||||
private final AbstractDependencyManager dependencyManager;
|
private final AbstractDependencyManager dependencyManager;
|
||||||
private final Version version;
|
private final Version version;
|
||||||
|
private final boolean integrityCheck;
|
||||||
private final List<Library> libraries;
|
private final List<Library> libraries;
|
||||||
private final List<Task<?>> dependencies = new LinkedList<>();
|
private final List<Task<?>> dependencies = new LinkedList<>();
|
||||||
|
|
||||||
@@ -43,21 +48,22 @@ public final class GameLibrariesTask extends Task<Void> {
|
|||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param dependencyManager the dependency manager that can provides {@link org.jackhuang.hmcl.game.GameRepository}
|
* @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) {
|
public GameLibrariesTask(AbstractDependencyManager dependencyManager, Version version, boolean integrityCheck) {
|
||||||
this(dependencyManager, version, version.resolve(dependencyManager.getGameRepository()).getLibraries());
|
this(dependencyManager, version, integrityCheck, version.resolve(dependencyManager.getGameRepository()).getLibraries());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param dependencyManager the dependency manager that can provides {@link org.jackhuang.hmcl.game.GameRepository}
|
* @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<Library> libraries) {
|
public GameLibrariesTask(AbstractDependencyManager dependencyManager, Version version, boolean integrityCheck, List<Library> libraries) {
|
||||||
this.dependencyManager = dependencyManager;
|
this.dependencyManager = dependencyManager;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
|
this.integrityCheck = integrityCheck;
|
||||||
this.libraries = libraries;
|
this.libraries = libraries;
|
||||||
|
|
||||||
setSignificance(TaskSignificance.MODERATE);
|
setSignificance(TaskSignificance.MODERATE);
|
||||||
@@ -72,10 +78,22 @@ public final class GameLibrariesTask extends Task<Void> {
|
|||||||
public void execute() {
|
public void execute() {
|
||||||
libraries.stream().filter(Library::appliesToCurrentEnvironment).forEach(library -> {
|
libraries.stream().filter(Library::appliesToCurrentEnvironment).forEach(library -> {
|
||||||
File file = dependencyManager.getGameRepository().getLibraryFile(version, 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));
|
dependencies.add(new LibraryDownloadTask(dependencyManager, file, library));
|
||||||
else
|
} else {
|
||||||
dependencyManager.getCacheRepository().tryCacheLibrary(library, file.toPath());
|
dependencyManager.getCacheRepository().tryCacheLibrary(library, file.toPath());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,12 +19,7 @@ package org.jackhuang.hmcl.download.liteloader;
|
|||||||
|
|
||||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||||
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||||
import org.jackhuang.hmcl.game.Arguments;
|
import org.jackhuang.hmcl.game.*;
|
||||||
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.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.util.Lang;
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
|
|
||||||
@@ -79,7 +74,7 @@ public final class LiteLoaderInstallTask extends Task<Version> {
|
|||||||
.setLogging(Collections.emptyMap()) // Mods may log in malformed format, causing XML parser to crash. So we suppress using official log4j configuration
|
.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));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,14 +20,7 @@ package org.jackhuang.hmcl.download.optifine;
|
|||||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||||
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||||
import org.jackhuang.hmcl.download.VersionMismatchException;
|
import org.jackhuang.hmcl.download.VersionMismatchException;
|
||||||
import org.jackhuang.hmcl.game.Arguments;
|
import org.jackhuang.hmcl.game.*;
|
||||||
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.task.FileDownloadTask;
|
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
||||||
@@ -184,7 +177,7 @@ public final class OptiFineInstallTask extends Task<Version> {
|
|||||||
libraries
|
libraries
|
||||||
));
|
));
|
||||||
|
|
||||||
dependencies.add(dependencyManager.checkLibraryCompletionAsync(getResult()));
|
dependencies.add(dependencyManager.checkLibraryCompletionAsync(getResult(), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class UnsupportedOptiFineInstallationException extends Exception {
|
public static class UnsupportedOptiFineInstallationException extends Exception {
|
||||||
|
|||||||
@@ -18,9 +18,14 @@
|
|||||||
package org.jackhuang.hmcl.game;
|
package org.jackhuang.hmcl.game;
|
||||||
|
|
||||||
import com.google.gson.JsonParseException;
|
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.StringUtils;
|
||||||
import org.jackhuang.hmcl.util.gson.Validation;
|
import org.jackhuang.hmcl.util.gson.Validation;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
@@ -56,4 +61,9 @@ public final class AssetObject implements Validation {
|
|||||||
if (StringUtils.isBlank(hash) || hash.length() < 2)
|
if (StringUtils.isBlank(hash) || hash.length() < 2)
|
||||||
throw new JsonParseException("AssetObject hash cannot be blank.");
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,12 +19,13 @@ package org.jackhuang.hmcl.game;
|
|||||||
|
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
import org.jackhuang.hmcl.util.Immutable;
|
import org.jackhuang.hmcl.util.*;
|
||||||
import org.jackhuang.hmcl.util.StringUtils;
|
|
||||||
import org.jackhuang.hmcl.util.ToStringBuilder;
|
|
||||||
import org.jackhuang.hmcl.util.gson.TolerableValidationException;
|
import org.jackhuang.hmcl.util.gson.TolerableValidationException;
|
||||||
import org.jackhuang.hmcl.util.gson.Validation;
|
import org.jackhuang.hmcl.util.gson.Validation;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
@@ -79,4 +80,9 @@ public class DownloadInfo implements Validation {
|
|||||||
if (StringUtils.isBlank(url))
|
if (StringUtils.isBlank(url))
|
||||||
throw new TolerableValidationException();
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user