Only cache verified files and copy cached files to current directory

This commit is contained in:
huangyuhui
2018-09-06 00:13:16 +08:00
parent 61aee90c8d
commit 1392ad413a
15 changed files with 500 additions and 45 deletions

View File

@@ -20,7 +20,10 @@ package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.DownloadProvider; import org.jackhuang.hmcl.download.DownloadProvider;
import org.jackhuang.hmcl.download.GameBuilder; import org.jackhuang.hmcl.download.GameBuilder;
import org.jackhuang.hmcl.download.game.GameAssetDownloadTask;
import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.task.ParallelTask;
import org.jackhuang.hmcl.task.Task;
/** /**
* @author huangyuhui * @author huangyuhui
@@ -38,4 +41,17 @@ public class HMCLDependencyManager extends DefaultDependencyManager {
public GameBuilder gameBuilder() { public GameBuilder gameBuilder() {
return new HMCLGameBuilder(profile); return new HMCLGameBuilder(profile);
} }
@Override
public Task checkGameCompletionAsync(Version version) {
return new ParallelTask(
new GameAssetDownloadTask(this, version),
new HMCLGameLibrariesTask(this, version)
);
}
@Override
public Task checkLibraryCompletionAsync(Version version) {
return new HMCLGameLibrariesTask(this, version);
}
} }

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.game; package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.FileDownloadTask;
import org.jackhuang.hmcl.task.FileDownloadTask.IntegrityCheck; import org.jackhuang.hmcl.task.FileDownloadTask.IntegrityCheck;
import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.Task;
@@ -28,6 +27,9 @@ import org.jackhuang.hmcl.util.NetworkUtils;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.nio.file.Path;
import java.util.Collection;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@@ -51,7 +53,7 @@ public class HMCLGameDownloadTask extends Task {
} }
@Override @Override
public List<Task> getDependencies() { public Collection<Task> getDependencies() {
return dependencies; return dependencies;
} }
@@ -59,24 +61,26 @@ public class HMCLGameDownloadTask extends Task {
public void execute() { public void execute() {
File jar = profile.getRepository().getVersionJar(version); File jar = profile.getRepository().getVersionJar(version);
// Force using common directory will not affect the behaviour that repository acts Optional<Path> path = HMCLLocalRepository.REPOSITORY.getVersion(gameVersion, version);
// Since we always copy the downloaded jar to .minecraft/versions/<version>/ if (path.isPresent()) {
File cache = new File(Optional.ofNullable(Settings.instance().getCommonDirectory())
.orElse(Settings.getDefaultCommonDirectory()),
"jars/" + gameVersion + ".jar");
if (cache.exists())
try { try {
FileUtils.copyFile(cache, jar); FileUtils.copyFile(path.get().toFile(), jar);
return; return;
} catch (IOException e) { } catch (IOException e) {
Logging.LOG.log(Level.SEVERE, "Unable to copy cached Minecraft jar from " + cache + " to " + jar, e); Logging.LOG.log(Level.SEVERE, "Unable to copy cached Minecraft jar from " + path.get() + " to " + jar, e);
} }
}
dependencies.add(new FileDownloadTask( URL url = NetworkUtils.toURL(profile.getDependency().getDownloadProvider().injectURL(version.getDownloadInfo().getUrl()));
NetworkUtils.toURL(profile.getDependency().getDownloadProvider().injectURL(version.getDownloadInfo().getUrl())),
cache, if (version.getDownloadInfo().getSha1() == null) {
new IntegrityCheck("SHA-1", version.getDownloadInfo().getSha1()) // We do not know jar's hash, then we will not cache it.
).then(Task.of(v -> FileUtils.copyFile(cache, jar)))); dependencies.add(new FileDownloadTask(url, jar));
} else {
dependencies.add(new FileDownloadTask(url, jar,
new IntegrityCheck("SHA-1", version.getDownloadInfo().getSha1())
).then(Task.of(v -> HMCLLocalRepository.REPOSITORY.cacheVersion(version, jar.toPath()))));
}
} }
} }

View File

@@ -0,0 +1,61 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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 {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.Lang;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
public class HMCLGameLibrariesTask extends Task {
private final HMCLDependencyManager dependencyManager;
private final Version version;
private final List<Task> dependencies = new LinkedList<>();
/**
* Constructor.
*
* @param dependencyManager the dependency manager that can provides {@link org.jackhuang.hmcl.game.GameRepository}
* @param version the <b>resolved</b> version
*/
public HMCLGameLibrariesTask(HMCLDependencyManager dependencyManager, Version version) {
this.dependencyManager = dependencyManager;
this.version = version;
setSignificance(TaskSignificance.MODERATE);
}
@Override
public List<Task> getDependencies() {
return dependencies;
}
@Override
public void execute() {
version.getLibraries().stream().filter(Library::appliesToCurrentEnvironment).forEach(library -> {
File file = dependencyManager.getGameRepository().getLibraryFile(version, library);
if (!file.exists())
dependencies.add(new HMCLLibraryDownloadTask(dependencyManager, file, library));
else
HMCLLocalRepository.REPOSITORY.tryCacheLibrary(library, file.toPath());
});
}
}

