fix(launch): cannot launch far old versions on macOS.

This commit is contained in:
huanghongxun 2021-10-19 23:07:00 +08:00
parent a4f22671c6
commit f70ec8a090
5 changed files with 53 additions and 44 deletions

View File

@ -30,9 +30,10 @@ import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
@ -47,7 +48,7 @@ public final class GameAssetDownloadTask extends Task<Void> {
private final AbstractDependencyManager dependencyManager;
private final Version version;
private final AssetIndexInfo assetIndexInfo;
private final File assetIndexFile;
private final Path assetIndexFile;
private final boolean integrityCheck;
private final List<Task<?>> dependents = new LinkedList<>();
private final List<Task<?>> dependencies = new LinkedList<>();
@ -93,18 +94,18 @@ public final class GameAssetDownloadTask extends Task<Void> {
if (isCancelled())
throw new InterruptedException();
File file = dependencyManager.getGameRepository().getAssetObject(version.getId(), assetIndexInfo.getId(), assetObject);
boolean download = !file.isFile();
Path file = dependencyManager.getGameRepository().getAssetObject(version.getId(), assetIndexInfo.getId(), assetObject);
boolean download = !Files.isRegularFile(file);
try {
if (!download && integrityCheck && !assetObject.validateChecksum(file.toPath(), true))
if (!download && integrityCheck && !assetObject.validateChecksum(file, true))
download = true;
} catch (IOException e) {
Logging.LOG.log(Level.WARNING, "Unable to calc hash value of file " + file.toPath(), e);
Logging.LOG.log(Level.WARNING, "Unable to calc hash value of file " + file, e);
}
if (download) {
List<URL> urls = dependencyManager.getDownloadProvider().getAssetObjectCandidates(assetObject.getLocation());
FileDownloadTask task = new FileDownloadTask(urls, file, new FileDownloadTask.IntegrityCheck("SHA-1", assetObject.getHash()));
FileDownloadTask task = new FileDownloadTask(urls, file.toFile(), new FileDownloadTask.IntegrityCheck("SHA-1", assetObject.getHash()));
task.setName(assetObject.getHash());
task.setCandidate(dependencyManager.getCacheRepository().getCommonDirectory()
.resolve("assets").resolve("objects").resolve(assetObject.getLocation()));
@ -112,7 +113,7 @@ public final class GameAssetDownloadTask extends Task<Void> {
task.setCaching(true);
dependencies.add(task.withCounter("hmcl.install.assets"));
} else {
dependencyManager.getCacheRepository().tryCacheFile(file.toPath(), CacheRepository.SHA1, assetObject.getHash());
dependencyManager.getCacheRepository().tryCacheFile(file, CacheRepository.SHA1, assetObject.getHash());
}
updateProgress(++progress, index.getObjects().size());

View File

@ -30,8 +30,9 @@ import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
@ -71,14 +72,14 @@ public final class GameAssetIndexDownloadTask extends Task<Void> {
@Override
public void execute() {
AssetIndexInfo assetIndexInfo = version.getAssetIndex();
File assetIndexFile = dependencyManager.getGameRepository().getIndexFile(version.getId(), assetIndexInfo.getId());
Path assetIndexFile = dependencyManager.getGameRepository().getIndexFile(version.getId(), assetIndexInfo.getId());
boolean verifyHashCode = StringUtils.isNotBlank(assetIndexInfo.getSha1()) && assetIndexInfo.getUrl().contains(assetIndexInfo.getSha1());
if (assetIndexFile.exists() && !forceDownloading) {
if (Files.exists(assetIndexFile) && !forceDownloading) {
// verify correctness of file content
if (verifyHashCode) {
try {
String actualSum = Hex.encodeHex(DigestUtils.digest("SHA-1", assetIndexFile.toPath()));
String actualSum = Hex.encodeHex(DigestUtils.digest("SHA-1", assetIndexFile));
if (actualSum.equalsIgnoreCase(assetIndexInfo.getSha1()))
return;
} catch (IOException e) {
@ -98,7 +99,7 @@ public final class GameAssetIndexDownloadTask extends Task<Void> {
// And Mojang will modify this file anytime. So assetIndex.hash might be outdated.
FileDownloadTask task = new FileDownloadTask(
dependencyManager.getDownloadProvider().injectURLWithCandidates(assetIndexInfo.getUrl()),
assetIndexFile,
assetIndexFile.toFile(),
verifyHashCode ? new FileDownloadTask.IntegrityCheck("SHA-1", assetIndexInfo.getSha1()) : null
);
task.setCacheRepository(dependencyManager.getCacheRepository());

View File

@ -382,7 +382,7 @@ public class DefaultGameRepository implements GameRepository {
}
@Override
public File getActualAssetDirectory(String version, String assetId) {
public Path getActualAssetDirectory(String version, String assetId) {
try {
return reconstructAssets(version, assetId);
} catch (IOException | JsonParseException e) {
@ -392,14 +392,16 @@ public class DefaultGameRepository implements GameRepository {
}
@Override
public File getAssetDirectory(String version, String assetId) {
return new File(getBaseDirectory(), "assets");
public Path getAssetDirectory(String version, String assetId) {
return getBaseDirectory().toPath().resolve("assets");
}
@Override
public File getAssetObject(String version, String assetId, String name) throws IOException {
public Optional<Path> getAssetObject(String version, String assetId, String name) throws IOException {
try {
return getAssetObject(version, assetId, getAssetIndex(version, assetId).getObjects().get(name));
AssetObject assetObject = getAssetIndex(version, assetId).getObjects().get(name);
if (assetObject == null) return Optional.empty();
return Optional.of(getAssetObject(version, assetId, assetObject));
} catch (IOException e) {
throw e;
} catch (Exception e) {
@ -408,30 +410,30 @@ public class DefaultGameRepository implements GameRepository {
}
@Override
public File getAssetObject(String version, String assetId, AssetObject obj) {
public Path getAssetObject(String version, String assetId, AssetObject obj) {
return getAssetObject(version, getAssetDirectory(version, assetId), obj);
}
public File getAssetObject(String version, File assetDir, AssetObject obj) {
return new File(assetDir, "objects/" + obj.getLocation());
public Path getAssetObject(String version, Path assetDir, AssetObject obj) {
return assetDir.resolve("objects").resolve(obj.getLocation());
}
@Override
public File getIndexFile(String version, String assetId) {
return new File(getAssetDirectory(version, assetId), "indexes/" + assetId + ".json");
public Path getIndexFile(String version, String assetId) {
return getAssetDirectory(version, assetId).resolve("indexes").resolve(assetId + ".json");
}
@Override
public File getLoggingObject(String version, String assetId, LoggingInfo loggingInfo) {
return new File(getAssetDirectory(version, assetId), "log_configs/" + loggingInfo.getFile().getId());
public Path getLoggingObject(String version, String assetId, LoggingInfo loggingInfo) {
return getAssetDirectory(version, assetId).resolve("log_configs").resolve(loggingInfo.getFile().getId());
}
protected File reconstructAssets(String version, String assetId) throws IOException, JsonParseException {
File assetsDir = getAssetDirectory(version, assetId);
File indexFile = getIndexFile(version, assetId);
File virtualRoot = new File(new File(assetsDir, "virtual"), assetId);
protected Path reconstructAssets(String version, String assetId) throws IOException, JsonParseException {
Path assetsDir = getAssetDirectory(version, assetId);
Path indexFile = getIndexFile(version, assetId);
Path virtualRoot = assetsDir.resolve("virtual").resolve(assetId);
if (!indexFile.isFile())
if (!Files.isRegularFile(indexFile))
return assetsDir;
String assetIndexContent = FileUtils.readText(indexFile);
@ -444,11 +446,11 @@ public class DefaultGameRepository implements GameRepository {
int cnt = 0;
int tot = index.getObjects().entrySet().size();
for (Map.Entry<String, AssetObject> entry : index.getObjects().entrySet()) {
File target = new File(virtualRoot, entry.getKey());
File original = getAssetObject(version, assetsDir, entry.getValue());
if (original.exists()) {
Path target = virtualRoot.resolve(entry.getKey());
Path original = getAssetObject(version, assetsDir, entry.getValue());
if (Files.exists(original)) {
cnt++;
if (!target.isFile())
if (!Files.isRegularFile(target))
FileUtils.copyFile(original, target);
}
}

View File

@ -22,6 +22,7 @@ import org.jackhuang.hmcl.util.platform.Platform;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@ -190,7 +191,7 @@ public interface GameRepository extends VersionProvider {
* @param assetId the asset id, you can find it in {@link AssetIndexInfo#getId()} {@link Version#getAssetIndex()}
* @return the actual asset directory
*/
File getActualAssetDirectory(String version, String assetId);
Path getActualAssetDirectory(String version, String assetId);
/**
* Get the asset directory according to the asset id.
@ -199,7 +200,7 @@ public interface GameRepository extends VersionProvider {
* @param assetId the asset id, you can find it in {@link AssetIndexInfo#getId()} {@link Version#getAssetIndex()}
* @return the asset directory
*/
File getAssetDirectory(String version, String assetId);
Path getAssetDirectory(String version, String assetId);
/**
* Get the file that given asset object refers to
@ -210,7 +211,7 @@ public interface GameRepository extends VersionProvider {
* @throws java.io.IOException if I/O operation fails.
* @return the file that given asset object refers to
*/
File getAssetObject(String version, String assetId, String name) throws IOException;
Optional<Path> getAssetObject(String version, String assetId, String name) throws IOException;
/**
* Get the file that given asset object refers to
@ -220,7 +221,7 @@ public interface GameRepository extends VersionProvider {
* @param obj the asset object, you can find it in {@link AssetIndex#getObjects()}
* @return the file that given asset object refers to
*/
File getAssetObject(String version, String assetId, AssetObject obj);
Path getAssetObject(String version, String assetId, AssetObject obj);
/**
* Get asset index that assetId represents
@ -237,7 +238,7 @@ public interface GameRepository extends VersionProvider {
* @param version the id of specific version that is relevant to {@code assetId}
* @param assetId the asset id, you can find it in {@link AssetIndexInfo#getId()} {@link Version#getAssetIndex()}
*/
File getIndexFile(String version, String assetId);
Path getIndexFile(String version, String assetId);
/**
* Get logging object
@ -247,7 +248,7 @@ public interface GameRepository extends VersionProvider {
* @param loggingInfo the logging info
* @return the file that loggingInfo refers to
*/
File getLoggingObject(String version, String assetId, LoggingInfo loggingInfo);
Path getLoggingObject(String version, String assetId, LoggingInfo loggingInfo);
default List<String> getClasspath(Version version) {
List<String> classpath = new ArrayList<>();

View File

@ -44,6 +44,7 @@ import java.net.Proxy;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Supplier;
@ -120,7 +121,10 @@ public class DefaultLauncher extends Launcher {
if (OperatingSystem.CURRENT_OS == OperatingSystem.OSX) {
res.addDefault("-Xdock:name=", "Minecraft " + version.getId());
res.addDefault("-Xdock:icon=", repository.getAssetObject(version.getId(), version.getAssetIndex().getId(), "icons/minecraft.icns").getAbsolutePath());
repository.getAssetObject(version.getId(), version.getAssetIndex().getId(), "icons/minecraft.icns")
.ifPresent(minecraftIcns -> {
res.addDefault("-Xdock:icon=", minecraftIcns.toAbsolutePath().toString());
});
}
if (OperatingSystem.CURRENT_OS != OperatingSystem.WINDOWS)
@ -201,12 +205,12 @@ public class DefaultLauncher extends Launcher {
classpath.add(jar.getAbsolutePath());
// Provided Minecraft arguments
File gameAssets = repository.getActualAssetDirectory(version.getId(), version.getAssetIndex().getId());
Path gameAssets = repository.getActualAssetDirectory(version.getId(), version.getAssetIndex().getId());
Map<String, String> configuration = getConfigurations();
configuration.put("${classpath}", String.join(OperatingSystem.PATH_SEPARATOR, classpath));
configuration.put("${natives_directory}", nativeFolder.getAbsolutePath());
configuration.put("${game_assets}", gameAssets.getAbsolutePath());
configuration.put("${assets_root}", gameAssets.getAbsolutePath());
configuration.put("${game_assets}", gameAssets.toAbsolutePath().toString());
configuration.put("${assets_root}", gameAssets.toAbsolutePath().toString());
res.addAll(Arguments.parseArguments(version.getArguments().map(Arguments::getJvm).orElseGet(this::getDefaultJVMArguments), configuration));
if (authInfo.getArguments() != null && authInfo.getArguments().getJvm() != null && !authInfo.getArguments().getJvm().isEmpty())