Only cache verified files and copy cached files to current directory
This commit is contained in:
@@ -20,7 +20,10 @@ package org.jackhuang.hmcl.game;
|
||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||
import org.jackhuang.hmcl.download.GameBuilder;
|
||||
import org.jackhuang.hmcl.download.game.GameAssetDownloadTask;
|
||||
import org.jackhuang.hmcl.setting.Profile;
|
||||
import org.jackhuang.hmcl.task.ParallelTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
|
||||
/**
|
||||
* @author huangyuhui
|
||||
@@ -38,4 +41,17 @@ public class HMCLDependencyManager extends DefaultDependencyManager {
|
||||
public GameBuilder gameBuilder() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import org.jackhuang.hmcl.setting.Profile;
|
||||
import org.jackhuang.hmcl.setting.Settings;
|
||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.task.FileDownloadTask.IntegrityCheck;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
@@ -28,6 +27,9 @@ import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -51,7 +53,7 @@ public class HMCLGameDownloadTask extends Task {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Task> getDependencies() {
|
||||
public Collection<Task> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@@ -59,24 +61,26 @@ public class HMCLGameDownloadTask extends Task {
|
||||
public void execute() {
|
||||
File jar = profile.getRepository().getVersionJar(version);
|
||||
|
||||
// Force using common directory will not affect the behaviour that repository acts
|
||||
// Since we always copy the downloaded jar to .minecraft/versions/<version>/
|
||||
File cache = new File(Optional.ofNullable(Settings.instance().getCommonDirectory())
|
||||
.orElse(Settings.getDefaultCommonDirectory()),
|
||||
"jars/" + gameVersion + ".jar");
|
||||
if (cache.exists())
|
||||
Optional<Path> path = HMCLLocalRepository.REPOSITORY.getVersion(gameVersion, version);
|
||||
if (path.isPresent()) {
|
||||
try {
|
||||
FileUtils.copyFile(cache, jar);
|
||||
FileUtils.copyFile(path.get().toFile(), jar);
|
||||
return;
|
||||
} 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(
|
||||
NetworkUtils.toURL(profile.getDependency().getDownloadProvider().injectURL(version.getDownloadInfo().getUrl())),
|
||||
cache,
|
||||
new IntegrityCheck("SHA-1", version.getDownloadInfo().getSha1())
|
||||
).then(Task.of(v -> FileUtils.copyFile(cache, jar))));
|
||||
URL url = NetworkUtils.toURL(profile.getDependency().getDownloadProvider().injectURL(version.getDownloadInfo().getUrl()));
|
||||
|
||||
if (version.getDownloadInfo().getSha1() == null) {
|
||||
// We do not know jar's hash, then we will not cache it.
|
||||
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()))));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -56,7 +56,7 @@ public class HMCLGameRepository extends DefaultGameRepository {
|
||||
|
||||
@Override
|
||||
public File getAssetDirectory(String version, String assetId) {
|
||||
if (Settings.instance().isCommonDirectoryDisabled() || useSelf(assetId))
|
||||
if (useSelf(assetId))
|
||||
return super.getAssetDirectory(version, assetId);
|
||||
else
|
||||
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
|
||||
protected void refreshVersionsImpl() {
|
||||
versionSettings.clear();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,6 @@
|
||||
package org.jackhuang.hmcl.setting;
|
||||
|
||||
public enum EnumCommonDirectory {
|
||||
/**
|
||||
* same to game directory
|
||||
*/
|
||||
DISABLED,
|
||||
/**
|
||||
* %appdata%/.minecraft or ~/.minecraft
|
||||
*/
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package org.jackhuang.hmcl.setting;
|
||||
|
||||
import com.google.gson.*;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.InvalidationListener;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.property.*;
|
||||
@@ -231,7 +230,7 @@ public final class Profile implements Observable {
|
||||
}
|
||||
|
||||
protected void invalidate() {
|
||||
Platform.runLater(observableHelper::invalidate);
|
||||
observableHelper.invalidate();
|
||||
}
|
||||
|
||||
public static final class Serializer implements JsonSerializer<Profile>, JsonDeserializer<Profile> {
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.jackhuang.hmcl.setting;
|
||||
import javafx.scene.text.Font;
|
||||
import org.jackhuang.hmcl.Launcher;
|
||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||
import org.jackhuang.hmcl.game.HMCLLocalRepository;
|
||||
|
||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||
|
||||
@@ -45,6 +46,8 @@ public class Settings {
|
||||
ProxyManager.init();
|
||||
Accounts.init();
|
||||
Profiles.init();
|
||||
|
||||
HMCLLocalRepository.REPOSITORY.directoryProperty().bind(config().commonDirectoryProperty());
|
||||
}
|
||||
|
||||
public Font getFont() {
|
||||
@@ -64,18 +67,12 @@ public class Settings {
|
||||
config().setLogLines(logLines);
|
||||
}
|
||||
|
||||
public boolean isCommonDirectoryDisabled() {
|
||||
return config().getCommonDirType() == EnumCommonDirectory.DISABLED;
|
||||
}
|
||||
|
||||
public static String getDefaultCommonDirectory() {
|
||||
return Launcher.MINECRAFT_DIRECTORY.getAbsolutePath();
|
||||
}
|
||||
|
||||
public String getCommonDirectory() {
|
||||
switch (config().getCommonDirType()) {
|
||||
case DISABLED:
|
||||
return null;
|
||||
case DEFAULT:
|
||||
return getDefaultCommonDirectory();
|
||||
case CUSTOM:
|
||||
|
||||
@@ -138,7 +138,6 @@ public final class SettingsPage extends SettingsView implements DecoratorPage {
|
||||
// ====
|
||||
|
||||
fileCommonLocation.loadChildren(Arrays.asList(
|
||||
fileCommonLocation.createChildren(i18n("launcher.common_directory.disabled"), EnumCommonDirectory.DISABLED),
|
||||
fileCommonLocation.createChildren(i18n("launcher.common_directory.default"), EnumCommonDirectory.DEFAULT)
|
||||
), EnumCommonDirectory.CUSTOM);
|
||||
fileCommonLocation.selectedDataProperty().bindBidirectional(config().commonDirTypeProperty());
|
||||
|
||||
@@ -72,6 +72,11 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task checkLibraryCompletionAsync(Version version) {
|
||||
return new GameLibrariesTask(this, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task installLibraryAsync(String gameVersion, Version version, String libraryId, String libraryVersion) {
|
||||
VersionList<?> versionList = getVersionList(libraryId);
|
||||
|
||||
@@ -36,12 +36,20 @@ public interface DependencyManager {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package org.jackhuang.hmcl.download.forge;
|
||||
|
||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.download.game.GameLibrariesTask;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.game.SimpleVersionProvider;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
@@ -114,7 +113,7 @@ public final class ForgeInstallTask extends TaskResult<Version> {
|
||||
.resolve(provider).setJar(null)
|
||||
.setId(version.getId()).setLogging(Collections.emptyMap()));
|
||||
|
||||
dependencies.add(new GameLibrariesTask(dependencyManager, installProfile.getVersionInfo()));
|
||||
dependencies.add(dependencyManager.checkLibraryCompletionAsync(installProfile.getVersionInfo()));
|
||||
}
|
||||
|
||||
if (!installer.delete())
|
||||
|
||||
@@ -82,7 +82,7 @@ public final class LiteLoaderInstallTask extends TaskResult<Version> {
|
||||
.setLogging(Collections.emptyMap())
|
||||
);
|
||||
|
||||
dependencies.add(new GameLibrariesTask(dependencyManager, tempVersion));
|
||||
dependencies.add(dependencyManager.checkLibraryCompletionAsync(tempVersion));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package org.jackhuang.hmcl.download.optifine;
|
||||
|
||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.download.game.GameLibrariesTask;
|
||||
import org.jackhuang.hmcl.game.LibrariesDownloadInfo;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.game.LibraryDownloadInfo;
|
||||
@@ -92,7 +91,7 @@ public final class OptiFineInstallTask extends TaskResult<Version> {
|
||||
.setMainClass("net.minecraft.launchwrapper.Launch")
|
||||
);
|
||||
|
||||
dependencies.add(new GameLibrariesTask(dependencyManager, version.setLibraries(libraries)));
|
||||
dependencies.add(dependencyManager.checkLibraryCompletionAsync(version.setLibraries(libraries)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user