View File

@@ -56,7 +56,7 @@ public class HMCLGameRepository extends DefaultGameRepository {
@Override @Override
public File getAssetDirectory(String version, String assetId) { public File getAssetDirectory(String version, String assetId) {
if (Settings.instance().isCommonDirectoryDisabled() || useSelf(assetId)) if (useSelf(assetId))
return super.getAssetDirectory(version, assetId); return super.getAssetDirectory(version, assetId);
else else
return new File(Settings.instance().getCommonDirectory(), "assets"); return new File(Settings.instance().getCommonDirectory(), "assets");
@@ -77,16 +77,6 @@ public class HMCLGameRepository extends DefaultGameRepository {
} }
} }
@Override
public File getLibraryFile(Version version, Library lib) {
File self = super.getLibraryFile(version, lib);
if (Settings.instance().isCommonDirectoryDisabled() || self.exists())
return self;
else
return new File(Settings.instance().getCommonDirectory(), "libraries/" + lib.getPath());
}
@Override @Override
protected void refreshVersionsImpl() { protected void refreshVersionsImpl() {
versionSettings.clear(); versionSettings.clear();

View File

@@ -0,0 +1,79 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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 {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.download.game.LibraryDownloadException;
import org.jackhuang.hmcl.download.game.LibraryDownloadTask;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.FileUtils;
import org.jackhuang.hmcl.util.Logging;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.logging.Level;
public final class HMCLLibraryDownloadTask extends LibraryDownloadTask {
private boolean cached = false;
public HMCLLibraryDownloadTask(HMCLDependencyManager dependencyManager, File file, Library library) {
super(dependencyManager, file, library);
}
@Override
public void preExecute() throws Exception {
Optional<Path> libPath = HMCLLocalRepository.REPOSITORY.getLibrary(library);
if (libPath.isPresent()) {
try {
FileUtils.copyFile(libPath.get().toFile(), jar);
cached = true;
return;
} catch (IOException e) {
Logging.LOG.log(Level.WARNING, "Failed to copy file from cache", e);
// We cannot copy cached file to current location
// so we try to download a new one.
}
}
super.preExecute();
}
@Override
public Collection<? extends Task> getDependents() {
if (cached) return Collections.emptyList();
else return super.getDependents();
}
@Override
public void execute() throws Exception {
if (cached) return;
super.execute();
}
@Override
public void postExecute() throws Exception {
super.postExecute();
if (!cached)
HMCLLocalRepository.REPOSITORY.cacheLibrary(library, jar.toPath(), xz);
}
}

View File

@@ -0,0 +1,303 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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 {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hmcl.game;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import org.jackhuang.hmcl.download.game.LibraryDownloadTask;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.util.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.stream.Collectors;
public class HMCLLocalRepository {
private final StringProperty directory = new SimpleStringProperty();
private Path cacheDir;
private Path librariesDir;
private Path jarsDir;
private Path indexFile;
private Index index = null;
public HMCLLocalRepository() {
FXUtils.onChange(directory, t -> changeDirectory(Paths.get(t)));
}
public String getDirectory() {
return directory.get();
}
public StringProperty directoryProperty() {
return directory;
}
public void setDirectory(String directory) {
this.directory.set(directory);
}
private void changeDirectory(Path commonDir) {
cacheDir = commonDir.resolve("cache");
librariesDir = commonDir.resolve("libraries");
jarsDir = commonDir.resolve("jars");
indexFile = cacheDir.resolve("index.json");
try {
index = Constants.GSON.fromJson(FileUtils.readText(indexFile.toFile()), Index.class);
} catch (IOException e) {
Logging.LOG.log(Level.WARNING, "Unable to read index file", e);
index = new Index();
}
}
private Path getFile(String algorithm, String hash) {
return cacheDir.resolve(algorithm).resolve(hash.substring(0, 2)).resolve(hash);
}
private boolean fileExists(String algorithm, String hash) {
if (hash == null) return false;
return Files.exists(getFile(algorithm, hash));
}
public void tryCacheLibrary(Library library, Path jar) {
if (index.getLibraries().stream().anyMatch(it -> library.getName().equals(it.getName())))
return;
try {
LibraryDownloadInfo info = library.getDownload();
String hash = info.getSha1();
if (hash != null) {
String checksum = Hex.encodeHex(DigestUtils.digest("SHA-1", jar));
if (hash.equalsIgnoreCase(checksum))
cacheLibrary(library, jar, false);
} else if (library.getChecksums() != null && !library.getChecksums().isEmpty()) {
if (LibraryDownloadTask.checksumValid(jar.toFile(), library.getChecksums()))
cacheLibrary(library, jar, true);
} else {
// or we will not cache the library
}
} catch (IOException e) {
Logging.LOG.log(Level.WARNING, "Unable to calc hash value of file " + jar, e);
}
}
public synchronized Optional<Path> getLibrary(Library library) {
LibraryDownloadInfo info = library.getDownload();
String hash = info.getSha1();
if (fileExists(SHA1, hash))
return Optional.of(getFile(SHA1, hash));
// check if this library is from Forge
List<LibraryIndex> libraries = index.getLibraries().stream()
.filter(it -> it.getName().equals(library.getName()))
.collect(Collectors.toList());
for (LibraryIndex libIndex : libraries) {
if (fileExists(SHA1, libIndex.getHash())) {
Path file = getFile(SHA1, libIndex.getHash());
if (libIndex.getType().equalsIgnoreCase(LibraryIndex.TYPE_FORGE)) {
if (LibraryDownloadTask.checksumValid(file.toFile(), library.getChecksums()))
return Optional.of(file);
}
}
}
// check old common directory
Path jar = librariesDir.resolve(info.getPath());
if (Files.exists(jar)) {
try {
if (hash != null) {
String checksum = Hex.encodeHex(DigestUtils.digest("SHA-1", jar));
if (hash.equalsIgnoreCase(checksum))
return Optional.of(restore(jar, () -> cacheLibrary(library, jar, false)));
} else if (library.getChecksums() != null && !library.getChecksums().isEmpty()) {
if (LibraryDownloadTask.checksumValid(jar.toFile(), library.getChecksums()))
return Optional.of(restore(jar, () -> cacheLibrary(library, jar, true)));
} else {
return Optional.of(jar);
}
} catch (IOException e) {
// we cannot check the hashcode or unable to move file.
}
}
return Optional.empty();
}
public synchronized Path cacheLibrary(Library library, Path path, boolean forge) throws IOException {
String hash = library.getDownload().getSha1();
if (hash == null)
hash = Hex.encodeHex(DigestUtils.digest(SHA1, path));
Path cache = getFile(SHA1, hash);
FileUtils.copyFile(path.toFile(), cache.toFile());
LibraryIndex libIndex = new LibraryIndex(library.getName(), hash, forge ? LibraryIndex.TYPE_FORGE : LibraryIndex.TYPE_JAR);
index.getLibraries().add(libIndex);
saveIndex();
return cache;
}
public synchronized Optional<Path> getVersion(String gameVersion, Version version) {
DownloadInfo info = version.getDownloadInfo();
String hash = info.getSha1();
if (fileExists(SHA1, hash))
return Optional.of(getFile(SHA1, hash));
// check old common directory, but we will no longer maintain it.
Path jar = jarsDir.resolve(gameVersion + ".jar");
if (Files.exists(jar)) {
if (hash != null) {
try {
String checksum = Hex.encodeHex(DigestUtils.digest("SHA-1", jar));
if (!checksum.equalsIgnoreCase(hash)) {
// The file is not the one we want
return Optional.empty();
} else {
return Optional.of(restore(jar, () -> cacheVersion(version, jar)));
}
} catch (IOException e) {
// we cannot check the hashcode.
return Optional.empty();
}
} else {
return Optional.of(jar);
}
}
return Optional.empty();
}
public synchronized Path cacheVersion(Version version, Path path) throws IOException {
if (version.getDownloadInfo().getSha1() == null)
throw new IllegalStateException();
Path cache = getFile(SHA1, version.getDownloadInfo().getSha1());
FileUtils.copyFile(path.toFile(), cache.toFile());
return cache;
}
private Path restore(Path original, ExceptionalSupplier<Path, ? extends IOException> cacheSupplier) throws IOException {
Path cache = cacheSupplier.get();
Files.delete(original);
Files.createLink(original, cache);
return cache;
}
private void saveIndex() {
if (indexFile == null || index == null) return;
try {
FileUtils.writeText(indexFile.toFile(), Constants.GSON.toJson(index));
} catch (IOException e) {
Logging.LOG.log(Level.SEVERE, "Unable to save index.json", e);
}
}
private static final String SHA1 = "SHA-1";
public static final HMCLLocalRepository REPOSITORY = new HMCLLocalRepository();
/**
* {
* "libraries": {
* // allow a library has multiple hash code.
* [
* "name": "net.minecraftforge:forge:1.11.2-13.20.0.2345",
* "hash": "blablabla",
* "type": "forge"
* ]
* },
* "indexes": [
* {
* "name": "1.7.10",
* "hash": "..."
* }
* ]
* // we don't cache asset objects in our repository which are already stored in a cache repository.
* }
*/
private class Index {
private final Set<LibraryIndex> libraries;
public Index() {
this(new HashSet<>());
}
public Index(Set<LibraryIndex> libraries) {
this.libraries = libraries;
}
public Set<LibraryIndex> getLibraries() {
return libraries;
}
}
private class LibraryIndex {
private final String name;
private final String hash;
private final String type;
public LibraryIndex() {
this(null, null, null);
}
public LibraryIndex(String name, String hash, String type) {
this.name = name;
this.hash = hash;
this.type = type;
}
public String getName() {
return name;
}
public String getHash() {
return hash;
}
public String getType() {
return type;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LibraryIndex that = (LibraryIndex) o;
return Objects.equals(name, that.name) &&
Objects.equals(hash, that.hash) &&
Objects.equals(type, that.type);
}
@Override
public int hashCode() {
return Objects.hash(name, hash, type);
}
public static final String TYPE_FORGE = "forge";
public static final String TYPE_JAR = "jar";
}
}

View File

@@ -18,10 +18,6 @@
package org.jackhuang.hmcl.setting; package org.jackhuang.hmcl.setting;
public enum EnumCommonDirectory { public enum EnumCommonDirectory {
/**
* same to game directory
*/
DISABLED,
/** /**
* %appdata%/.minecraft or ~/.minecraft * %appdata%/.minecraft or ~/.minecraft
*/ */

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.setting; package org.jackhuang.hmcl.setting;
import com.google.gson.*; import com.google.gson.*;
import javafx.application.Platform;
import javafx.beans.InvalidationListener; import javafx.beans.InvalidationListener;
import javafx.beans.Observable; import javafx.beans.Observable;
import javafx.beans.property.*; import javafx.beans.property.*;
@@ -231,7 +230,7 @@ public final class Profile implements Observable {
} }
protected void invalidate() { protected void invalidate() {
Platform.runLater(observableHelper::invalidate); observableHelper.invalidate();
} }
public static final class Serializer implements JsonSerializer<Profile>, JsonDeserializer<Profile> { public static final class Serializer implements JsonSerializer<Profile>, JsonDeserializer<Profile> {

View File

@@ -20,6 +20,7 @@ package org.jackhuang.hmcl.setting;
import javafx.scene.text.Font; import javafx.scene.text.Font;
import org.jackhuang.hmcl.Launcher; import org.jackhuang.hmcl.Launcher;
import org.jackhuang.hmcl.download.DownloadProvider; import org.jackhuang.hmcl.download.DownloadProvider;
import org.jackhuang.hmcl.game.HMCLLocalRepository;
import static org.jackhuang.hmcl.setting.ConfigHolder.config; import static org.jackhuang.hmcl.setting.ConfigHolder.config;
@@ -45,6 +46,8 @@ public class Settings {
ProxyManager.init(); ProxyManager.init();
Accounts.init(); Accounts.init();
Profiles.init(); Profiles.init();
HMCLLocalRepository.REPOSITORY.directoryProperty().bind(config().commonDirectoryProperty());
} }
public Font getFont() { public Font getFont() {
@@ -64,18 +67,12 @@ public class Settings {
config().setLogLines(logLines); config().setLogLines(logLines);
} }
public boolean isCommonDirectoryDisabled() {
return config().getCommonDirType() == EnumCommonDirectory.DISABLED;
}
public static String getDefaultCommonDirectory() { public static String getDefaultCommonDirectory() {
return Launcher.MINECRAFT_DIRECTORY.getAbsolutePath(); return Launcher.MINECRAFT_DIRECTORY.getAbsolutePath();
} }
public String getCommonDirectory() { public String getCommonDirectory() {
switch (config().getCommonDirType()) { switch (config().getCommonDirType()) {
case DISABLED:
return null;
case DEFAULT: case DEFAULT:
return getDefaultCommonDirectory(); return getDefaultCommonDirectory();
case CUSTOM: case CUSTOM:

View File

@@ -138,7 +138,6 @@ public final class SettingsPage extends SettingsView implements DecoratorPage {
// ==== // ====
fileCommonLocation.loadChildren(Arrays.asList( fileCommonLocation.loadChildren(Arrays.asList(
fileCommonLocation.createChildren(i18n("launcher.common_directory.disabled"), EnumCommonDirectory.DISABLED),
fileCommonLocation.createChildren(i18n("launcher.common_directory.default"), EnumCommonDirectory.DEFAULT) fileCommonLocation.createChildren(i18n("launcher.common_directory.default"), EnumCommonDirectory.DEFAULT)
), EnumCommonDirectory.CUSTOM); ), EnumCommonDirectory.CUSTOM);
fileCommonLocation.selectedDataProperty().bindBidirectional(config().commonDirTypeProperty()); fileCommonLocation.selectedDataProperty().bindBidirectional(config().commonDirTypeProperty());

View File

@@ -72,6 +72,11 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
); );
} }
@Override
public Task checkLibraryCompletionAsync(Version version) {
return new GameLibrariesTask(this, version);
}
@Override @Override
public Task installLibraryAsync(String gameVersion, Version version, String libraryId, String libraryVersion) { public Task installLibraryAsync(String gameVersion, Version version, String libraryId, String libraryVersion) {
VersionList<?> versionList = getVersionList(libraryId); VersionList<?> versionList = getVersionList(libraryId);

View File

@@ -36,12 +36,20 @@ public interface DependencyManager {
/** /**
* Check if the game is complete. * Check if the game is complete.
* Check libraries, assets, logging files and so on. * Check libraries, assets files and so on.
* *
* @return the task to check game completion. * @return the task to check game completion.
*/ */
Task checkGameCompletionAsync(Version version); Task checkGameCompletionAsync(Version version);
/**
* Check if the game is complete.
* Check libraries, assets files and so on.
*
* @return the task to check game completion.
*/
Task checkLibraryCompletionAsync(Version version);
/** /**
* 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.
*/ */

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.download.forge; package org.jackhuang.hmcl.download.forge;
import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.game.GameLibrariesTask;
import org.jackhuang.hmcl.game.Library; import org.jackhuang.hmcl.game.Library;
import org.jackhuang.hmcl.game.SimpleVersionProvider; import org.jackhuang.hmcl.game.SimpleVersionProvider;
import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.game.Version;
@@ -114,7 +113,7 @@ public final class ForgeInstallTask extends TaskResult<Version> {
.resolve(provider).setJar(null) .resolve(provider).setJar(null)
.setId(version.getId()).setLogging(Collections.emptyMap())); .setId(version.getId()).setLogging(Collections.emptyMap()));
dependencies.add(new GameLibrariesTask(dependencyManager, installProfile.getVersionInfo())); dependencies.add(dependencyManager.checkLibraryCompletionAsync(installProfile.getVersionInfo()));
} }
if (!installer.delete()) if (!installer.delete())

View File

@@ -82,7 +82,7 @@ public final class LiteLoaderInstallTask extends TaskResult<Version> {
.setLogging(Collections.emptyMap()) .setLogging(Collections.emptyMap())
); );
dependencies.add(new GameLibrariesTask(dependencyManager, tempVersion)); dependencies.add(dependencyManager.checkLibraryCompletionAsync(tempVersion));
} }
} }

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.download.optifine; package org.jackhuang.hmcl.download.optifine;
import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.game.GameLibrariesTask;
import org.jackhuang.hmcl.game.LibrariesDownloadInfo; import org.jackhuang.hmcl.game.LibrariesDownloadInfo;
import org.jackhuang.hmcl.game.Library; import org.jackhuang.hmcl.game.Library;
import org.jackhuang.hmcl.game.LibraryDownloadInfo; import org.jackhuang.hmcl.game.LibraryDownloadInfo;
@@ -92,7 +91,7 @@ public final class OptiFineInstallTask extends TaskResult<Version> {
.setMainClass("net.minecraft.launchwrapper.Launch") .setMainClass("net.minecraft.launchwrapper.Launch")
); );
dependencies.add(new GameLibrariesTask(dependencyManager, version.setLibraries(libraries))); dependencies.add(dependencyManager.checkLibraryCompletionAsync(version.setLibraries(libraries)));
} }
} }