将 GameRepository 从 java.io.File 迁移至 NIO (#4496)
https://github.com/HMCL-dev/HMCL/issues/2987
This commit is contained in:
@@ -28,9 +28,10 @@ import org.jackhuang.hmcl.game.DefaultGameRepository;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
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.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -79,11 +80,11 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
|
||||
public Task<?> checkGameCompletionAsync(Version version, boolean integrityCheck) {
|
||||
return Task.allOf(
|
||||
Task.composeAsync(() -> {
|
||||
File versionJar = repository.getVersionJar(version);
|
||||
if (!versionJar.exists() || versionJar.length() == 0)
|
||||
return new GameDownloadTask(this, null, version);
|
||||
else
|
||||
return null;
|
||||
Path versionJar = repository.getVersionJar(version);
|
||||
|
||||
return Files.notExists(versionJar) || FileUtils.size(versionJar) == 0L
|
||||
? new GameDownloadTask(this, null, version)
|
||||
: null;
|
||||
}).thenComposeAsync(checkPatchCompletionAsync(version, integrityCheck)),
|
||||
new GameAssetDownloadTask(this, version, GameAssetDownloadTask.DOWNLOAD_INDEX_IF_NECESSARY, integrityCheck)
|
||||
.setSignificance(Task.TaskSignificance.MODERATE),
|
||||
@@ -134,7 +135,7 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
|
||||
if (GameLibrariesTask.shouldDownloadLibrary(repository, version, installer, integrityCheck)) {
|
||||
tasks.add(installLibraryAsync(gameVersion, original, "optifine", optifinePatchVersion));
|
||||
} else {
|
||||
tasks.add(OptiFineInstallTask.install(this, original, repository.getLibraryFile(version, installer).toPath()));
|
||||
tasks.add(OptiFineInstallTask.install(this, original, repository.getLibraryFile(version, installer)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ public class MaintainTask extends Task<Version> {
|
||||
optiFine.ifPresent(library -> {
|
||||
builder.addJvmArgument("-Dhmcl.transformer.candidates=${library_directory}/" + library.getPath());
|
||||
if (!libraryExisting) builder.addLibrary(hmclTransformerDiscoveryService);
|
||||
Path libraryPath = repository.getLibraryFile(version, hmclTransformerDiscoveryService).toPath();
|
||||
Path libraryPath = repository.getLibraryFile(version, hmclTransformerDiscoveryService);
|
||||
try (InputStream input = MaintainTask.class.getResourceAsStream("/assets/game/HMCLTransformerDiscoveryService-1.0.jar")) {
|
||||
Files.createDirectories(libraryPath.getParent());
|
||||
Files.copy(Objects.requireNonNull(input, "Bundled HMCLTransformerDiscoveryService is missing."), libraryPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
@@ -181,7 +181,7 @@ public class MaintainTask extends Task<Version> {
|
||||
// we need to manually ignore ${primary_jar}.
|
||||
newIgnoreList.add("${primary_jar}");
|
||||
|
||||
Path libraryDirectory = repository.getLibrariesDirectory(version).toPath().toAbsolutePath();
|
||||
Path libraryDirectory = repository.getLibrariesDirectory(version).toAbsolutePath().normalize();
|
||||
|
||||
// The default ignoreList is too loose and may cause some problems, we replace them with the absolute version.
|
||||
// For example, if "client-extra" is in ignoreList, and game directory contains "client-extra" component, all
|
||||
@@ -260,7 +260,7 @@ public class MaintainTask extends Task<Version> {
|
||||
Library library = libraries.get(i);
|
||||
if (library.is("optifine", "OptiFine")) {
|
||||
Library newLibrary = new Library(new Artifact("optifine", "OptiFine", library.getVersion(), "installer"));
|
||||
if (repository.getLibraryFile(version, newLibrary).exists()) {
|
||||
if (Files.exists(repository.getLibraryFile(version, newLibrary))) {
|
||||
libraries.set(i, null);
|
||||
// OptiFine should be loaded after Forge in classpath.
|
||||
// Although we have altered priority of OptiFine higher than Forge,
|
||||
|
||||
@@ -59,7 +59,7 @@ public final class FabricAPIInstallTask extends Task<Version> {
|
||||
public void execute() throws IOException {
|
||||
dependencies.add(new FileDownloadTask(
|
||||
remote.getVersion().getFile().getUrl(),
|
||||
dependencyManager.getGameRepository().getRunDirectory(version.getId()).toPath().resolve("mods").resolve("fabric-api-" + remote.getVersion().getVersion() + ".jar"),
|
||||
dependencyManager.getGameRepository().getRunDirectory(version.getId()).resolve("mods").resolve("fabric-api-" + remote.getVersion().getVersion() + ".jar"),
|
||||
remote.getVersion().getFile().getIntegrityCheck())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ public class ForgeNewInstallTask extends Task<Version> {
|
||||
for (Library library : profile.getLibraries()) {
|
||||
Path file = fs.getPath("maven").resolve(library.getPath());
|
||||
if (Files.exists(file)) {
|
||||
Path dest = gameRepository.getLibraryFile(version, library).toPath();
|
||||
Path dest = gameRepository.getLibraryFile(version, library);
|
||||
FileUtils.copyFile(file, dest);
|
||||
}
|
||||
}
|
||||
@@ -391,11 +391,11 @@ public class ForgeNewInstallTask extends Task<Version> {
|
||||
}
|
||||
|
||||
vars.put("SIDE", "client");
|
||||
vars.put("MINECRAFT_JAR", gameRepository.getVersionJar(version).getAbsolutePath());
|
||||
vars.put("MINECRAFT_VERSION", gameRepository.getVersionJar(version).getAbsolutePath());
|
||||
vars.put("ROOT", gameRepository.getBaseDirectory().getAbsolutePath());
|
||||
vars.put("MINECRAFT_JAR", FileUtils.getAbsolutePath(gameRepository.getVersionJar(version)));
|
||||
vars.put("MINECRAFT_VERSION", FileUtils.getAbsolutePath(gameRepository.getVersionJar(version)));
|
||||
vars.put("ROOT", FileUtils.getAbsolutePath(gameRepository.getBaseDirectory()));
|
||||
vars.put("INSTALLER", installer.toAbsolutePath().toString());
|
||||
vars.put("LIBRARY_DIR", gameRepository.getLibrariesDirectory(version).getAbsolutePath());
|
||||
vars.put("LIBRARY_DIR", FileUtils.getAbsolutePath(gameRepository.getLibrariesDirectory(version)));
|
||||
|
||||
updateProgress(0, processors.size());
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ public class ForgeOldInstallTask extends Task<Version> {
|
||||
|
||||
// unpack the universal jar in the installer file.
|
||||
Library forgeLibrary = new Library(installProfile.getInstall().getPath());
|
||||
Path forgeFile = dependencyManager.getGameRepository().getLibraryFile(version, forgeLibrary).toPath();
|
||||
Path forgeFile = dependencyManager.getGameRepository().getLibraryFile(version, forgeLibrary);
|
||||
Files.createDirectories(forgeFile.getParent());
|
||||
|
||||
ZipEntry forgeEntry = zipFile.getEntry(installProfile.getInstall().getFilePath());
|
||||
|
||||
@@ -53,7 +53,7 @@ public final class GameDownloadTask extends Task<Void> {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
Path jar = dependencyManager.getGameRepository().getVersionJar(version).toPath();
|
||||
Path jar = dependencyManager.getGameRepository().getVersionJar(version);
|
||||
|
||||
var task = new FileDownloadTask(
|
||||
dependencyManager.getDownloadProvider().injectURLWithCandidates(version.getDownloadInfo().getUrl()),
|
||||
|
||||
@@ -88,7 +88,7 @@ public final class GameLibrariesTask extends Task<Void> {
|
||||
}
|
||||
|
||||
public static boolean shouldDownloadLibrary(GameRepository gameRepository, Version version, Library library, boolean integrityCheck) {
|
||||
Path file = gameRepository.getLibraryFile(version, library).toPath();
|
||||
Path file = gameRepository.getLibraryFile(version, library);
|
||||
if (!Files.isRegularFile(file)) return true;
|
||||
|
||||
if (!integrityCheck) {
|
||||
@@ -142,8 +142,7 @@ public final class GameLibrariesTask extends Task<Void> {
|
||||
&& gameRepository instanceof DefaultGameRepository defaultGameRepository) {
|
||||
List<FMLLib> fmlLibs = getFMLLibs(library.getVersion());
|
||||
if (fmlLibs != null) {
|
||||
Path libDir = defaultGameRepository.getBaseDirectory().toPath()
|
||||
.resolve("lib")
|
||||
Path libDir = defaultGameRepository.getBaseDirectory().resolve("lib")
|
||||
.toAbsolutePath().normalize();
|
||||
|
||||
for (FMLLib fmlLib : fmlLibs) {
|
||||
@@ -158,7 +157,7 @@ public final class GameLibrariesTask extends Task<Void> {
|
||||
}
|
||||
}
|
||||
|
||||
Path file = gameRepository.getLibraryFile(version, library).toPath();
|
||||
Path file = gameRepository.getLibraryFile(version, library);
|
||||
if ("optifine".equals(library.getGroupId()) && Files.exists(file) && GameVersionNumber.asGameVersion(gameRepository.getGameVersion(version)).compareTo("1.20.4") == 0) {
|
||||
String forgeVersion = LibraryAnalyzer.analyze(version, "1.20.4")
|
||||
.getVersion(LibraryAnalyzer.LibraryType.FORGE)
|
||||
|
||||
@@ -62,7 +62,7 @@ public final class GameVerificationFixTask extends Task<Void> {
|
||||
|
||||
@Override
|
||||
public void execute() throws IOException {
|
||||
Path jar = dependencyManager.getGameRepository().getVersionJar(version).toPath();
|
||||
Path jar = dependencyManager.getGameRepository().getVersionJar(version);
|
||||
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version, gameVersion);
|
||||
|
||||
if (Files.exists(jar) && GameVersionNumber.compare(gameVersion, "1.6") < 0 && analyzer.has(LibraryAnalyzer.LibraryType.FORGE)) {
|
||||
|
||||
@@ -51,7 +51,7 @@ public final class VersionJsonSaveTask extends Task<Version> {
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
Path json = repository.getVersionJson(version.getId()).toPath().toAbsolutePath();
|
||||
Path json = repository.getVersionJson(version.getId()).toAbsolutePath();
|
||||
Files.createDirectories(json.getParent());
|
||||
JsonUtils.writeToJsonFile(json, version);
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ public class NeoForgeOldInstallTask extends Task<Version> {
|
||||
for (Library library : profile.getLibraries()) {
|
||||
Path file = fs.getPath("maven").resolve(library.getPath());
|
||||
if (Files.exists(file)) {
|
||||
Path dest = gameRepository.getLibraryFile(version, library).toPath();
|
||||
Path dest = gameRepository.getLibraryFile(version, library);
|
||||
FileUtils.copyFile(file, dest);
|
||||
}
|
||||
}
|
||||
@@ -387,11 +387,11 @@ public class NeoForgeOldInstallTask extends Task<Version> {
|
||||
}
|
||||
|
||||
vars.put("SIDE", "client");
|
||||
vars.put("MINECRAFT_JAR", gameRepository.getVersionJar(version).getAbsolutePath());
|
||||
vars.put("MINECRAFT_VERSION", gameRepository.getVersionJar(version).getAbsolutePath());
|
||||
vars.put("ROOT", gameRepository.getBaseDirectory().getAbsolutePath());
|
||||
vars.put("MINECRAFT_JAR", FileUtils.getAbsolutePath(gameRepository.getVersionJar(version)));
|
||||
vars.put("MINECRAFT_VERSION", FileUtils.getAbsolutePath(gameRepository.getVersionJar(version)));
|
||||
vars.put("ROOT", FileUtils.getAbsolutePath(gameRepository.getBaseDirectory()));
|
||||
vars.put("INSTALLER", installer.toAbsolutePath().toString());
|
||||
vars.put("LIBRARY_DIR", gameRepository.getLibrariesDirectory(version).getAbsolutePath());
|
||||
vars.put("LIBRARY_DIR", FileUtils.getAbsolutePath(gameRepository.getLibrariesDirectory(version)));
|
||||
|
||||
updateProgress(0, processors.size());
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.jenkinsci.constant_pool_scanner.ConstantPoolScanner;
|
||||
import org.jenkinsci.constant_pool_scanner.ConstantType;
|
||||
import org.jenkinsci.constant_pool_scanner.Utf8Constant;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Files;
|
||||
@@ -131,7 +130,7 @@ public final class OptiFineInstallTask extends Task<Version> {
|
||||
List<Library> libraries = new ArrayList<>(4);
|
||||
libraries.add(optiFineLibrary);
|
||||
|
||||
Path optiFineInstallerLibraryPath = gameRepository.getLibraryFile(version, optiFineInstallerLibrary).toPath();
|
||||
Path optiFineInstallerLibraryPath = gameRepository.getLibraryFile(version, optiFineInstallerLibrary);
|
||||
FileUtils.copyFile(dest, optiFineInstallerLibraryPath);
|
||||
|
||||
try (FileSystem fs2 = CompressingUtils.createWritableZipFileSystem(optiFineInstallerLibraryPath)) {
|
||||
@@ -141,14 +140,14 @@ public final class OptiFineInstallTask extends Task<Version> {
|
||||
// Install launch wrapper modified by OptiFine
|
||||
boolean hasLaunchWrapper = false;
|
||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(dest)) {
|
||||
Path optiFineLibraryPath = gameRepository.getLibraryFile(version, optiFineLibrary).toPath();
|
||||
Path optiFineLibraryPath = gameRepository.getLibraryFile(version, optiFineLibrary);
|
||||
if (Files.exists(fs.getPath("optifine/Patcher.class"))) {
|
||||
String[] command = {
|
||||
JavaRuntime.getDefault().getBinary().toString(),
|
||||
"-cp",
|
||||
dest.toString(),
|
||||
"optifine.Patcher",
|
||||
gameRepository.getVersionJar(version).getAbsolutePath(),
|
||||
gameRepository.getVersionJar(version).toAbsolutePath().normalize().toString(),
|
||||
dest.toString(),
|
||||
optiFineLibraryPath.toString()
|
||||
};
|
||||
@@ -166,9 +165,9 @@ public final class OptiFineInstallTask extends Task<Version> {
|
||||
Path launchWrapper2 = fs.getPath("launchwrapper-2.0.jar");
|
||||
if (Files.exists(launchWrapper2)) {
|
||||
Library launchWrapper = new Library(new Artifact("optifine", "launchwrapper", "2.0"));
|
||||
File launchWrapperFile = gameRepository.getLibraryFile(version, launchWrapper);
|
||||
Files.createDirectories(launchWrapperFile.toPath().toAbsolutePath().getParent());
|
||||
FileUtils.copyFile(launchWrapper2, launchWrapperFile.toPath());
|
||||
Path launchWrapperFile = gameRepository.getLibraryFile(version, launchWrapper);
|
||||
Files.createDirectories(launchWrapperFile.toAbsolutePath().getParent());
|
||||
FileUtils.copyFile(launchWrapper2, launchWrapperFile);
|
||||
hasLaunchWrapper = true;
|
||||
libraries.add(launchWrapper);
|
||||
}
|
||||
@@ -181,9 +180,9 @@ public final class OptiFineInstallTask extends Task<Version> {
|
||||
Library launchWrapper = new Library(new Artifact("optifine", "launchwrapper-of", launchWrapperVersion));
|
||||
|
||||
if (Files.exists(launchWrapperJar)) {
|
||||
File launchWrapperFile = gameRepository.getLibraryFile(version, launchWrapper);
|
||||
Files.createDirectories(launchWrapperFile.toPath().toAbsolutePath().getParent());
|
||||
FileUtils.copyFile(launchWrapperJar, launchWrapperFile.toPath());
|
||||
Path launchWrapperFile = gameRepository.getLibraryFile(version, launchWrapper);
|
||||
Files.createDirectories(launchWrapperFile.toAbsolutePath().getParent());
|
||||
FileUtils.copyFile(launchWrapperJar, launchWrapperFile);
|
||||
|
||||
hasLaunchWrapper = true;
|
||||
libraries.add(launchWrapper);
|
||||
|
||||
@@ -59,7 +59,7 @@ public final class QuiltAPIInstallTask extends Task<Version> {
|
||||
public void execute() throws IOException {
|
||||
dependencies.add(new FileDownloadTask(
|
||||
remote.getVersion().getFile().getUrl(),
|
||||
dependencyManager.getGameRepository().getRunDirectory(version.getId()).toPath().resolve("mods").resolve("quilt-api-" + remote.getVersion().getVersion() + ".jar"),
|
||||
dependencyManager.getGameRepository().getRunDirectory(version.getId()).resolve("mods").resolve("quilt-api-" + remote.getVersion().getVersion() + ".jar"),
|
||||
remote.getVersion().getFile().getIntegrityCheck())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,16 +17,15 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* The Minecraft version for 1.5.x and earlier.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class ClassicVersion extends Version {
|
||||
/// The Minecraft version for 1.5.x and earlier.
|
||||
///
|
||||
/// @author huangyuhui
|
||||
public final class ClassicVersion extends Version {
|
||||
|
||||
public ClassicVersion() {
|
||||
super(true, "Classic", null, null, "${auth_player_name} ${auth_session} --workDir ${game_directory}",
|
||||
@@ -35,8 +34,7 @@ public class ClassicVersion extends Version {
|
||||
null, null, null, ReleaseType.UNKNOWN, Instant.now(), Instant.now(), 0, false, false, null);
|
||||
}
|
||||
|
||||
private static class ClassicLibrary extends Library {
|
||||
|
||||
private static final class ClassicLibrary extends Library {
|
||||
public ClassicLibrary(String name) {
|
||||
super(new Artifact("", "", ""), null,
|
||||
new LibrariesDownloadInfo(new LibraryDownloadInfo("bin/" + name + ".jar"), null),
|
||||
@@ -44,11 +42,11 @@ public class ClassicVersion extends Version {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasClassicVersion(File baseDirectory) {
|
||||
File bin = new File(baseDirectory, "bin");
|
||||
return bin.exists()
|
||||
&& new File(bin, "lwjgl.jar").exists()
|
||||
&& new File(bin, "jinput.jar").exists()
|
||||
&& new File(bin, "lwjgl_util.jar").exists();
|
||||
public static boolean hasClassicVersion(Path baseDirectory) {
|
||||
Path bin = baseDirectory.resolve("bin");
|
||||
return Files.isDirectory(bin)
|
||||
&& Files.exists(bin.resolve("lwjgl.jar"))
|
||||
&& Files.exists(bin.resolve("jinput.jar"))
|
||||
&& Files.exists(bin.resolve("lwjgl_util.jar"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,11 +32,11 @@ import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.platform.Platform;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Stream;
|
||||
@@ -50,19 +50,19 @@ import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
*/
|
||||
public class DefaultGameRepository implements GameRepository {
|
||||
|
||||
private File baseDirectory;
|
||||
private Path baseDirectory;
|
||||
protected Map<String, Version> versions;
|
||||
private final ConcurrentHashMap<File, Optional<String>> gameVersions = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<Path, Optional<String>> gameVersions = new ConcurrentHashMap<>();
|
||||
|
||||
public DefaultGameRepository(File baseDirectory) {
|
||||
public DefaultGameRepository(Path baseDirectory) {
|
||||
this.baseDirectory = baseDirectory;
|
||||
}
|
||||
|
||||
public File getBaseDirectory() {
|
||||
public Path getBaseDirectory() {
|
||||
return baseDirectory;
|
||||
}
|
||||
|
||||
public void setBaseDirectory(File baseDirectory) {
|
||||
public void setBaseDirectory(Path baseDirectory) {
|
||||
this.baseDirectory = baseDirectory;
|
||||
}
|
||||
|
||||
@@ -89,25 +89,25 @@ public class DefaultGameRepository implements GameRepository {
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getLibrariesDirectory(Version version) {
|
||||
return new File(getBaseDirectory(), "libraries");
|
||||
public Path getLibrariesDirectory(Version version) {
|
||||
return getBaseDirectory().resolve("libraries");
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getLibraryFile(Version version, Library lib) {
|
||||
public Path getLibraryFile(Version version, Library lib) {
|
||||
if ("local".equals(lib.getHint())) {
|
||||
if (lib.getFileName() != null) {
|
||||
return new File(getVersionRoot(version.getId()), "libraries/" + lib.getFileName());
|
||||
return getVersionRoot(version.getId()).resolve("libraries/" + lib.getFileName());
|
||||
}
|
||||
|
||||
return new File(getVersionRoot(version.getId()), "libraries/" + lib.getArtifact().getFileName());
|
||||
return getVersionRoot(version.getId()).resolve("libraries/" + lib.getArtifact().getFileName());
|
||||
}
|
||||
|
||||
return new File(getLibrariesDirectory(version), lib.getPath());
|
||||
return getLibrariesDirectory(version).resolve(lib.getPath());
|
||||
}
|
||||
|
||||
public Path getArtifactFile(Version version, Artifact artifact) {
|
||||
return artifact.getPath(getBaseDirectory().toPath().resolve("libraries"));
|
||||
return artifact.getPath(getBaseDirectory().resolve("libraries"));
|
||||
}
|
||||
|
||||
public GameDirectoryType getGameDirectoryType(String id) {
|
||||
@@ -115,22 +115,19 @@ public class DefaultGameRepository implements GameRepository {
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getRunDirectory(String id) {
|
||||
switch (getGameDirectoryType(id)) {
|
||||
case VERSION_FOLDER:
|
||||
return getVersionRoot(id);
|
||||
case ROOT_FOLDER:
|
||||
return getBaseDirectory();
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
public Path getRunDirectory(String id) {
|
||||
return switch (getGameDirectoryType(id)) {
|
||||
case VERSION_FOLDER -> getVersionRoot(id);
|
||||
case ROOT_FOLDER -> getBaseDirectory();
|
||||
default -> throw new IllegalStateException();
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getVersionJar(Version version) {
|
||||
public Path getVersionJar(Version version) {
|
||||
Version v = version.resolve(this);
|
||||
String id = Optional.ofNullable(v.getJar()).orElse(v.getId());
|
||||
return new File(getVersionRoot(id), id + ".jar");
|
||||
return getVersionRoot(id).resolve(id + ".jar");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -140,33 +137,33 @@ public class DefaultGameRepository implements GameRepository {
|
||||
// be consistent.
|
||||
return gameVersions.computeIfAbsent(getVersionJar(version), versionJar -> {
|
||||
Optional<String> gameVersion = GameVersion.minecraftVersion(versionJar);
|
||||
if (!gameVersion.isPresent()) {
|
||||
LOG.warning("Cannot find out game version of " + version.getId() + ", primary jar: " + versionJar.toString() + ", jar exists: " + versionJar.exists());
|
||||
if (gameVersion.isEmpty()) {
|
||||
LOG.warning("Cannot find out game version of " + version.getId() + ", primary jar: " + versionJar.toString() + ", jar exists: " + Files.exists(versionJar));
|
||||
}
|
||||
return gameVersion;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getNativeDirectory(String id, Platform platform) {
|
||||
return new File(getVersionRoot(id), "natives-" + platform);
|
||||
public Path getNativeDirectory(String id, Platform platform) {
|
||||
return getVersionRoot(id).resolve("natives-" + platform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getVersionRoot(String id) {
|
||||
return new File(getBaseDirectory(), "versions/" + id);
|
||||
public Path getVersionRoot(String id) {
|
||||
return getBaseDirectory().resolve("versions/" + id);
|
||||
}
|
||||
|
||||
public File getVersionJson(String id) {
|
||||
return new File(getVersionRoot(id), id + ".json");
|
||||
public Path getVersionJson(String id) {
|
||||
return getVersionRoot(id).resolve(id + ".json");
|
||||
}
|
||||
|
||||
public Version readVersionJson(String id) throws IOException, JsonParseException {
|
||||
return readVersionJson(getVersionJson(id));
|
||||
}
|
||||
|
||||
public Version readVersionJson(File file) throws IOException, JsonParseException {
|
||||
String jsonText = Files.readString(file.toPath());
|
||||
public Version readVersionJson(Path file) throws IOException, JsonParseException {
|
||||
String jsonText = Files.readString(file);
|
||||
try {
|
||||
// Try TLauncher version json format
|
||||
return JsonUtils.fromNonNullJson(jsonText, TLauncherVersion.class).toVersion();
|
||||
@@ -179,7 +176,7 @@ public class DefaultGameRepository implements GameRepository {
|
||||
} catch (JsonParseException ignored) {
|
||||
}
|
||||
|
||||
LOG.warning("Cannot parse version json: " + file.toString() + "\n" + jsonText);
|
||||
LOG.warning("Cannot parse version json: " + file + "\n" + jsonText);
|
||||
throw new JsonParseException("Version json incorrect");
|
||||
}
|
||||
|
||||
@@ -190,8 +187,8 @@ public class DefaultGameRepository implements GameRepository {
|
||||
|
||||
try {
|
||||
Version fromVersion = getVersion(from);
|
||||
Path fromDir = getVersionRoot(from).toPath();
|
||||
Path toDir = getVersionRoot(to).toPath();
|
||||
Path fromDir = getVersionRoot(from);
|
||||
Path toDir = getVersionRoot(to);
|
||||
Files.move(fromDir, toDir);
|
||||
|
||||
Path fromJson = toDir.resolve(from + ".json");
|
||||
@@ -219,7 +216,7 @@ public class DefaultGameRepository implements GameRepository {
|
||||
// fix inheritsFrom of versions that inherits from version [from].
|
||||
for (Version version : getVersions()) {
|
||||
if (from.equals(version.getInheritsFrom())) {
|
||||
Path targetPath = getVersionJson(version.getId()).toPath();
|
||||
Path targetPath = getVersionJson(version.getId());
|
||||
Files.createDirectories(targetPath.getParent());
|
||||
JsonUtils.writeToJsonFile(targetPath, version.setInheritsFrom(to));
|
||||
}
|
||||
@@ -235,25 +232,29 @@ public class DefaultGameRepository implements GameRepository {
|
||||
if (EventBus.EVENT_BUS.fireEvent(new RemoveVersionEvent(this, id)) == Event.Result.DENY)
|
||||
return false;
|
||||
if (!versions.containsKey(id))
|
||||
return FileUtils.deleteDirectoryQuietly(getVersionRoot(id).toPath());
|
||||
File file = getVersionRoot(id);
|
||||
if (!file.exists())
|
||||
return FileUtils.deleteDirectoryQuietly(getVersionRoot(id));
|
||||
Path file = getVersionRoot(id);
|
||||
if (Files.notExists(file))
|
||||
return true;
|
||||
// test if no file in this version directory is occupied.
|
||||
File removedFile = new File(file.getAbsoluteFile().getParentFile(), file.getName() + "_removed");
|
||||
if (!file.renameTo(removedFile))
|
||||
Path removedFile = file.toAbsolutePath().resolveSibling(FileUtils.getName(file) + "_removed");
|
||||
try {
|
||||
Files.move(file, removedFile, StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Failed to rename file " + file, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
versions.remove(id);
|
||||
|
||||
if (FileUtils.moveToTrash(removedFile.toPath())) {
|
||||
if (FileUtils.moveToTrash(removedFile)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// remove json files first to ensure HMCL will not recognize this folder as a valid version.
|
||||
|
||||
for (Path path : FileUtils.listFilesByExtension(removedFile.toPath(), "json")) {
|
||||
for (Path path : FileUtils.listFilesByExtension(removedFile, "json")) {
|
||||
try {
|
||||
Files.delete(path);
|
||||
} catch (IOException e) {
|
||||
@@ -263,7 +264,7 @@ public class DefaultGameRepository implements GameRepository {
|
||||
|
||||
// remove the version from version list regardless of whether the directory was removed successfully or not.
|
||||
try {
|
||||
FileUtils.deleteDirectory(removedFile.toPath());
|
||||
FileUtils.deleteDirectory(removedFile);
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Unable to remove version folder: " + file, e);
|
||||
}
|
||||
@@ -283,83 +284,95 @@ public class DefaultGameRepository implements GameRepository {
|
||||
|
||||
SimpleVersionProvider provider = new SimpleVersionProvider();
|
||||
|
||||
File[] files = new File(getBaseDirectory(), "versions").listFiles();
|
||||
if (files != null)
|
||||
Arrays.stream(files).parallel().filter(File::isDirectory).flatMap(dir -> {
|
||||
String id = dir.getName();
|
||||
File json = new File(dir, id + ".json");
|
||||
Path versionsDir = getBaseDirectory().resolve("versions");
|
||||
if (Files.isDirectory(versionsDir)) {
|
||||
try (Stream<Path> stream = Files.list(versionsDir)) {
|
||||
stream.parallel().filter(Files::isDirectory).flatMap(dir -> {
|
||||
String id = FileUtils.getName(dir);
|
||||
Path json = dir.resolve(id + ".json");
|
||||
|
||||
// If user renamed the json file by mistake or created the json file in a wrong name,
|
||||
// we will find the only json and rename it to correct name.
|
||||
if (!json.exists()) {
|
||||
List<Path> jsons = FileUtils.listFilesByExtension(dir.toPath(), "json");
|
||||
if (jsons.size() == 1) {
|
||||
LOG.info("Renaming json file " + jsons.get(0) + " to " + json);
|
||||
if (!jsons.get(0).toFile().renameTo(json)) {
|
||||
LOG.warning("Cannot rename json file, ignoring version " + id);
|
||||
// If user renamed the json file by mistake or created the json file in a wrong name,
|
||||
// we will find the only json and rename it to correct name.
|
||||
if (Files.notExists(json)) {
|
||||
List<Path> jsons = FileUtils.listFilesByExtension(dir, "json");
|
||||
if (jsons.size() == 1) {
|
||||
LOG.info("Renaming json file " + jsons.get(0) + " to " + json);
|
||||
|
||||
try {
|
||||
Files.move(jsons.get(0), json);
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Cannot rename json file, ignoring version " + id, e);
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
Path jar = dir.resolve(FileUtils.getNameWithoutExtension(jsons.get(0)) + ".jar");
|
||||
if (Files.exists(jar)) {
|
||||
try {
|
||||
Files.move(jar, dir.resolve(id + ".jar"));
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Cannot rename jar file, ignoring version " + id, e);
|
||||
return Stream.empty();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG.info("No available json file found, ignoring version " + id);
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
File jar = new File(dir, FileUtils.getNameWithoutExtension(jsons.get(0)) + ".jar");
|
||||
if (jar.exists() && !jar.renameTo(new File(dir, id + ".jar"))) {
|
||||
LOG.warning("Cannot rename jar file, ignoring version " + id);
|
||||
return Stream.empty();
|
||||
}
|
||||
} else {
|
||||
LOG.info("No available json file found, ignoring version " + id);
|
||||
return Stream.empty();
|
||||
}
|
||||
}
|
||||
|
||||
Version version;
|
||||
try {
|
||||
version = readVersionJson(json);
|
||||
} catch (Exception e) {
|
||||
LOG.warning("Malformed version json " + id, e);
|
||||
// JsonSyntaxException or IOException or NullPointerException(!!)
|
||||
if (EventBus.EVENT_BUS.fireEvent(new GameJsonParseFailedEvent(this, json, id)) != Event.Result.ALLOW)
|
||||
return Stream.empty();
|
||||
|
||||
Version version;
|
||||
try {
|
||||
version = readVersionJson(json);
|
||||
} catch (Exception e2) {
|
||||
LOG.error("User corrected version json is still malformed", e2);
|
||||
return Stream.empty();
|
||||
}
|
||||
}
|
||||
|
||||
if (!id.equals(version.getId())) {
|
||||
try {
|
||||
String from = id;
|
||||
String to = version.getId();
|
||||
Path fromDir = getVersionRoot(from).toPath();
|
||||
Path toDir = getVersionRoot(to).toPath();
|
||||
Files.move(fromDir, toDir);
|
||||
|
||||
Path fromJson = toDir.resolve(from + ".json");
|
||||
Path fromJar = toDir.resolve(from + ".jar");
|
||||
Path toJson = toDir.resolve(to + ".json");
|
||||
Path toJar = toDir.resolve(to + ".jar");
|
||||
} catch (Exception e) {
|
||||
LOG.warning("Malformed version json " + id, e);
|
||||
// JsonSyntaxException or IOException or NullPointerException(!!)
|
||||
if (EventBus.EVENT_BUS.fireEvent(new GameJsonParseFailedEvent(this, json.toFile(), id)) != Event.Result.ALLOW)
|
||||
return Stream.empty();
|
||||
|
||||
try {
|
||||
Files.move(fromJson, toJson);
|
||||
if (Files.exists(fromJar))
|
||||
Files.move(fromJar, toJar);
|
||||
} catch (IOException e) {
|
||||
// recovery
|
||||
Lang.ignoringException(() -> Files.move(toJson, fromJson));
|
||||
Lang.ignoringException(() -> Files.move(toJar, fromJar));
|
||||
Lang.ignoringException(() -> Files.move(toDir, fromDir));
|
||||
throw e;
|
||||
version = readVersionJson(json);
|
||||
} catch (Exception e2) {
|
||||
LOG.error("User corrected version json is still malformed", e2);
|
||||
return Stream.empty();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Ignoring version " + version.getId() + " because version id does not match folder name " + id + ", and we cannot correct it.", e);
|
||||
return Stream.empty();
|
||||
}
|
||||
}
|
||||
|
||||
return Stream.of(version);
|
||||
}).forEachOrdered(provider::addVersion);
|
||||
if (!id.equals(version.getId())) {
|
||||
try {
|
||||
String from = id;
|
||||
String to = version.getId();
|
||||
Path fromDir = getVersionRoot(from);
|
||||
Path toDir = getVersionRoot(to);
|
||||
Files.move(fromDir, toDir);
|
||||
|
||||
Path fromJson = toDir.resolve(from + ".json");
|
||||
Path fromJar = toDir.resolve(from + ".jar");
|
||||
Path toJson = toDir.resolve(to + ".json");
|
||||
Path toJar = toDir.resolve(to + ".jar");
|
||||
|
||||
try {
|
||||
Files.move(fromJson, toJson);
|
||||
if (Files.exists(fromJar))
|
||||
Files.move(fromJar, toJar);
|
||||
} catch (IOException e) {
|
||||
// recovery
|
||||
Lang.ignoringException(() -> Files.move(toJson, fromJson));
|
||||
Lang.ignoringException(() -> Files.move(toJar, fromJar));
|
||||
Lang.ignoringException(() -> Files.move(toDir, fromDir));
|
||||
throw e;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Ignoring version " + version.getId() + " because version id does not match folder name " + id + ", and we cannot correct it.", e);
|
||||
return Stream.empty();
|
||||
}
|
||||
}
|
||||
|
||||
return Stream.of(version);
|
||||
}).forEachOrdered(provider::addVersion);
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Failed to load versions from " + versionsDir, e);
|
||||
}
|
||||
}
|
||||
|
||||
for (Version version : provider.getVersionMap().values()) {
|
||||
try {
|
||||
@@ -407,7 +420,7 @@ public class DefaultGameRepository implements GameRepository {
|
||||
|
||||
@Override
|
||||
public Path getAssetDirectory(String version, String assetId) {
|
||||
return getBaseDirectory().toPath().resolve("assets");
|
||||
return getBaseDirectory().resolve("assets");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -456,7 +469,7 @@ public class DefaultGameRepository implements GameRepository {
|
||||
return assetsDir;
|
||||
|
||||
if (index.isVirtual()) {
|
||||
Path resourcesDir = getRunDirectory(version).toPath().resolve("resources");
|
||||
Path resourcesDir = getRunDirectory(version).resolve("resources");
|
||||
|
||||
int cnt = 0;
|
||||
int tot = index.getObjects().size();
|
||||
@@ -499,8 +512,8 @@ public class DefaultGameRepository implements GameRepository {
|
||||
return versions != null;
|
||||
}
|
||||
|
||||
public File getModpackConfiguration(String version) {
|
||||
return new File(getVersionRoot(version), "modpack.json");
|
||||
public Path getModpackConfiguration(String version) {
|
||||
return getVersionRoot(version).resolve("modpack.json");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -514,13 +527,13 @@ public class DefaultGameRepository implements GameRepository {
|
||||
@Nullable
|
||||
public ModpackConfiguration<?> readModpackConfiguration(String version) throws IOException, VersionNotFoundException {
|
||||
if (!hasVersion(version)) throw new VersionNotFoundException(version);
|
||||
File file = getModpackConfiguration(version);
|
||||
if (!file.exists()) return null;
|
||||
return JsonUtils.fromJsonFile(file.toPath(), ModpackConfiguration.class);
|
||||
Path file = getModpackConfiguration(version);
|
||||
if (Files.notExists(file)) return null;
|
||||
return JsonUtils.fromJsonFile(file, ModpackConfiguration.class);
|
||||
}
|
||||
|
||||
public boolean isModpack(String version) {
|
||||
return getModpackConfiguration(version).exists();
|
||||
return Files.exists(getModpackConfiguration(version));
|
||||
}
|
||||
|
||||
public ModManager getModManager(String version) {
|
||||
@@ -528,15 +541,15 @@ public class DefaultGameRepository implements GameRepository {
|
||||
}
|
||||
|
||||
public Path getSavesDirectory(String id) {
|
||||
return getRunDirectory(id).toPath().resolve("saves");
|
||||
return getRunDirectory(id).resolve("saves");
|
||||
}
|
||||
|
||||
public Path getBackupsDirectory(String id) {
|
||||
return getRunDirectory(id).toPath().resolve("backups");
|
||||
return getRunDirectory(id).resolve("backups");
|
||||
}
|
||||
|
||||
public Path getSchematicsDirectory(String id) {
|
||||
return getRunDirectory(id).toPath().resolve("schematics");
|
||||
return getRunDirectory(id).resolve("schematics");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,10 +18,11 @@
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.platform.Platform;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -30,7 +31,7 @@ import java.util.Set;
|
||||
|
||||
/**
|
||||
* Supports operations on versioning.
|
||||
*
|
||||
* <p>
|
||||
* Note that game repository will not do any operations which need connection with Internet, if do,
|
||||
* see {@link org.jackhuang.hmcl.download.DependencyManager}
|
||||
*
|
||||
@@ -79,7 +80,7 @@ public interface GameRepository extends VersionProvider {
|
||||
|
||||
/**
|
||||
* Load version list.
|
||||
*
|
||||
* <p>
|
||||
* This method should be called before launching a version.
|
||||
* A time-costly operation.
|
||||
* You'd better execute this method in a new thread.
|
||||
@@ -95,16 +96,16 @@ public interface GameRepository extends VersionProvider {
|
||||
* The root folders the versions must be unique.
|
||||
* For example, .minecraft/versions/<version name>/.
|
||||
*/
|
||||
File getVersionRoot(String id);
|
||||
Path getVersionRoot(String id);
|
||||
|
||||
/**
|
||||
* Gets the current running directory of the given version for game.
|
||||
*
|
||||
* @param id the version id
|
||||
*/
|
||||
File getRunDirectory(String id);
|
||||
Path getRunDirectory(String id);
|
||||
|
||||
File getLibrariesDirectory(Version version);
|
||||
Path getLibrariesDirectory(Version version);
|
||||
|
||||
/**
|
||||
* Get the library file in disk.
|
||||
@@ -114,11 +115,11 @@ public interface GameRepository extends VersionProvider {
|
||||
* @param lib the library, {@link Version#getLibraries()}
|
||||
* @return the library file
|
||||
*/
|
||||
File getLibraryFile(Version version, Library lib);
|
||||
Path getLibraryFile(Version version, Library lib);
|
||||
|
||||
/**
|
||||
* Get the directory that native libraries will be unzipped to.
|
||||
*
|
||||
* <p>
|
||||
* You'd better return a unique directory.
|
||||
* Or if it returns a temporary directory, {@link org.jackhuang.hmcl.launch.Launcher#makeLaunchScript} will fail.
|
||||
* If you do want to return a temporary directory, make {@link org.jackhuang.hmcl.launch.Launcher#makeLaunchScript}
|
||||
@@ -128,7 +129,7 @@ public interface GameRepository extends VersionProvider {
|
||||
* @param platform the platform of native libraries
|
||||
* @return the native directory
|
||||
*/
|
||||
File getNativeDirectory(String id, Platform platform);
|
||||
Path getNativeDirectory(String id, Platform platform);
|
||||
|
||||
/**
|
||||
* Get minecraft jar
|
||||
@@ -136,11 +137,11 @@ public interface GameRepository extends VersionProvider {
|
||||
* @param version resolvedVersion
|
||||
* @return the minecraft jar
|
||||
*/
|
||||
File getVersionJar(Version version);
|
||||
Path getVersionJar(Version version);
|
||||
|
||||
/**
|
||||
* Detect game version.
|
||||
*
|
||||
* <p>
|
||||
* This method is time-consuming, but the result will be cached.
|
||||
* Consider running this job in IO scheduler.
|
||||
*
|
||||
@@ -151,7 +152,7 @@ public interface GameRepository extends VersionProvider {
|
||||
|
||||
/**
|
||||
* Detect game version.
|
||||
*
|
||||
* <p>
|
||||
* This method is time-consuming, but the result will be cached.
|
||||
* Consider running this job in IO scheduler.
|
||||
*
|
||||
@@ -168,7 +169,7 @@ public interface GameRepository extends VersionProvider {
|
||||
* @param version version id
|
||||
* @return the minecraft jar
|
||||
*/
|
||||
default File getVersionJar(String version) throws VersionNotFoundException {
|
||||
default Path getVersionJar(String version) throws VersionNotFoundException {
|
||||
return getVersionJar(getVersion(version).resolve(this));
|
||||
}
|
||||
|
||||
@@ -254,9 +255,9 @@ public interface GameRepository extends VersionProvider {
|
||||
Set<String> classpath = new LinkedHashSet<>();
|
||||
for (Library library : version.getLibraries())
|
||||
if (library.appliesToCurrentEnvironment() && !library.isNative()) {
|
||||
File f = getLibraryFile(version, library);
|
||||
if (f.exists() && f.isFile())
|
||||
classpath.add(f.getAbsolutePath());
|
||||
Path f = getLibraryFile(version, library);
|
||||
if (Files.isRegularFile(f))
|
||||
classpath.add(FileUtils.getAbsolutePath(f));
|
||||
}
|
||||
return classpath;
|
||||
}
|
||||
|
||||
@@ -24,9 +24,10 @@ import org.jenkinsci.constant_pool_scanner.ConstantPoolScanner;
|
||||
import org.jenkinsci.constant_pool_scanner.ConstantType;
|
||||
import org.jenkinsci.constant_pool_scanner.StringConstant;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -89,11 +90,11 @@ final class GameVersion {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public static Optional<String> minecraftVersion(File file) {
|
||||
if (file == null || !file.exists() || !file.isFile() || !file.canRead())
|
||||
public static Optional<String> minecraftVersion(Path file) {
|
||||
if (file == null || !Files.isRegularFile(file))
|
||||
return Optional.empty();
|
||||
|
||||
try (ZipFile gameJar = new ZipFile(file)) {
|
||||
try (var gameJar = new ZipFile(file.toFile())) {
|
||||
ZipEntry versionJson = gameJar.getEntry("version.json");
|
||||
if (versionJson != null) {
|
||||
Optional<String> result = getVersionFromJson(gameJar.getInputStream(versionJson));
|
||||
|
||||
@@ -20,9 +20,9 @@ package org.jackhuang.hmcl.game;
|
||||
import org.jackhuang.hmcl.java.JavaRuntime;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.net.Proxy;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@@ -31,7 +31,7 @@ import java.util.*;
|
||||
*/
|
||||
public class LaunchOptions implements Serializable {
|
||||
|
||||
private File gameDir;
|
||||
private Path gameDir;
|
||||
private JavaRuntime java;
|
||||
private String versionName;
|
||||
private String versionType;
|
||||
@@ -68,7 +68,7 @@ public class LaunchOptions implements Serializable {
|
||||
/**
|
||||
* The game directory
|
||||
*/
|
||||
public File getGameDir() {
|
||||
public Path getGameDir() {
|
||||
return gameDir;
|
||||
}
|
||||
|
||||
@@ -314,7 +314,7 @@ public class LaunchOptions implements Serializable {
|
||||
return options.javaAgents;
|
||||
}
|
||||
|
||||
public Builder setGameDir(File gameDir) {
|
||||
public Builder setGameDir(Path gameDir) {
|
||||
options.gameDir = gameDir;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -25,12 +25,14 @@ import org.jackhuang.hmcl.game.LibrariesDownloadInfo;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.game.LibraryDownloadInfo;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.gson.JsonSerializable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Immutable
|
||||
public class TLauncherLibrary {
|
||||
@JsonSerializable
|
||||
public final class TLauncherLibrary {
|
||||
|
||||
@SerializedName("name")
|
||||
private final Artifact name;
|
||||
|
||||
@@ -28,7 +28,7 @@ import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class TLauncherVersion implements Validation {
|
||||
public final class TLauncherVersion implements Validation {
|
||||
|
||||
private final String id;
|
||||
private final String minecraftArguments;
|
||||
|
||||
@@ -36,6 +36,7 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -64,7 +65,7 @@ public class DefaultLauncher extends Launcher {
|
||||
this.analyzer = LibraryAnalyzer.analyze(version, repository.getGameVersion(version).orElse(null));
|
||||
}
|
||||
|
||||
private Command generateCommandLine(File nativeFolder) throws IOException {
|
||||
private Command generateCommandLine(Path nativeFolder) throws IOException {
|
||||
CommandBuilder res = new CommandBuilder();
|
||||
|
||||
switch (options.getProcessPriority()) {
|
||||
@@ -149,25 +150,25 @@ public class DefaultLauncher extends Launcher {
|
||||
|
||||
String formatMsgNoLookups = res.addDefault("-Dlog4j2.formatMsgNoLookups=", "true");
|
||||
if (!"-Dlog4j2.formatMsgNoLookups=false".equals(formatMsgNoLookups) && isUsingLog4j()) {
|
||||
res.addDefault("-Dlog4j.configurationFile=", getLog4jConfigurationFile().getAbsolutePath());
|
||||
res.addDefault("-Dlog4j.configurationFile=", FileUtils.getAbsolutePath(getLog4jConfigurationFile()));
|
||||
}
|
||||
|
||||
// Default JVM Args
|
||||
if (!options.isNoGeneratedJVMArgs()) {
|
||||
appendJvmArgs(res);
|
||||
|
||||
res.addDefault("-Dminecraft.client.jar=", repository.getVersionJar(version).toString());
|
||||
res.addDefault("-Dminecraft.client.jar=", FileUtils.getAbsolutePath(repository.getVersionJar(version)));
|
||||
|
||||
if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS) {
|
||||
res.addDefault("-Xdock:name=", "Minecraft " + version.getId());
|
||||
repository.getAssetObject(version.getId(), version.getAssetIndex().getId(), "icons/minecraft.icns")
|
||||
.ifPresent(minecraftIcns -> {
|
||||
res.addDefault("-Xdock:icon=", minecraftIcns.toAbsolutePath().toString());
|
||||
res.addDefault("-Xdock:icon=", FileUtils.getAbsolutePath(minecraftIcns));
|
||||
});
|
||||
}
|
||||
|
||||
if (OperatingSystem.CURRENT_OS != OperatingSystem.WINDOWS)
|
||||
res.addDefault("-Duser.home=", options.getGameDir().getAbsoluteFile().getParent());
|
||||
res.addDefault("-Duser.home=", options.getGameDir().toAbsolutePath().getParent().toString());
|
||||
|
||||
Proxy.Type proxyType = options.getProxyType();
|
||||
if (proxyType == null) {
|
||||
@@ -250,23 +251,23 @@ public class DefaultLauncher extends Launcher {
|
||||
classpath.removeIf(c -> c.contains("2.9.4-nightly-20150209"));
|
||||
}
|
||||
|
||||
File jar = repository.getVersionJar(version);
|
||||
if (!jar.exists() || !jar.isFile())
|
||||
Path jar = repository.getVersionJar(version);
|
||||
if (!Files.isRegularFile(jar))
|
||||
throw new IOException("Minecraft jar does not exist");
|
||||
classpath.add(jar.getAbsolutePath());
|
||||
classpath.add(FileUtils.getAbsolutePath(jar.toAbsolutePath()));
|
||||
|
||||
// Provided Minecraft arguments
|
||||
Path gameAssets = repository.getActualAssetDirectory(version.getId(), version.getAssetIndex().getId());
|
||||
Map<String, String> configuration = getConfigurations();
|
||||
configuration.put("${classpath}", String.join(File.pathSeparator, classpath));
|
||||
configuration.put("${game_assets}", gameAssets.toAbsolutePath().toString());
|
||||
configuration.put("${assets_root}", gameAssets.toAbsolutePath().toString());
|
||||
configuration.put("${game_assets}", FileUtils.getAbsolutePath(gameAssets));
|
||||
configuration.put("${assets_root}", FileUtils.getAbsolutePath(gameAssets));
|
||||
|
||||
Optional<String> gameVersion = repository.getGameVersion(version);
|
||||
|
||||
// lwjgl assumes path to native libraries encoded by ASCII.
|
||||
// Here is a workaround for this issue: https://github.com/HMCL-dev/HMCL/issues/1141.
|
||||
String nativeFolderPath = nativeFolder.getAbsolutePath();
|
||||
String nativeFolderPath = FileUtils.getAbsolutePath(nativeFolder);
|
||||
Path tempNativeFolder = null;
|
||||
if ((OperatingSystem.CURRENT_OS == OperatingSystem.LINUX || OperatingSystem.CURRENT_OS == OperatingSystem.MACOS)
|
||||
&& !StringUtils.isASCII(nativeFolderPath)
|
||||
@@ -376,9 +377,9 @@ public class DefaultLauncher extends Launcher {
|
||||
protected void appendJvmArgs(CommandBuilder result) {
|
||||
}
|
||||
|
||||
public void decompressNatives(File destination) throws NotDecompressingNativesException {
|
||||
public void decompressNatives(Path destination) throws NotDecompressingNativesException {
|
||||
try {
|
||||
FileUtils.cleanDirectoryQuietly(destination.toPath());
|
||||
FileUtils.cleanDirectoryQuietly(destination);
|
||||
for (Library library : version.getLibraries())
|
||||
if (library.isNative())
|
||||
new Unzipper(repository.getLibraryFile(version, library), destination)
|
||||
@@ -408,12 +409,12 @@ public class DefaultLauncher extends Launcher {
|
||||
return GameVersionNumber.compare(repository.getGameVersion(version).orElse("1.7"), "1.7") >= 0;
|
||||
}
|
||||
|
||||
public File getLog4jConfigurationFile() {
|
||||
return new File(repository.getVersionRoot(version.getId()), "log4j2.xml");
|
||||
public Path getLog4jConfigurationFile() {
|
||||
return repository.getVersionRoot(version.getId()).resolve("log4j2.xml");
|
||||
}
|
||||
|
||||
public void extractLog4jConfigurationFile() throws IOException {
|
||||
File targetFile = getLog4jConfigurationFile();
|
||||
Path targetFile = getLog4jConfigurationFile();
|
||||
InputStream source;
|
||||
if (GameVersionNumber.asGameVersion(repository.getGameVersion(version)).compareTo("1.12") < 0) {
|
||||
source = DefaultLauncher.class.getResourceAsStream("/assets/game/log4j2-1.7.xml");
|
||||
@@ -421,8 +422,8 @@ public class DefaultLauncher extends Launcher {
|
||||
source = DefaultLauncher.class.getResourceAsStream("/assets/game/log4j2-1.12.xml");
|
||||
}
|
||||
|
||||
try (InputStream input = source; OutputStream output = new FileOutputStream(targetFile)) {
|
||||
input.transferTo(output);
|
||||
try (InputStream input = source) {
|
||||
Files.copy(input, targetFile, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,35 +437,35 @@ public class DefaultLauncher extends Launcher {
|
||||
pair("${version_name}", Optional.ofNullable(options.getVersionName()).orElse(version.getId())),
|
||||
pair("${profile_name}", Optional.ofNullable(options.getProfileName()).orElse("Minecraft")),
|
||||
pair("${version_type}", Optional.ofNullable(options.getVersionType()).orElse(version.getType().getId())),
|
||||
pair("${game_directory}", repository.getRunDirectory(version.getId()).getAbsolutePath()),
|
||||
pair("${game_directory}", FileUtils.getAbsolutePath(repository.getRunDirectory(version.getId()))),
|
||||
pair("${user_type}", authInfo.getUserType()),
|
||||
pair("${assets_index_name}", version.getAssetIndex().getId()),
|
||||
pair("${user_properties}", authInfo.getUserProperties()),
|
||||
pair("${resolution_width}", options.getWidth().toString()),
|
||||
pair("${resolution_height}", options.getHeight().toString()),
|
||||
pair("${library_directory}", repository.getLibrariesDirectory(version).getAbsolutePath()),
|
||||
pair("${library_directory}", FileUtils.getAbsolutePath(repository.getLibrariesDirectory(version))),
|
||||
pair("${classpath_separator}", File.pathSeparator),
|
||||
pair("${primary_jar}", repository.getVersionJar(version).getAbsolutePath()),
|
||||
pair("${primary_jar}", FileUtils.getAbsolutePath(repository.getVersionJar(version))),
|
||||
pair("${language}", Locale.getDefault().toLanguageTag()),
|
||||
|
||||
// defined by HMCL
|
||||
// libraries_directory stands for historical reasons here. We don't know the official launcher
|
||||
// had already defined "library_directory" as the placeholder for path to ".minecraft/libraries"
|
||||
// when we propose this placeholder.
|
||||
pair("${libraries_directory}", repository.getLibrariesDirectory(version).getAbsolutePath()),
|
||||
pair("${libraries_directory}", FileUtils.getAbsolutePath(repository.getLibrariesDirectory(version))),
|
||||
// file_separator is used in -DignoreList
|
||||
pair("${file_separator}", File.separator),
|
||||
pair("${primary_jar_name}", FileUtils.getName(repository.getVersionJar(version).toPath()))
|
||||
pair("${primary_jar_name}", FileUtils.getName(repository.getVersionJar(version)))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManagedProcess launch() throws IOException, InterruptedException {
|
||||
File nativeFolder;
|
||||
Path nativeFolder;
|
||||
if (options.getNativesDirType() == NativesDirectoryType.VERSION_FOLDER) {
|
||||
nativeFolder = repository.getNativeDirectory(version.getId(), options.getJava().getPlatform());
|
||||
} else {
|
||||
nativeFolder = new File(options.getNativesDir());
|
||||
nativeFolder = Path.of(options.getNativesDir());
|
||||
}
|
||||
|
||||
final Command command = generateCommandLine(nativeFolder);
|
||||
@@ -474,7 +475,7 @@ public class DefaultLauncher extends Launcher {
|
||||
|
||||
if (command.tempNativeFolder != null) {
|
||||
Files.deleteIfExists(command.tempNativeFolder);
|
||||
Files.createSymbolicLink(command.tempNativeFolder, nativeFolder.toPath().toAbsolutePath());
|
||||
Files.createSymbolicLink(command.tempNativeFolder, nativeFolder.toAbsolutePath());
|
||||
}
|
||||
|
||||
if (rawCommandLine.stream().anyMatch(StringUtils::isBlank)) {
|
||||
@@ -488,22 +489,22 @@ public class DefaultLauncher extends Launcher {
|
||||
if (isUsingLog4j())
|
||||
extractLog4jConfigurationFile();
|
||||
|
||||
File runDirectory = repository.getRunDirectory(version.getId());
|
||||
Path runDirectory = repository.getRunDirectory(version.getId());
|
||||
|
||||
if (StringUtils.isNotBlank(options.getPreLaunchCommand())) {
|
||||
ProcessBuilder builder = new ProcessBuilder(StringUtils.tokenize(options.getPreLaunchCommand(), getEnvVars())).directory(runDirectory);
|
||||
ProcessBuilder builder = new ProcessBuilder(StringUtils.tokenize(options.getPreLaunchCommand(), getEnvVars())).directory(runDirectory.toFile());
|
||||
builder.environment().putAll(getEnvVars());
|
||||
SystemUtils.callExternalProcess(builder);
|
||||
}
|
||||
|
||||
Process process;
|
||||
try {
|
||||
ProcessBuilder builder = new ProcessBuilder(rawCommandLine).directory(runDirectory);
|
||||
ProcessBuilder builder = new ProcessBuilder(rawCommandLine).directory(runDirectory.toFile());
|
||||
if (listener == null) {
|
||||
builder.inheritIO();
|
||||
}
|
||||
String appdata = options.getGameDir().getAbsoluteFile().getParent();
|
||||
if (appdata != null) builder.environment().put("APPDATA", appdata);
|
||||
Path appdata = options.getGameDir().toAbsolutePath().getParent();
|
||||
if (appdata != null) builder.environment().put("APPDATA", appdata.toString());
|
||||
|
||||
builder.environment().putAll(getEnvVars());
|
||||
process = builder.start();
|
||||
@@ -522,8 +523,8 @@ public class DefaultLauncher extends Launcher {
|
||||
Map<String, String> env = new LinkedHashMap<>();
|
||||
env.put("INST_NAME", versionName);
|
||||
env.put("INST_ID", versionName);
|
||||
env.put("INST_DIR", repository.getVersionRoot(version.getId()).getAbsolutePath());
|
||||
env.put("INST_MC_DIR", repository.getRunDirectory(version.getId()).getAbsolutePath());
|
||||
env.put("INST_DIR", FileUtils.getAbsolutePath(repository.getVersionRoot(version.getId())));
|
||||
env.put("INST_MC_DIR", FileUtils.getAbsolutePath(repository.getRunDirectory(version.getId())));
|
||||
env.put("INST_JAVA", options.getJava().getBinary().toString());
|
||||
|
||||
Renderer renderer = options.getRenderer();
|
||||
@@ -582,11 +583,11 @@ public class DefaultLauncher extends Launcher {
|
||||
public void makeLaunchScript(File scriptFile) throws IOException {
|
||||
boolean isWindows = OperatingSystem.WINDOWS == OperatingSystem.CURRENT_OS;
|
||||
|
||||
File nativeFolder;
|
||||
Path nativeFolder;
|
||||
if (options.getNativesDirType() == NativesDirectoryType.VERSION_FOLDER) {
|
||||
nativeFolder = repository.getNativeDirectory(version.getId(), options.getJava().getPlatform());
|
||||
} else {
|
||||
nativeFolder = new File(options.getNativesDir());
|
||||
nativeFolder = Path.of(options.getNativesDir());
|
||||
}
|
||||
|
||||
if (options.getNativesDirType() == NativesDirectoryType.VERSION_FOLDER) {
|
||||
@@ -640,9 +641,12 @@ public class DefaultLauncher extends Launcher {
|
||||
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, charset))) {
|
||||
if (usePowerShell) {
|
||||
if (isWindows) {
|
||||
writer.write("$Env:APPDATA=");
|
||||
writer.write(CommandBuilder.pwshString(options.getGameDir().getAbsoluteFile().getParent()));
|
||||
writer.newLine();
|
||||
Path appdata = options.getGameDir().toAbsolutePath().getParent();
|
||||
if (appdata != null) {
|
||||
writer.write("$Env:APPDATA=");
|
||||
writer.write(CommandBuilder.pwshString(appdata.toString()));
|
||||
writer.newLine();
|
||||
}
|
||||
}
|
||||
for (Map.Entry<String, String> entry : envVars.entrySet()) {
|
||||
writer.write("$Env:" + entry.getKey() + "=");
|
||||
@@ -650,7 +654,7 @@ public class DefaultLauncher extends Launcher {
|
||||
writer.newLine();
|
||||
}
|
||||
writer.write("Set-Location -Path ");
|
||||
writer.write(CommandBuilder.pwshString(repository.getRunDirectory(version.getId()).getAbsolutePath()));
|
||||
writer.write(CommandBuilder.pwshString(FileUtils.getAbsolutePath(repository.getRunDirectory(version.getId()))));
|
||||
writer.newLine();
|
||||
|
||||
|
||||
@@ -682,14 +686,19 @@ public class DefaultLauncher extends Launcher {
|
||||
if (isWindows) {
|
||||
writer.write("@echo off");
|
||||
writer.newLine();
|
||||
writer.write("set APPDATA=" + options.getGameDir().getAbsoluteFile().getParent());
|
||||
writer.newLine();
|
||||
|
||||
Path appdata = options.getGameDir().toAbsolutePath().getParent();
|
||||
if (appdata != null) {
|
||||
writer.write("set APPDATA=" + appdata);
|
||||
writer.newLine();
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> entry : envVars.entrySet()) {
|
||||
writer.write("set " + entry.getKey() + "=" + CommandBuilder.toBatchStringLiteral(entry.getValue()));
|
||||
writer.newLine();
|
||||
}
|
||||
writer.newLine();
|
||||
writer.write(new CommandBuilder().add("cd", "/D", repository.getRunDirectory(version.getId()).getAbsolutePath()).toString());
|
||||
writer.write(new CommandBuilder().add("cd", "/D", FileUtils.getAbsolutePath(repository.getRunDirectory(version.getId()))).toString());
|
||||
} else {
|
||||
writer.write("#!/usr/bin/env bash");
|
||||
writer.newLine();
|
||||
@@ -698,10 +707,10 @@ public class DefaultLauncher extends Launcher {
|
||||
writer.newLine();
|
||||
}
|
||||
if (commandLine.tempNativeFolder != null) {
|
||||
writer.write(new CommandBuilder().add("ln", "-s", nativeFolder.getAbsolutePath(), commandLine.tempNativeFolder.toString()).toString());
|
||||
writer.write(new CommandBuilder().add("ln", "-s", FileUtils.getAbsolutePath(nativeFolder), commandLine.tempNativeFolder.toString()).toString());
|
||||
writer.newLine();
|
||||
}
|
||||
writer.write(new CommandBuilder().add("cd", repository.getRunDirectory(version.getId()).getAbsolutePath()).toString());
|
||||
writer.write(new CommandBuilder().add("cd", FileUtils.getAbsolutePath(repository.getRunDirectory(version.getId()))).toString());
|
||||
}
|
||||
writer.newLine();
|
||||
if (StringUtils.isNotBlank(options.getPreLaunchCommand())) {
|
||||
@@ -751,7 +760,7 @@ public class DefaultLauncher extends Launcher {
|
||||
|
||||
if (StringUtils.isNotBlank(options.getPostExitCommand())) {
|
||||
try {
|
||||
ProcessBuilder builder = new ProcessBuilder(StringUtils.tokenize(options.getPostExitCommand(), getEnvVars())).directory(options.getGameDir());
|
||||
ProcessBuilder builder = new ProcessBuilder(StringUtils.tokenize(options.getPostExitCommand(), getEnvVars())).directory(options.getGameDir().toFile());
|
||||
builder.environment().putAll(getEnvVars());
|
||||
SystemUtils.callExternalProcess(builder);
|
||||
} catch (Throwable e) {
|
||||
|
||||
@@ -75,7 +75,7 @@ public final class ModManager {
|
||||
}
|
||||
|
||||
public Path getModsDirectory() {
|
||||
return repository.getRunDirectory(id).toPath().resolve("mods");
|
||||
return repository.getRunDirectory(id).resolve("mods");
|
||||
}
|
||||
|
||||
public LocalMod getLocalMod(String id, ModLoaderType modLoaderType) {
|
||||
|
||||
@@ -38,7 +38,7 @@ public class ModpackUpdateTask extends Task<Void> {
|
||||
this.id = id;
|
||||
this.updateTask = updateTask;
|
||||
|
||||
Path backup = repository.getBaseDirectory().toPath().resolve("backup");
|
||||
Path backup = repository.getBaseDirectory().resolve("backup");
|
||||
while (true) {
|
||||
int num = (int)(Math.random() * 10000000);
|
||||
if (!Files.exists(backup.resolve(id + "-" + num))) {
|
||||
@@ -55,7 +55,7 @@ public class ModpackUpdateTask extends Task<Void> {
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
FileUtils.copyDirectory(repository.getVersionRoot(id).toPath(), backupFolder);
|
||||
FileUtils.copyDirectory(repository.getVersionRoot(id), backupFolder);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,7 +71,7 @@ public class ModpackUpdateTask extends Task<Void> {
|
||||
// Restore backup
|
||||
repository.removeVersionFromDisk(id);
|
||||
|
||||
FileUtils.copyDirectory(backupFolder, repository.getVersionRoot(id).toPath());
|
||||
FileUtils.copyDirectory(backupFolder, repository.getVersionRoot(id));
|
||||
|
||||
repository.refreshVersionsAsync().start();
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -84,9 +86,9 @@ public final class CurseCompletionTask extends Task<Void> {
|
||||
|
||||
if (manifest == null)
|
||||
try {
|
||||
File manifestFile = new File(repository.getVersionRoot(version), "manifest.json");
|
||||
if (manifestFile.exists())
|
||||
this.manifest = JsonUtils.fromJsonFile(manifestFile.toPath(), CurseManifest.class);
|
||||
Path manifestFile = repository.getVersionRoot(version).resolve("manifest.json");
|
||||
if (Files.exists(manifestFile))
|
||||
this.manifest = JsonUtils.fromJsonFile(manifestFile, CurseManifest.class);
|
||||
} catch (Exception e) {
|
||||
LOG.warning("Unable to read CurseForge modpack manifest.json", e);
|
||||
}
|
||||
@@ -109,7 +111,7 @@ public final class CurseCompletionTask extends Task<Void> {
|
||||
if (manifest == null)
|
||||
return;
|
||||
|
||||
File root = repository.getVersionRoot(version);
|
||||
Path root = repository.getVersionRoot(version);
|
||||
|
||||
// Because in China, Curse is too difficult to visit,
|
||||
// if failed, ignore it and retry next time.
|
||||
@@ -135,17 +137,18 @@ public final class CurseCompletionTask extends Task<Void> {
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList()));
|
||||
JsonUtils.writeToJsonFile(root.toPath().resolve("manifest.json"), newManifest);
|
||||
JsonUtils.writeToJsonFile(root.resolve("manifest.json"), newManifest);
|
||||
|
||||
File versionRoot = repository.getVersionRoot(modManager.getVersion());
|
||||
File resourcePacksRoot = new File(versionRoot, "resourcepacks"), shaderPacksRoot = new File(versionRoot, "shaderpacks");
|
||||
Path versionRoot = repository.getVersionRoot(modManager.getVersion());
|
||||
Path resourcePacksRoot = versionRoot.resolve("resourcepacks");
|
||||
Path shaderPacksRoot = versionRoot.resolve("shaderpacks");
|
||||
finished.set(0);
|
||||
dependencies = newManifest.getFiles()
|
||||
.stream().parallel()
|
||||
.filter(f -> f.getFileName() != null)
|
||||
.flatMap(f -> {
|
||||
try {
|
||||
File path = guessFilePath(f, resourcePacksRoot, shaderPacksRoot);
|
||||
File path = guessFilePath(f, resourcePacksRoot.toFile(), shaderPacksRoot.toFile());
|
||||
if (path == null) {
|
||||
return Stream.empty();
|
||||
}
|
||||
@@ -171,9 +174,10 @@ public final class CurseCompletionTask extends Task<Void> {
|
||||
|
||||
/**
|
||||
* Guess where to store the file.
|
||||
* @param file The file.
|
||||
*
|
||||
* @param file The file.
|
||||
* @param resourcePacksRoot ./resourcepacks.
|
||||
* @param shaderPacksRoot ./shaderpacks.
|
||||
* @param shaderPacksRoot ./shaderpacks.
|
||||
* @return ./resourcepacks/$filename or ./shaderpacks/$filename or ./mods/$filename if the file doesn't exist. null if the file existed.
|
||||
* @throws IOException If IOException was encountered during getting data from CurseForge.
|
||||
*/
|
||||
|
||||
@@ -68,10 +68,10 @@ public final class CurseInstallTask extends Task<Void> {
|
||||
this.manifest = manifest;
|
||||
this.name = name;
|
||||
this.repository = dependencyManager.getGameRepository();
|
||||
this.run = repository.getRunDirectory(name);
|
||||
this.run = repository.getRunDirectory(name).toFile();
|
||||
|
||||
File json = repository.getModpackConfiguration(name);
|
||||
if (repository.hasVersion(name) && !json.exists())
|
||||
Path json = repository.getModpackConfiguration(name);
|
||||
if (repository.hasVersion(name) && Files.notExists(json))
|
||||
throw new IllegalArgumentException("Version " + name + " already exists.");
|
||||
|
||||
GameBuilder builder = dependencyManager.gameBuilder().name(name).gameVersion(manifest.getMinecraft().getGameVersion());
|
||||
@@ -97,8 +97,8 @@ public final class CurseInstallTask extends Task<Void> {
|
||||
|
||||
ModpackConfiguration<CurseManifest> config = null;
|
||||
try {
|
||||
if (json.exists()) {
|
||||
config = JsonUtils.fromJsonFile(json.toPath(), ModpackConfiguration.typeOf(CurseManifest.class));
|
||||
if (Files.exists(json)) {
|
||||
config = JsonUtils.fromJsonFile(json, ModpackConfiguration.typeOf(CurseManifest.class));
|
||||
|
||||
if (!CurseModpackProvider.INSTANCE.getName().equals(config.getType()))
|
||||
throw new IllegalArgumentException("Version " + name + " is not a Curse modpack. Cannot update this version.");
|
||||
@@ -107,7 +107,7 @@ public final class CurseInstallTask extends Task<Void> {
|
||||
}
|
||||
this.config = config;
|
||||
dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), Collections.singletonList(manifest.getOverrides()), any -> true, config).withStage("hmcl.modpack"));
|
||||
dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), Collections.singletonList(manifest.getOverrides()), manifest, CurseModpackProvider.INSTANCE, manifest.getName(), manifest.getVersion(), repository.getModpackConfiguration(name)).withStage("hmcl.modpack"));
|
||||
dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), Collections.singletonList(manifest.getOverrides()), manifest, CurseModpackProvider.INSTANCE, manifest.getName(), manifest.getVersion(), repository.getModpackConfiguration(name).toFile()).withStage("hmcl.modpack"));
|
||||
|
||||
dependencies.add(new CurseCompletionTask(dependencyManager, name, manifest));
|
||||
}
|
||||
@@ -136,7 +136,7 @@ public final class CurseInstallTask extends Task<Void> {
|
||||
}
|
||||
}
|
||||
|
||||
Path root = repository.getVersionRoot(name).toPath();
|
||||
Path root = repository.getVersionRoot(name);
|
||||
Files.createDirectories(root);
|
||||
JsonUtils.writeToJsonFile(root.resolve("manifest.json"), manifest);
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public class McbbsModpackCompletionTask extends CompletableFutureTask<Void> {
|
||||
this.repository = dependencyManager.getGameRepository();
|
||||
this.modManager = repository.getModManager(version);
|
||||
this.version = version;
|
||||
this.configurationFile = repository.getModpackConfiguration(version);
|
||||
this.configurationFile = repository.getModpackConfiguration(version).toFile();
|
||||
this.configuration = configuration;
|
||||
|
||||
setStage("hmcl.modpack.download");
|
||||
@@ -110,7 +110,7 @@ public class McbbsModpackCompletionTask extends CompletableFutureTask<Void> {
|
||||
throw new IOException("Unable to parse server manifest.json from " + manifest.getFileApi(), e);
|
||||
}
|
||||
|
||||
Path rootPath = repository.getVersionRoot(version).toPath();
|
||||
Path rootPath = repository.getVersionRoot(version);
|
||||
Files.createDirectories(rootPath);
|
||||
|
||||
Map<McbbsModpackManifest.File, McbbsModpackManifest.File> localFiles = manifest.getFiles().stream().collect(Collectors.toMap(Function.identity(), Function.identity()));
|
||||
@@ -172,7 +172,7 @@ public class McbbsModpackCompletionTask extends CompletableFutureTask<Void> {
|
||||
manifest = remoteManifest.setFiles(newFiles);
|
||||
return executor.all(tasks.stream().filter(Objects::nonNull).collect(Collectors.toList()));
|
||||
})).thenAcceptAsync(wrapConsumer(unused1 -> {
|
||||
Path manifestFile = repository.getModpackConfiguration(version).toPath();
|
||||
Path manifestFile = repository.getModpackConfiguration(version);
|
||||
JsonUtils.writeToJsonFile(manifestFile,
|
||||
new ModpackConfiguration<>(manifest, this.configuration.getType(), this.manifest.getName(), this.manifest.getVersion(),
|
||||
this.manifest.getFiles().stream()
|
||||
@@ -274,7 +274,7 @@ public class McbbsModpackCompletionTask extends CompletableFutureTask<Void> {
|
||||
@Nullable
|
||||
private Path getFilePath(McbbsModpackManifest.File file) {
|
||||
if (file instanceof McbbsModpackManifest.AddonFile) {
|
||||
return modManager.getRepository().getRunDirectory(modManager.getVersion()).toPath().resolve(((McbbsModpackManifest.AddonFile) file).getPath());
|
||||
return modManager.getRepository().getRunDirectory(modManager.getVersion()).resolve(((McbbsModpackManifest.AddonFile) file).getPath());
|
||||
} else if (file instanceof McbbsModpackManifest.CurseFile) {
|
||||
String fileName = ((McbbsModpackManifest.CurseFile) file).getFileName();
|
||||
if (fileName == null) return null;
|
||||
|
||||
@@ -67,7 +67,7 @@ public class McbbsModpackExportTask extends Task<Void> {
|
||||
blackList.add(version + ".json");
|
||||
LOG.info("Compressing game files without some files in blacklist, including files or directories: usernamecache.json, asm, logs, backups, versions, assets, usercache.json, libraries, crash-reports, launcher_profiles.json, NVIDIA, TCNodeTracker");
|
||||
try (Zipper zip = new Zipper(modpackFile.toPath())) {
|
||||
Path runDirectory = repository.getRunDirectory(version).toPath();
|
||||
Path runDirectory = repository.getRunDirectory(version);
|
||||
List<McbbsModpackManifest.File> files = new ArrayList<>();
|
||||
zip.putDirectory(runDirectory, "overrides", path -> {
|
||||
if (Modpack.acceptFile(path, blackList, info.getWhitelist())) {
|
||||
|
||||
@@ -31,6 +31,8 @@ import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -56,10 +58,10 @@ public class McbbsModpackLocalInstallTask extends Task<Void> {
|
||||
this.manifest = manifest;
|
||||
this.name = name;
|
||||
this.repository = dependencyManager.getGameRepository();
|
||||
File run = repository.getRunDirectory(name);
|
||||
Path run = repository.getRunDirectory(name);
|
||||
|
||||
File json = repository.getModpackConfiguration(name);
|
||||
if (repository.hasVersion(name) && !json.exists())
|
||||
Path json = repository.getModpackConfiguration(name);
|
||||
if (repository.hasVersion(name) && Files.notExists(json))
|
||||
throw new IllegalArgumentException("Version " + name + " already exists.");
|
||||
this.update = repository.hasVersion(name);
|
||||
|
||||
@@ -77,16 +79,16 @@ public class McbbsModpackLocalInstallTask extends Task<Void> {
|
||||
|
||||
ModpackConfiguration<McbbsModpackManifest> config = null;
|
||||
try {
|
||||
if (json.exists()) {
|
||||
config = JsonUtils.fromJsonFile(json.toPath(), ModpackConfiguration.typeOf(McbbsModpackManifest.class));
|
||||
if (Files.exists(json)) {
|
||||
config = JsonUtils.fromJsonFile(json, ModpackConfiguration.typeOf(McbbsModpackManifest.class));
|
||||
|
||||
if (!McbbsModpackProvider.INSTANCE.getName().equals(config.getType()))
|
||||
throw new IllegalArgumentException("Version " + name + " is not a Mcbbs modpack. Cannot update this version.");
|
||||
}
|
||||
} catch (JsonParseException | IOException ignore) {
|
||||
}
|
||||
dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), Collections.singletonList("/overrides"), any -> true, config).withStage("hmcl.modpack"));
|
||||
instanceTask = new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), Collections.singletonList("/overrides"), manifest, McbbsModpackProvider.INSTANCE, modpack.getName(), modpack.getVersion(), repository.getModpackConfiguration(name));
|
||||
dependents.add(new ModpackInstallTask<>(zipFile, run.toFile(), modpack.getEncoding(), Collections.singletonList("/overrides"), any -> true, config).withStage("hmcl.modpack"));
|
||||
instanceTask = new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), Collections.singletonList("/overrides"), manifest, McbbsModpackProvider.INSTANCE, modpack.getName(), modpack.getVersion(), repository.getModpackConfiguration(name).toFile());
|
||||
dependents.add(instanceTask.withStage("hmcl.modpack"));
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,9 @@ import org.jackhuang.hmcl.mod.ModpackConfiguration;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -46,8 +47,8 @@ public class McbbsModpackRemoteInstallTask extends Task<Void> {
|
||||
this.repository = dependencyManager.getGameRepository();
|
||||
this.manifest = manifest;
|
||||
|
||||
File json = repository.getModpackConfiguration(name);
|
||||
if (repository.hasVersion(name) && !json.exists())
|
||||
Path json = repository.getModpackConfiguration(name);
|
||||
if (repository.hasVersion(name) && Files.notExists(json))
|
||||
throw new IllegalArgumentException("Version " + name + " already exists.");
|
||||
|
||||
GameBuilder builder = dependencyManager.gameBuilder().name(name);
|
||||
@@ -63,8 +64,8 @@ public class McbbsModpackRemoteInstallTask extends Task<Void> {
|
||||
|
||||
ModpackConfiguration<McbbsModpackManifest> config;
|
||||
try {
|
||||
if (json.exists()) {
|
||||
config = JsonUtils.fromJsonFile(json.toPath(), ModpackConfiguration.typeOf(McbbsModpackManifest.class));
|
||||
if (Files.exists(json)) {
|
||||
config = JsonUtils.fromJsonFile(json, ModpackConfiguration.typeOf(McbbsModpackManifest.class));
|
||||
|
||||
if (!MODPACK_TYPE.equals(config.getType()))
|
||||
throw new IllegalArgumentException("Version " + name + " is not a Mcbbs modpack. Cannot update this version.");
|
||||
|
||||
@@ -79,7 +79,7 @@ public class ModrinthCompletionTask extends Task<Void> {
|
||||
|
||||
if (manifest == null)
|
||||
try {
|
||||
Path manifestFile = repository.getVersionRoot(version).toPath().resolve("modrinth.index.json");
|
||||
Path manifestFile = repository.getVersionRoot(version).resolve("modrinth.index.json");
|
||||
if (Files.exists(manifestFile))
|
||||
this.manifest = JsonUtils.fromJsonFile(manifestFile, ModrinthManifest.class);
|
||||
} catch (Exception e) {
|
||||
@@ -104,7 +104,7 @@ public class ModrinthCompletionTask extends Task<Void> {
|
||||
if (manifest == null)
|
||||
return;
|
||||
|
||||
Path runDirectory = repository.getRunDirectory(version).toPath().toAbsolutePath().normalize();
|
||||
Path runDirectory = FileUtils.toAbsolute(repository.getRunDirectory(version));
|
||||
Path modsDirectory = runDirectory.resolve("mods");
|
||||
|
||||
for (ModrinthManifest.File file : manifest.getFiles()) {
|
||||
|
||||
@@ -51,10 +51,10 @@ public class ModrinthInstallTask extends Task<Void> {
|
||||
this.manifest = manifest;
|
||||
this.name = name;
|
||||
this.repository = dependencyManager.getGameRepository();
|
||||
this.run = repository.getRunDirectory(name);
|
||||
this.run = repository.getRunDirectory(name).toFile();
|
||||
|
||||
File json = repository.getModpackConfiguration(name);
|
||||
if (repository.hasVersion(name) && !json.exists())
|
||||
Path json = repository.getModpackConfiguration(name);
|
||||
if (repository.hasVersion(name) && Files.notExists(json))
|
||||
throw new IllegalArgumentException("Version " + name + " already exists.");
|
||||
|
||||
GameBuilder builder = dependencyManager.gameBuilder().name(name).gameVersion(manifest.getGameVersion());
|
||||
@@ -91,8 +91,8 @@ public class ModrinthInstallTask extends Task<Void> {
|
||||
|
||||
ModpackConfiguration<ModrinthManifest> config = null;
|
||||
try {
|
||||
if (json.exists()) {
|
||||
config = JsonUtils.fromJsonFile(json.toPath(), ModpackConfiguration.typeOf(ModrinthManifest.class));
|
||||
if (Files.exists(json)) {
|
||||
config = JsonUtils.fromJsonFile(json, ModpackConfiguration.typeOf(ModrinthManifest.class));
|
||||
|
||||
if (!ModrinthModpackProvider.INSTANCE.getName().equals(config.getType()))
|
||||
throw new IllegalArgumentException("Version " + name + " is not a Modrinth modpack. Cannot update this version.");
|
||||
@@ -103,7 +103,7 @@ public class ModrinthInstallTask extends Task<Void> {
|
||||
this.config = config;
|
||||
List<String> subDirectories = Arrays.asList("/client-overrides", "/overrides");
|
||||
dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), subDirectories, any -> true, config).withStage("hmcl.modpack"));
|
||||
dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), subDirectories, manifest, ModrinthModpackProvider.INSTANCE, manifest.getName(), manifest.getVersionId(), repository.getModpackConfiguration(name)).withStage("hmcl.modpack"));
|
||||
dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), subDirectories, manifest, ModrinthModpackProvider.INSTANCE, manifest.getName(), manifest.getVersionId(), repository.getModpackConfiguration(name).toFile()).withStage("hmcl.modpack"));
|
||||
|
||||
dependencies.add(new ModrinthCompletionTask(dependencyManager, name, manifest));
|
||||
}
|
||||
@@ -131,7 +131,7 @@ public class ModrinthInstallTask extends Task<Void> {
|
||||
}
|
||||
}
|
||||
|
||||
Path root = repository.getVersionRoot(name).toPath();
|
||||
Path root = repository.getVersionRoot(name);
|
||||
Files.createDirectories(root);
|
||||
JsonUtils.writeToJsonFile(root.resolve("modrinth.index.json"), manifest);
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ public class ModrinthModpackExportTask extends Task<Void> {
|
||||
blackList.add(version + ".json");
|
||||
LOG.info("Compressing game files without some files in blacklist, including files or directories: usernamecache.json, asm, logs, backups, versions, assets, usercache.json, libraries, crash-reports, launcher_profiles.json, NVIDIA, TCNodeTracker");
|
||||
try (Zipper zip = new Zipper(modpackFile.toPath())) {
|
||||
Path runDirectory = repository.getRunDirectory(version).toPath();
|
||||
Path runDirectory = repository.getRunDirectory(version);
|
||||
List<ModrinthManifest.File> files = new ArrayList<>();
|
||||
Set<String> filesInManifest = new HashSet<>();
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ public class MultiMCModpackExportTask extends Task<Void> {
|
||||
blackList.add(versionId + ".json");
|
||||
LOG.info("Compressing game files without some files in blacklist, including files or directories: usernamecache.json, asm, logs, backups, versions, assets, usercache.json, libraries, crash-reports, launcher_profiles.json, NVIDIA, TCNodeTracker");
|
||||
try (Zipper zip = new Zipper(output.toPath())) {
|
||||
zip.putDirectory(repository.getRunDirectory(versionId).toPath(), ".minecraft", path -> Modpack.acceptFile(path, blackList, whitelist));
|
||||
zip.putDirectory(repository.getRunDirectory(versionId), ".minecraft", path -> Modpack.acceptFile(path, blackList, whitelist));
|
||||
|
||||
String gameVersion = repository.getGameVersion(versionId)
|
||||
.orElseThrow(() -> new IOException("Cannot parse the version of " + versionId));
|
||||
|
||||
@@ -94,8 +94,8 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.repository = dependencyManager.getGameRepository();
|
||||
|
||||
File json = repository.getModpackConfiguration(name);
|
||||
if (repository.hasVersion(name) && !json.exists())
|
||||
Path json = repository.getModpackConfiguration(name);
|
||||
if (repository.hasVersion(name) && Files.notExists(json))
|
||||
throw new IllegalArgumentException("Version " + name + " already exists.");
|
||||
|
||||
onDone().register(event -> {
|
||||
@@ -113,13 +113,13 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
||||
public void preExecute() throws Exception {
|
||||
// Stage #0: General Setup
|
||||
{
|
||||
File run = repository.getRunDirectory(name);
|
||||
File json = repository.getModpackConfiguration(name);
|
||||
Path run = repository.getRunDirectory(name);
|
||||
Path json = repository.getModpackConfiguration(name);
|
||||
|
||||
ModpackConfiguration<MultiMCInstanceConfiguration> config = null;
|
||||
try {
|
||||
if (json.exists()) {
|
||||
config = JsonUtils.fromJsonFile(json.toPath(), ModpackConfiguration.typeOf(MultiMCInstanceConfiguration.class));
|
||||
if (Files.exists(json)) {
|
||||
config = JsonUtils.fromJsonFile(json, ModpackConfiguration.typeOf(MultiMCInstanceConfiguration.class));
|
||||
|
||||
if (!MultiMCModpackProvider.INSTANCE.getName().equals(config.getType()))
|
||||
throw new IllegalArgumentException("Version " + name + " is not a MultiMC modpack. Cannot update this version.");
|
||||
@@ -133,8 +133,8 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
||||
}
|
||||
|
||||
// TODO: Optimize unbearably slow ModpackInstallTask
|
||||
dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), Collections.singletonList(mcDirectory), any -> true, config).withStage("hmcl.modpack"));
|
||||
dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), Collections.singletonList(mcDirectory), manifest, MultiMCModpackProvider.INSTANCE, manifest.getName(), null, repository.getModpackConfiguration(name)).withStage("hmcl.modpack"));
|
||||
dependents.add(new ModpackInstallTask<>(zipFile, run.toFile(), modpack.getEncoding(), Collections.singletonList(mcDirectory), any -> true, config).withStage("hmcl.modpack"));
|
||||
dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), Collections.singletonList(mcDirectory), manifest, MultiMCModpackProvider.INSTANCE, manifest.getName(), null, repository.getModpackConfiguration(name).toFile()).withStage("hmcl.modpack"));
|
||||
}
|
||||
|
||||
// Stage #1: Load all related Json-Patch from meta maven or local mod pack.
|
||||
@@ -253,7 +253,7 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
||||
|
||||
Path libraries = root.resolve("libraries");
|
||||
if (Files.exists(libraries))
|
||||
FileUtils.copyDirectory(libraries, repository.getVersionRoot(name).toPath().resolve("libraries"));
|
||||
FileUtils.copyDirectory(libraries, repository.getVersionRoot(name).resolve("libraries"));
|
||||
|
||||
for (Library library : artifact.getVersion().getLibraries()) {
|
||||
if ("local".equals(library.getHint())) {
|
||||
@@ -261,15 +261,15 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
||||
Retain them will facilitate compatibility, as some embedded libraries may check where their JAR is.
|
||||
Meanwhile, potential compatibility issue with other launcher which never supports these fields might occur.
|
||||
Here, we make the file stored twice, to keep maximum compatibility. */
|
||||
Path from = repository.getLibraryFile(artifact.getVersion(), library).toPath();
|
||||
Path target = repository.getLibraryFile(artifact.getVersion(), library.withoutCommunityFields()).toPath();
|
||||
Path from = repository.getLibraryFile(artifact.getVersion(), library);
|
||||
Path target = repository.getLibraryFile(artifact.getVersion(), library.withoutCommunityFields());
|
||||
Files.createDirectories(target.getParent());
|
||||
Files.copy(from, target, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
||||
|
||||
try (InputStream input = MaintainTask.class.getResourceAsStream("/assets/game/HMCLMultiMCBootstrap-1.0.jar")) {
|
||||
Path libraryPath = repository.getLibraryFile(artifact.getVersion(), MultiMCInstancePatch.BOOTSTRAP_LIBRARY).toPath();
|
||||
Path libraryPath = repository.getLibraryFile(artifact.getVersion(), MultiMCInstancePatch.BOOTSTRAP_LIBRARY);
|
||||
|
||||
Files.createDirectories(libraryPath.getParent());
|
||||
Files.copy(Objects.requireNonNull(input, "Bundled HMCLMultiMCBootstrap is missing."), libraryPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
@@ -279,7 +279,7 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
||||
if (iconKey != null) {
|
||||
Path iconFile = root.resolve(iconKey + ".png");
|
||||
if (Files.exists(iconFile)) {
|
||||
FileUtils.copyFile(iconFile, repository.getVersionRoot(name).toPath().resolve("icon.png"));
|
||||
FileUtils.copyFile(iconFile, repository.getVersionRoot(name).resolve("icon.png"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -339,7 +339,7 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
||||
Path root = getRootPath(fs).resolve("jarmods");
|
||||
|
||||
try (FileSystem mc = CompressingUtils.writable(
|
||||
repository.getVersionRoot(name).toPath().resolve(name + ".jar")
|
||||
repository.getVersionRoot(name).resolve(name + ".jar")
|
||||
).setAutoDetectEncoding(true).build()) {
|
||||
for (String fileName : files) {
|
||||
try (FileSystem jm = CompressingUtils.readonly(root.resolve(fileName)).setAutoDetectEncoding(true).build()) {
|
||||
|
||||
@@ -30,7 +30,6 @@ import org.jackhuang.hmcl.util.DigestUtils;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -61,9 +60,9 @@ public class ServerModpackCompletionTask extends Task<Void> {
|
||||
|
||||
if (manifest == null) {
|
||||
try {
|
||||
File manifestFile = repository.getModpackConfiguration(version);
|
||||
if (manifestFile.exists()) {
|
||||
this.manifest = JsonUtils.fromJsonFile(manifestFile.toPath(), ModpackConfiguration.typeOf(ServerModpackManifest.class));
|
||||
Path manifestFile = repository.getModpackConfiguration(version);
|
||||
if (Files.exists(manifestFile)) {
|
||||
this.manifest = JsonUtils.fromJsonFile(manifestFile, ModpackConfiguration.typeOf(ServerModpackManifest.class));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.warning("Unable to read Server modpack manifest.json", e);
|
||||
@@ -121,7 +120,7 @@ public class ServerModpackCompletionTask extends Task<Void> {
|
||||
dependencies.add(builder.buildAsync());
|
||||
}
|
||||
|
||||
Path rootPath = repository.getVersionRoot(version).toPath().toAbsolutePath().normalize();
|
||||
Path rootPath = repository.getVersionRoot(version).toAbsolutePath().normalize();
|
||||
Map<String, ModpackConfiguration.FileInformation> files = manifest.getManifest().getFiles().stream()
|
||||
.collect(Collectors.toMap(ModpackConfiguration.FileInformation::getPath,
|
||||
Function.identity()));
|
||||
@@ -129,7 +128,7 @@ public class ServerModpackCompletionTask extends Task<Void> {
|
||||
Set<String> remoteFiles = remoteManifest.getFiles().stream().map(ModpackConfiguration.FileInformation::getPath)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Path runDirectory = repository.getRunDirectory(version).toPath().toAbsolutePath().normalize();
|
||||
Path runDirectory = repository.getRunDirectory(version).toAbsolutePath().normalize();
|
||||
Path modsDirectory = runDirectory.resolve("mods");
|
||||
|
||||
int total = 0;
|
||||
@@ -189,7 +188,7 @@ public class ServerModpackCompletionTask extends Task<Void> {
|
||||
@Override
|
||||
public void postExecute() throws Exception {
|
||||
if (manifest == null || StringUtils.isBlank(manifest.getManifest().getFileApi())) return;
|
||||
Path manifestFile = repository.getModpackConfiguration(version).toPath();
|
||||
Path manifestFile = repository.getModpackConfiguration(version);
|
||||
Files.createDirectories(manifestFile.getParent());
|
||||
JsonUtils.writeToJsonFile(manifestFile, new ModpackConfiguration<>(remoteManifest, this.manifest.getType(), this.manifest.getName(), this.manifest.getVersion(), remoteManifest.getFiles()));
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class ServerModpackExportTask extends Task<Void> {
|
||||
blackList.add(versionId + ".json");
|
||||
LOG.info("Compressing game files without some files in blacklist, including files or directories: usernamecache.json, asm, logs, backups, versions, assets, usercache.json, libraries, crash-reports, launcher_profiles.json, NVIDIA, TCNodeTracker");
|
||||
try (Zipper zip = new Zipper(modpackFile.toPath())) {
|
||||
Path runDirectory = repository.getRunDirectory(versionId).toPath();
|
||||
Path runDirectory = repository.getRunDirectory(versionId);
|
||||
List<ModpackConfiguration.FileInformation> files = new ArrayList<>();
|
||||
zip.putDirectory(runDirectory, "overrides", path -> {
|
||||
if (Modpack.acceptFile(path, blackList, exportInfo.getWhitelist())) {
|
||||
|
||||
@@ -30,6 +30,8 @@ import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -50,10 +52,10 @@ public class ServerModpackLocalInstallTask extends Task<Void> {
|
||||
this.manifest = manifest;
|
||||
this.name = name;
|
||||
this.repository = dependencyManager.getGameRepository();
|
||||
File run = repository.getRunDirectory(name);
|
||||
Path run = repository.getRunDirectory(name);
|
||||
|
||||
File json = repository.getModpackConfiguration(name);
|
||||
if (repository.hasVersion(name) && !json.exists())
|
||||
Path json = repository.getModpackConfiguration(name);
|
||||
if (repository.hasVersion(name) && Files.notExists(json))
|
||||
throw new IllegalArgumentException("Version " + name + " already exists.");
|
||||
|
||||
GameBuilder builder = dependencyManager.gameBuilder().name(name);
|
||||
@@ -69,16 +71,16 @@ public class ServerModpackLocalInstallTask extends Task<Void> {
|
||||
|
||||
ModpackConfiguration<ServerModpackManifest> config = null;
|
||||
try {
|
||||
if (json.exists()) {
|
||||
config = JsonUtils.fromJsonFile(json.toPath(), ModpackConfiguration.typeOf(ServerModpackManifest.class));
|
||||
if (Files.exists(json)) {
|
||||
config = JsonUtils.fromJsonFile(json, ModpackConfiguration.typeOf(ServerModpackManifest.class));
|
||||
|
||||
if (!ServerModpackProvider.INSTANCE.getName().equals(config.getType()))
|
||||
throw new IllegalArgumentException("Version " + name + " is not a Server modpack. Cannot update this version.");
|
||||
}
|
||||
} catch (JsonParseException | IOException ignore) {
|
||||
}
|
||||
dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), Collections.singletonList("/overrides"), any -> true, config).withStage("hmcl.modpack"));
|
||||
dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), Collections.singletonList("/overrides"), manifest, ServerModpackProvider.INSTANCE, modpack.getName(), modpack.getVersion(), repository.getModpackConfiguration(name)).withStage("hmcl.modpack"));
|
||||
dependents.add(new ModpackInstallTask<>(zipFile, run.toFile(), modpack.getEncoding(), Collections.singletonList("/overrides"), any -> true, config).withStage("hmcl.modpack"));
|
||||
dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), Collections.singletonList("/overrides"), manifest, ServerModpackProvider.INSTANCE, modpack.getName(), modpack.getVersion(), repository.getModpackConfiguration(name).toFile()).withStage("hmcl.modpack"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,8 +25,9 @@ import org.jackhuang.hmcl.mod.ModpackConfiguration;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -46,8 +47,8 @@ public class ServerModpackRemoteInstallTask extends Task<Void> {
|
||||
this.repository = dependencyManager.getGameRepository();
|
||||
this.manifest = manifest;
|
||||
|
||||
File json = repository.getModpackConfiguration(name);
|
||||
if (repository.hasVersion(name) && !json.exists())
|
||||
Path json = repository.getModpackConfiguration(name);
|
||||
if (repository.hasVersion(name) && Files.notExists(json))
|
||||
throw new IllegalArgumentException("Version " + name + " already exists.");
|
||||
|
||||
GameBuilder builder = dependencyManager.gameBuilder().name(name);
|
||||
@@ -63,8 +64,8 @@ public class ServerModpackRemoteInstallTask extends Task<Void> {
|
||||
|
||||
ModpackConfiguration<ServerModpackManifest> config;
|
||||
try {
|
||||
if (json.exists()) {
|
||||
config = JsonUtils.fromJsonFile(json.toPath(), ModpackConfiguration.typeOf(ServerModpackManifest.class));
|
||||
if (Files.exists(json)) {
|
||||
config = JsonUtils.fromJsonFile(json, ModpackConfiguration.typeOf(ServerModpackManifest.class));
|
||||
|
||||
if (!MODPACK_TYPE.equals(config.getType()))
|
||||
throw new IllegalArgumentException("Version " + name + " is not a Server modpack. Cannot update this version.");
|
||||
|
||||
@@ -109,6 +109,14 @@ public final class FileUtils {
|
||||
return fileName != null ? fileName.toString() : "";
|
||||
}
|
||||
|
||||
public static Path toAbsolute(Path path) {
|
||||
return path.toAbsolutePath().normalize();
|
||||
}
|
||||
|
||||
public static String getAbsolutePath(Path path) {
|
||||
return path.toAbsolutePath().normalize().toString();
|
||||
}
|
||||
|
||||
// https://learn.microsoft.com/biztalk/core/restrictions-when-configuring-the-file-adapter
|
||||
private static final Set<String> INVALID_WINDOWS_RESOURCE_BASE_NAMES = Set.of(
|
||||
"aux", "con", "nul", "prn", "clock$",
|
||||
@@ -187,6 +195,18 @@ public final class FileUtils {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Safely get the file size. Returns `0` if the file does not exist or the size cannot be obtained.
|
||||
public static long size(Path file) {
|
||||
try {
|
||||
return Files.size(file);
|
||||
} catch (NoSuchFileException ignored) {
|
||||
return 0L;
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Failed to get file size of " + file, e);
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
public static String readTextMaybeNativeEncoding(Path file) throws IOException {
|
||||
byte[] bytes = Files.readAllBytes(file);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user