From 26e274a89af9a414d64d2dbbdca24259411bb5a5 Mon Sep 17 00:00:00 2001 From: Glavo Date: Wed, 17 Sep 2025 16:07:59 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86=20GameRepository=20=E4=BB=8E=20java.i?= =?UTF-8?q?o.File=20=E8=BF=81=E7=A7=BB=E8=87=B3=20NIO=20(#4496)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/HMCL-dev/HMCL/issues/2987 --- .../jackhuang/hmcl/game/HMCLGameLauncher.java | 2 +- .../hmcl/game/HMCLGameRepository.java | 100 ++++--- .../hmcl/game/HMCLModpackInstallTask.java | 16 +- .../jackhuang/hmcl/game/LauncherHelper.java | 13 +- .../org/jackhuang/hmcl/game/LogExporter.java | 4 +- .../org/jackhuang/hmcl/setting/Profile.java | 4 +- .../jackhuang/hmcl/ui/GameCrashWindow.java | 4 +- .../hmcl/ui/download/DownloadPage.java | 2 +- .../ModpackInstallWizardProvider.java | 4 +- .../ui/export/ModpackFileSelectionPage.java | 2 +- .../versions/AdvancedVersionSettingPage.java | 4 +- .../hmcl/ui/versions/ModListPage.java | 2 +- .../hmcl/ui/versions/VersionIconDialog.java | 2 +- .../hmcl/ui/versions/VersionPage.java | 9 +- .../hmcl/ui/versions/VersionSettingsPage.java | 3 +- .../jackhuang/hmcl/ui/versions/Versions.java | 6 +- .../hmcl/ui/GameCrashWindowTest.java | 8 +- .../download/DefaultDependencyManager.java | 15 +- .../jackhuang/hmcl/download/MaintainTask.java | 6 +- .../download/fabric/FabricAPIInstallTask.java | 2 +- .../download/forge/ForgeNewInstallTask.java | 10 +- .../download/forge/ForgeOldInstallTask.java | 2 +- .../hmcl/download/game/GameDownloadTask.java | 2 +- .../hmcl/download/game/GameLibrariesTask.java | 7 +- .../game/GameVerificationFixTask.java | 2 +- .../download/game/VersionJsonSaveTask.java | 2 +- .../neoforge/NeoForgeOldInstallTask.java | 10 +- .../optifine/OptiFineInstallTask.java | 19 +- .../download/quilt/QuiltAPIInstallTask.java | 2 +- .../jackhuang/hmcl/game/ClassicVersion.java | 28 +- .../hmcl/game/DefaultGameRepository.java | 257 +++++++++--------- .../jackhuang/hmcl/game/GameRepository.java | 33 +-- .../org/jackhuang/hmcl/game/GameVersion.java | 9 +- .../jackhuang/hmcl/game/LaunchOptions.java | 8 +- .../hmcl/game/tlauncher/TLauncherLibrary.java | 4 +- .../hmcl/game/tlauncher/TLauncherVersion.java | 2 +- .../hmcl/launch/DefaultLauncher.java | 99 ++++--- .../org/jackhuang/hmcl/mod/ModManager.java | 2 +- .../jackhuang/hmcl/mod/ModpackUpdateTask.java | 6 +- .../hmcl/mod/curse/CurseCompletionTask.java | 24 +- .../hmcl/mod/curse/CurseInstallTask.java | 14 +- .../mod/mcbbs/McbbsModpackCompletionTask.java | 8 +- .../mod/mcbbs/McbbsModpackExportTask.java | 2 +- .../mcbbs/McbbsModpackLocalInstallTask.java | 16 +- .../mcbbs/McbbsModpackRemoteInstallTask.java | 11 +- .../mod/modrinth/ModrinthCompletionTask.java | 4 +- .../mod/modrinth/ModrinthInstallTask.java | 14 +- .../modrinth/ModrinthModpackExportTask.java | 2 +- .../mod/multimc/MultiMCModpackExportTask.java | 2 +- .../multimc/MultiMCModpackInstallTask.java | 28 +- .../server/ServerModpackCompletionTask.java | 13 +- .../mod/server/ServerModpackExportTask.java | 2 +- .../server/ServerModpackLocalInstallTask.java | 16 +- .../ServerModpackRemoteInstallTask.java | 11 +- .../org/jackhuang/hmcl/util/io/FileUtils.java | 20 ++ 55 files changed, 483 insertions(+), 416 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java index d1240c52c..94ee1834e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameLauncher.java @@ -64,7 +64,7 @@ public final class HMCLGameLauncher extends DefaultLauncher { if (config().isDisableAutoGameOptions()) return; - Path runDir = repository.getRunDirectory(version.getId()).toPath(); + Path runDir = repository.getRunDirectory(version.getId()); Path optionsFile = runDir.resolve("options.txt"); Path configFolder = runDir.resolve("config"); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java index df95029cd..9ad0546ac 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java @@ -44,7 +44,6 @@ import org.jackhuang.hmcl.util.platform.SystemInfo; import org.jackhuang.hmcl.util.versioning.VersionNumber; import org.jetbrains.annotations.Nullable; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.InvalidPathException; @@ -58,7 +57,7 @@ import static org.jackhuang.hmcl.setting.ConfigHolder.config; import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.Pair.pair; -public class HMCLGameRepository extends DefaultGameRepository { +public final class HMCLGameRepository extends DefaultGameRepository { private final Profile profile; // local version settings @@ -67,7 +66,7 @@ public class HMCLGameRepository extends DefaultGameRepository { public final EventManager onVersionIconChanged = new EventManager<>(); - public HMCLGameRepository(Profile profile, File baseDirectory) { + public HMCLGameRepository(Profile profile, Path baseDirectory) { super(baseDirectory); this.profile = profile; } @@ -86,7 +85,7 @@ public class HMCLGameRepository extends DefaultGameRepository { } @Override - public File getRunDirectory(String id) { + public Path getRunDirectory(String id) { switch (getGameDirectoryType(id)) { case VERSION_FOLDER: return getVersionRoot(id); @@ -94,7 +93,7 @@ public class HMCLGameRepository extends DefaultGameRepository { return super.getRunDirectory(id); case CUSTOM: try { - return Path.of(getVersionSetting(id).getGameDir()).toFile(); + return Path.of(getVersionSetting(id).getGameDir()); } catch (InvalidPathException ignored) { return getVersionRoot(id); } @@ -122,7 +121,7 @@ public class HMCLGameRepository extends DefaultGameRepository { }); try { - Path file = getBaseDirectory().toPath().resolve("launcher_profiles.json"); + Path file = getBaseDirectory().resolve("launcher_profiles.json"); if (!Files.exists(file) && !versions.isEmpty()) { Files.createDirectories(file.getParent()); Files.writeString(file, PROFILE); @@ -132,7 +131,7 @@ public class HMCLGameRepository extends DefaultGameRepository { } } - public void changeDirectory(File newDirectory) { + public void changeDirectory(Path newDirectory) { setBaseDirectory(newDirectory); refreshVersionsAsync().start(); } @@ -143,13 +142,13 @@ public class HMCLGameRepository extends DefaultGameRepository { } public void clean(String id) throws IOException { - clean(getBaseDirectory().toPath()); - clean(getRunDirectory(id).toPath()); + clean(getBaseDirectory()); + clean(getRunDirectory(id)); } public void duplicateVersion(String srcId, String dstId, boolean copySaves) throws IOException { - Path srcDir = getVersionRoot(srcId).toPath(); - Path dstDir = getVersionRoot(dstId).toPath(); + Path srcDir = getVersionRoot(srcId); + Path dstDir = getVersionRoot(dstId); Version fromVersion = getVersion(srcId); @@ -183,22 +182,22 @@ public class HMCLGameRepository extends DefaultGameRepository { VersionSetting newVersionSetting = initLocalVersionSetting(dstId, oldVersionSetting); saveVersionSetting(dstId); - File srcGameDir = getRunDirectory(srcId); - File dstGameDir = getRunDirectory(dstId); + Path srcGameDir = getRunDirectory(srcId); + Path dstGameDir = getRunDirectory(dstId); if (originalGameDirType != GameDirectoryType.VERSION_FOLDER) - FileUtils.copyDirectory(srcGameDir.toPath(), dstGameDir.toPath(), path -> Modpack.acceptFile(path, blackList, null)); + FileUtils.copyDirectory(srcGameDir, dstGameDir, path -> Modpack.acceptFile(path, blackList, null)); } - private File getLocalVersionSettingFile(String id) { - return new File(getVersionRoot(id), "hmclversion.cfg"); + private Path getLocalVersionSettingFile(String id) { + return getVersionRoot(id).resolve("hmclversion.cfg"); } private void loadLocalVersionSetting(String id) { - File file = getLocalVersionSettingFile(id); - if (file.exists()) + Path file = getLocalVersionSettingFile(id); + if (Files.exists(file)) try { - VersionSetting versionSetting = GSON.fromJson(Files.readString(file.toPath()), VersionSetting.class); + VersionSetting versionSetting = JsonUtils.fromJsonFile(file, VersionSetting.class); initLocalVersionSetting(id, versionSetting); } catch (Exception ex) { // If [JsonParseException], [IOException] or [NullPointerException] happens, the json file is malformed and needed to be recreated. @@ -261,12 +260,12 @@ public class HMCLGameRepository extends DefaultGameRepository { return vs; } - public Optional getVersionIconFile(String id) { - File root = getVersionRoot(id); + public Optional getVersionIconFile(String id) { + Path root = getVersionRoot(id); for (String extension : FXUtils.IMAGE_EXTENSIONS) { - File file = new File(root, "icon." + extension); - if (file.exists()) { + Path file = root.resolve("icon." + extension); + if (Files.exists(file)) { return Optional.of(file); } } @@ -274,21 +273,26 @@ public class HMCLGameRepository extends DefaultGameRepository { return Optional.empty(); } - public void setVersionIconFile(String id, File iconFile) throws IOException { - String ext = FileUtils.getExtension(iconFile.getName()).toLowerCase(Locale.ROOT); + public void setVersionIconFile(String id, Path iconFile) throws IOException { + String ext = FileUtils.getExtension(iconFile).toLowerCase(Locale.ROOT); if (!FXUtils.IMAGE_EXTENSIONS.contains(ext)) { throw new IllegalArgumentException("Unsupported icon file: " + ext); } deleteIconFile(id); - FileUtils.copyFile(iconFile.toPath(), getVersionRoot(id).toPath().resolve("icon." + ext)); + FileUtils.copyFile(iconFile, getVersionRoot(id).resolve("icon." + ext)); } public void deleteIconFile(String id) { - File root = getVersionRoot(id); + Path root = getVersionRoot(id); for (String extension : FXUtils.IMAGE_EXTENSIONS) { - new File(root, "icon." + extension).delete(); + Path file = root.resolve("icon." + extension); + try { + Files.deleteIfExists(file); + } catch (IOException e) { + LOG.warning("Failed to delete icon file: " + file, e); + } } } @@ -301,10 +305,10 @@ public class HMCLGameRepository extends DefaultGameRepository { if (iconType == VersionIconType.DEFAULT) { Version version = getVersion(id).resolve(this); - Optional iconFile = getVersionIconFile(id); + Optional iconFile = getVersionIconFile(id); if (iconFile.isPresent()) { try { - return FXUtils.loadImage(iconFile.get().toPath()); + return FXUtils.loadImage(iconFile.get()); } catch (Exception e) { LOG.warning("Failed to load version icon of " + id, e); } @@ -339,7 +343,7 @@ public class HMCLGameRepository extends DefaultGameRepository { public void saveVersionSetting(String id) { if (!localVersionSettings.containsKey(id)) return; - Path file = getLocalVersionSettingFile(id).toPath().toAbsolutePath().normalize(); + Path file = getLocalVersionSettingFile(id).toAbsolutePath().normalize(); try { Files.createDirectories(file.getParent()); } catch (IOException e) { @@ -373,7 +377,7 @@ public class HMCLGameRepository extends DefaultGameRepository { vs.setUsesGlobal(true); } - public LaunchOptions getLaunchOptions(String version, JavaRuntime javaVersion, File gameDir, List javaAgents, List javaArguments, boolean makeLaunchScript) { + public LaunchOptions getLaunchOptions(String version, JavaRuntime javaVersion, Path gameDir, List javaAgents, List javaArguments, boolean makeLaunchScript) { VersionSetting vs = getVersionSetting(version); LaunchOptions.Builder builder = new LaunchOptions.Builder() @@ -384,7 +388,7 @@ public class HMCLGameRepository extends DefaultGameRepository { .setProfileName(Metadata.TITLE) .setGameArguments(StringUtils.tokenize(vs.getMinecraftArgs())) .setOverrideJavaArguments(StringUtils.tokenize(vs.getJavaArgs())) - .setMaxMemory(vs.isNoJVMArgs() && vs.isAutoMemory() ? null : (int)(getAllocatedMemory( + .setMaxMemory(vs.isNoJVMArgs() && vs.isAutoMemory() ? null : (int) (getAllocatedMemory( vs.getMaxMemory() * 1024L * 1024L, SystemInfo.getPhysicalMemoryStatus().getAvailable(), vs.isAutoMemory() @@ -430,15 +434,15 @@ public class HMCLGameRepository extends DefaultGameRepository { } } - File json = getModpackConfiguration(version); - if (json.exists()) { + Path json = getModpackConfiguration(version); + if (Files.exists(json)) { try { - String jsonText = Files.readString(json.toPath()); + String jsonText = Files.readString(json); ModpackConfiguration modpackConfiguration = JsonUtils.GSON.fromJson(jsonText, ModpackConfiguration.class); ModpackProvider provider = ModpackHelper.getProviderByType(modpackConfiguration.getType()); if (provider != null) provider.injectLaunchOptions(jsonText, builder); } catch (IOException | JsonParseException e) { - e.printStackTrace(); + LOG.warning("Failed to parse modpack configuration file " + json, e); } } @@ -449,8 +453,8 @@ public class HMCLGameRepository extends DefaultGameRepository { } @Override - public File getModpackConfiguration(String version) { - return new File(getVersionRoot(version), "modpack.cfg"); + public Path getModpackConfiguration(String version) { + return getVersionRoot(version).resolve("modpack.cfg"); } public void markVersionAsModpack(String id) { @@ -463,16 +467,24 @@ public class HMCLGameRepository extends DefaultGameRepository { public void markVersionLaunchedAbnormally(String id) { try { - Files.createFile(getVersionRoot(id).toPath().resolve(".abnormal")); + Files.createFile(getVersionRoot(id).resolve(".abnormal")); } catch (IOException ignored) { } } public boolean unmarkVersionLaunchedAbnormally(String id) { - File file = new File(getVersionRoot(id), ".abnormal"); - boolean result = file.isFile(); - file.delete(); - return result; + Path file = getVersionRoot(id).resolve(".abnormal"); + if (Files.isRegularFile(file)) { + try { + Files.delete(file); + } catch (IOException e) { + LOG.warning("Failed to delete abnormal mark file: " + file, e); + } + + return true; + } else { + return false; + } } private static final Gson GSON = new GsonBuilder() diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackInstallTask.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackInstallTask.java index a6f04fcd4..5718f61e1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackInstallTask.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackInstallTask.java @@ -31,6 +31,8 @@ import org.jackhuang.hmcl.util.io.CompressingUtils; 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; @@ -51,9 +53,9 @@ public final class HMCLModpackInstallTask extends Task { this.name = name; this.modpack = modpack; - File run = repository.getRunDirectory(name); - File json = repository.getModpackConfiguration(name); - if (repository.hasVersion(name) && !json.exists()) + Path run = repository.getRunDirectory(name); + Path json = repository.getModpackConfiguration(name); + if (repository.hasVersion(name) && Files.notExists(json)) throw new IllegalArgumentException("Version " + name + " already exists"); dependents.add(dependency.gameBuilder().name(name).gameVersion(modpack.getGameVersion()).buildAsync()); @@ -64,16 +66,16 @@ public final class HMCLModpackInstallTask extends Task { ModpackConfiguration config = null; try { - if (json.exists()) { - config = JsonUtils.fromJsonFile(json.toPath(), ModpackConfiguration.typeOf(Modpack.class)); + if (Files.exists(json)) { + config = JsonUtils.fromJsonFile(json, ModpackConfiguration.typeOf(Modpack.class)); if (!HMCLModpackProvider.INSTANCE.getName().equals(config.getType())) throw new IllegalArgumentException("Version " + name + " is not a HMCL modpack. Cannot update this version."); } } catch (JsonParseException | IOException ignore) { } - dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), Collections.singletonList("/minecraft"), it -> !"pack.json".equals(it), config)); - dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), Collections.singletonList("/minecraft"), modpack, HMCLModpackProvider.INSTANCE, modpack.getName(), modpack.getVersion(), repository.getModpackConfiguration(name)).withStage("hmcl.modpack")); + dependents.add(new ModpackInstallTask<>(zipFile, run.toFile(), modpack.getEncoding(), Collections.singletonList("/minecraft"), it -> !"pack.json".equals(it), config)); + dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), Collections.singletonList("/minecraft"), modpack, HMCLModpackProvider.INSTANCE, modpack.getName(), modpack.getVersion(), repository.getModpackConfiguration(name).toFile()).withStage("hmcl.modpack")); } @Override diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java index 5b9cd51d7..412119bba 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java @@ -55,6 +55,7 @@ import java.io.IOException; import java.net.SocketTimeoutException; import java.net.URI; import java.nio.file.AccessDeniedException; +import java.nio.file.Path; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; @@ -150,7 +151,7 @@ public final class LauncherHelper { dependencyManager.checkGameCompletionAsync(version.get(), integrityCheck), Task.composeAsync(() -> { try { - ModpackConfiguration configuration = ModpackHelper.readModpackConfiguration(repository.getModpackConfiguration(selectedVersion)); + ModpackConfiguration configuration = ModpackHelper.readModpackConfiguration(repository.getModpackConfiguration(selectedVersion).toFile()); ModpackProvider provider = ModpackHelper.getProviderByType(configuration.getType()); if (provider == null) return null; else return provider.createCompletionTask(dependencyManager, selectedVersion); @@ -164,16 +165,16 @@ public final class LauncherHelper { Library lib = NativePatcher.getWindowsMesaLoader(java, renderer, OperatingSystem.SYSTEM_VERSION); if (lib == null) return null; - File file = dependencyManager.getGameRepository().getLibraryFile(version.get(), lib); - if (file.getAbsolutePath().indexOf('=') >= 0) { + Path file = dependencyManager.getGameRepository().getLibraryFile(version.get(), lib); + if (file.toAbsolutePath().toString().indexOf('=') >= 0) { LOG.warning("Invalid character '=' in the libraries directory path, unable to attach software renderer loader"); return null; } - String agent = file.getAbsolutePath() + "=" + renderer.name().toLowerCase(Locale.ROOT); + String agent = FileUtils.getAbsolutePath(file) + "=" + renderer.name().toLowerCase(Locale.ROOT); if (GameLibrariesTask.shouldDownloadLibrary(repository, version.get(), lib, integrityCheck)) { - return new LibraryDownloadTask(dependencyManager, file.toPath(), lib) + return new LibraryDownloadTask(dependencyManager, file, lib) .thenRunAsync(() -> javaAgents.add(agent)); } else { javaAgents.add(agent); @@ -189,7 +190,7 @@ public final class LauncherHelper { .thenComposeAsync(() -> logIn(account).withStage("launch.state.logging_in")) .thenComposeAsync(authInfo -> Task.supplyAsync(() -> { LaunchOptions launchOptions = repository.getLaunchOptions( - selectedVersion, javaVersionRef.get(), profile.getGameDir(), javaAgents, javaArguments, scriptFile != null); + selectedVersion, javaVersionRef.get(), profile.getGameDir().toPath(), javaAgents, javaArguments, scriptFile != null); LOG.info("Here's the structure of game mod directory:\n" + FileUtils.printFileStructure(repository.getModManager(selectedVersion).getModsDirectory(), 10)); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/LogExporter.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/LogExporter.java index 9aed6454f..3cb59219e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LogExporter.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LogExporter.java @@ -44,8 +44,8 @@ public final class LogExporter { } public static CompletableFuture exportLogs(Path zipFile, DefaultGameRepository gameRepository, String versionId, String logs, String launchScript) { - Path runDirectory = gameRepository.getRunDirectory(versionId).toPath(); - Path baseDirectory = gameRepository.getBaseDirectory().toPath(); + Path runDirectory = gameRepository.getRunDirectory(versionId); + Path baseDirectory = gameRepository.getBaseDirectory(); List versions = new ArrayList<>(); String currentVersionId = versionId; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Profile.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Profile.java index 239eef2ec..8472d7fd2 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Profile.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Profile.java @@ -132,12 +132,12 @@ public final class Profile implements Observable { public Profile(String name, File initialGameDir, VersionSetting global, String selectedVersion, boolean useRelativePath) { this.name = new SimpleStringProperty(this, "name", name); gameDir = new SimpleObjectProperty<>(this, "gameDir", initialGameDir); - repository = new HMCLGameRepository(this, initialGameDir); + repository = new HMCLGameRepository(this, initialGameDir.toPath()); this.global.set(global == null ? new VersionSetting() : global); this.selectedVersion.set(selectedVersion); this.useRelativePath.set(useRelativePath); - gameDir.addListener((a, b, newValue) -> repository.changeDirectory(newValue)); + gameDir.addListener((a, b, newValue) -> repository.changeDirectory(newValue.toPath())); this.selectedVersion.addListener(o -> checkSelectedVersion()); listenerHolder.add(EventBus.EVENT_BUS.channel(RefreshedVersionsEvent.class).registerWeak(event -> checkSelectedVersion(), EventPriority.HIGHEST)); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java index c522620c3..13506ce21 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java @@ -129,7 +129,7 @@ public class GameCrashWindow extends Stage { return pair(CrashReportAnalyzer.analyze(rawLog), crashReport != null ? CrashReportAnalyzer.findKeywordsFromCrashReport(crashReport) : new HashSet<>()); }), Task.supplyAsync(() -> { - Path latestLog = repository.getRunDirectory(version.getId()).toPath().resolve("logs/latest.log"); + Path latestLog = repository.getRunDirectory(version.getId()).resolve("logs/latest.log"); if (!Files.isReadable(latestLog)) { return pair(new HashSet(), new HashSet()); } @@ -379,7 +379,7 @@ public class GameCrashWindow extends Stage { TwoLineListItem gameDir = new TwoLineListItem(); gameDir.getStyleClass().setAll("two-line-item-second-large"); gameDir.setTitle(i18n("game.directory")); - gameDir.setSubtitle(launchOptions.getGameDir().getAbsolutePath()); + gameDir.setSubtitle(launchOptions.getGameDir().toAbsolutePath().toString()); FXUtils.installFastTooltip(gameDir, i18n("game.directory")); TwoLineListItem javaDir = new TwoLineListItem(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java index c3d6ed011..3ea1e84c3 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java @@ -145,7 +145,7 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage public static void download(Profile profile, @Nullable String version, RemoteMod.Version file, String subdirectoryName) { if (version == null) version = profile.getSelectedVersion(); - Path runDirectory = profile.getRepository().hasVersion(version) ? profile.getRepository().getRunDirectory(version).toPath() : profile.getRepository().getBaseDirectory().toPath(); + Path runDirectory = profile.getRepository().hasVersion(version) ? profile.getRepository().getRunDirectory(version) : profile.getRepository().getBaseDirectory(); Controllers.prompt(i18n("archive.file.name"), (result, resolve, reject) -> { if (!FileUtils.isNameValid(result)) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java index f45009203..c7c42b1b2 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java @@ -95,9 +95,9 @@ public class ModpackInstallWizardProvider implements WizardProvider { } try { if (serverModpackManifest != null) { - return ModpackHelper.getUpdateTask(profile, serverModpackManifest, modpack.getEncoding(), name, ModpackHelper.readModpackConfiguration(profile.getRepository().getModpackConfiguration(name))); + return ModpackHelper.getUpdateTask(profile, serverModpackManifest, modpack.getEncoding(), name, ModpackHelper.readModpackConfiguration(profile.getRepository().getModpackConfiguration(name).toFile())); } else { - return ModpackHelper.getUpdateTask(profile, selected, modpack.getEncoding(), name, ModpackHelper.readModpackConfiguration(profile.getRepository().getModpackConfiguration(name))); + return ModpackHelper.getUpdateTask(profile, selected, modpack.getEncoding(), name, ModpackHelper.readModpackConfiguration(profile.getRepository().getModpackConfiguration(name).toFile())); } } catch (UnsupportedModpackException | ManuallyCreatedModpackException e) { Controllers.dialog(i18n("modpack.unsupported"), i18n("message.error"), MessageType.ERROR); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ModpackFileSelectionPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ModpackFileSelectionPage.java index 379345ee4..a4c44be46 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ModpackFileSelectionPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ModpackFileSelectionPage.java @@ -61,7 +61,7 @@ public final class ModpackFileSelectionPage extends BorderPane implements Wizard this.adviser = adviser; JFXTreeView treeView = new JFXTreeView<>(); - rootNode = getTreeItem(profile.getRepository().getRunDirectory(version), "minecraft"); + rootNode = getTreeItem(profile.getRepository().getRunDirectory(version).toFile(), "minecraft"); treeView.setRoot(rootNode); treeView.setSelectionModel(new NoneMultipleSelectionModel<>()); this.setCenter(treeView); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java index c47cb30df..2cbf8e73f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java @@ -245,12 +245,12 @@ public final class AdvancedVersionSettingPage extends StackPane implements Decor String nativesDirName = "natives-" + Platform.SYSTEM_PLATFORM; if (versionId == null) { return String.format("%s/%s/%s", - profile.getRepository().getBaseDirectory().toPath().resolve("versions").toAbsolutePath().normalize(), + profile.getRepository().getBaseDirectory().resolve("versions").toAbsolutePath().normalize(), i18n("settings.advanced.natives_directory.default.version_id"), nativesDirName ); } else { - return profile.getRepository().getVersionRoot(versionId).toPath() + return profile.getRepository().getVersionRoot(versionId) .toAbsolutePath().normalize() .resolve(nativesDirName) .toString(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPage.java index 4e75a8b07..ef41185ee 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPage.java @@ -175,7 +175,7 @@ public final class ModListPage extends ListPageBase Paths.get(profile.getRepository().getRunDirectory(versionId).getAbsolutePath()).normalize().toString(), + gameDirSublist.subtitleProperty().bind(Bindings.createStringBinding(() -> profile.getRepository().getRunDirectory(versionId).toAbsolutePath().normalize().toString(), versionSetting.gameDirProperty(), versionSetting.gameDirTypeProperty())); lastVersionSetting = versionSetting; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java index 50bb72824..ae5d5ce0f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java @@ -143,7 +143,7 @@ public final class Versions { } public static void openFolder(Profile profile, String version) { - FXUtils.openFolder(profile.getRepository().getRunDirectory(version)); + FXUtils.openFolder(profile.getRepository().getRunDirectory(version).toFile()); } public static void duplicateVersion(Profile profile, String version) { @@ -193,8 +193,8 @@ public final class Versions { ensureSelectedAccount(account -> { GameRepository repository = profile.getRepository(); FileChooser chooser = new FileChooser(); - if (repository.getRunDirectory(id).isDirectory()) - chooser.setInitialDirectory(repository.getRunDirectory(id)); + if (Files.isDirectory(repository.getRunDirectory(id))) + chooser.setInitialDirectory(repository.getRunDirectory(id).toFile()); chooser.setTitle(i18n("version.launch_script.save")); chooser.getExtensionFilters().add(OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS ? new FileChooser.ExtensionFilter(i18n("extension.bat"), "*.bat") diff --git a/HMCL/src/test/java/org/jackhuang/hmcl/ui/GameCrashWindowTest.java b/HMCL/src/test/java/org/jackhuang/hmcl/ui/GameCrashWindowTest.java index 398c307d5..248e027c0 100644 --- a/HMCL/src/test/java/org/jackhuang/hmcl/ui/GameCrashWindowTest.java +++ b/HMCL/src/test/java/org/jackhuang/hmcl/ui/GameCrashWindowTest.java @@ -31,7 +31,7 @@ import org.junit.jupiter.api.Test; import java.io.File; import java.nio.file.Files; -import java.nio.file.Paths; +import java.nio.file.Path; import java.util.Arrays; import java.util.concurrent.CountDownLatch; import java.util.stream.Collectors; @@ -49,11 +49,13 @@ public class GameCrashWindowTest { CountDownLatch latch = new CountDownLatch(1); FXUtils.runInFX(() -> { + Path workingPath = Path.of(System.getProperty("user.dir")); + GameCrashWindow window = new GameCrashWindow(process, ProcessListener.ExitType.APPLICATION_ERROR, null, new ClassicVersion(), new LaunchOptions.Builder() - .setJava(new JavaRuntime(Paths.get("."), new JavaInfo(Platform.SYSTEM_PLATFORM, "16", null), false, false)) - .setGameDir(new File(".")) + .setJava(new JavaRuntime(workingPath, new JavaInfo(Platform.SYSTEM_PLATFORM, "16", null), false, false)) + .setGameDir(workingPath) .create(), Arrays.stream(logs.split("\\n")) .map(Log::new) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java index 7ee49baef..d1a223e9e 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java @@ -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))); } } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MaintainTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MaintainTask.java index 60e2b6c37..dc57fdf34 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MaintainTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MaintainTask.java @@ -160,7 +160,7 @@ public class MaintainTask extends Task { 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 { // 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 { 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, diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricAPIInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricAPIInstallTask.java index a5c89f387..90c5f388a 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricAPIInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricAPIInstallTask.java @@ -59,7 +59,7 @@ public final class FabricAPIInstallTask extends Task { 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()) ); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java index 73e1b0bab..6eb87c75f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java @@ -284,7 +284,7 @@ public class ForgeNewInstallTask extends Task { 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 { } 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()); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeOldInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeOldInstallTask.java index 8b91fd98b..61aa3ea33 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeOldInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeOldInstallTask.java @@ -72,7 +72,7 @@ public class ForgeOldInstallTask extends Task { // 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()); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameDownloadTask.java index 1123aecd6..c50596836 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameDownloadTask.java @@ -53,7 +53,7 @@ public final class GameDownloadTask extends Task { @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()), diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameLibrariesTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameLibrariesTask.java index a27fb5b31..700c47428 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameLibrariesTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameLibrariesTask.java @@ -88,7 +88,7 @@ public final class GameLibrariesTask extends Task { } 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 { && gameRepository instanceof DefaultGameRepository defaultGameRepository) { List 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 { } } - 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) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameVerificationFixTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameVerificationFixTask.java index c76b8b754..33407066e 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameVerificationFixTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameVerificationFixTask.java @@ -62,7 +62,7 @@ public final class GameVerificationFixTask extends Task { @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)) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/VersionJsonSaveTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/VersionJsonSaveTask.java index a21dbc5f4..c60265947 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/VersionJsonSaveTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/VersionJsonSaveTask.java @@ -51,7 +51,7 @@ public final class VersionJsonSaveTask extends Task { @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); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/neoforge/NeoForgeOldInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/neoforge/NeoForgeOldInstallTask.java index eeb6b03b6..2a7912aef 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/neoforge/NeoForgeOldInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/neoforge/NeoForgeOldInstallTask.java @@ -280,7 +280,7 @@ public class NeoForgeOldInstallTask extends Task { 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 { } 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()); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java index a4f68eb53..f2a87307e 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java @@ -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 { List 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 { // 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 { 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 { 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); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIInstallTask.java index f849023f6..b0d9eb2bf 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIInstallTask.java @@ -59,7 +59,7 @@ public final class QuiltAPIInstallTask extends Task { 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()) ); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/ClassicVersion.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/ClassicVersion.java index 42c8683a5..17bf52067 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/ClassicVersion.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/ClassicVersion.java @@ -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")); } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepository.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepository.java index cdf3127c0..01ab66175 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepository.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepository.java @@ -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 versions; - private final ConcurrentHashMap> gameVersions = new ConcurrentHashMap<>(); + private final ConcurrentHashMap> 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 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 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 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 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 diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameRepository.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameRepository.java index 33d4f60af..52a7cc1ef 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameRepository.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameRepository.java @@ -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. - * + *

* 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. - * + *

* 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. - * + *

* 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. - * + *

* 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. - * + *

* 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 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; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameVersion.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameVersion.java index 04188c885..140b2fd15 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameVersion.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameVersion.java @@ -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 minecraftVersion(File file) { - if (file == null || !file.exists() || !file.isFile() || !file.canRead()) + public static Optional 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 result = getVersionFromJson(gameJar.getInputStream(versionJson)); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/LaunchOptions.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/LaunchOptions.java index 310dbb241..88c75da94 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/LaunchOptions.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/LaunchOptions.java @@ -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; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/tlauncher/TLauncherLibrary.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/tlauncher/TLauncherLibrary.java index 3475fb310..9bf55a366 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/tlauncher/TLauncherLibrary.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/tlauncher/TLauncherLibrary.java @@ -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; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/tlauncher/TLauncherVersion.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/tlauncher/TLauncherVersion.java index 98d726162..d3d5095d5 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/tlauncher/TLauncherVersion.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/tlauncher/TLauncherVersion.java @@ -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; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index f1898243e..e664382d9 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -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 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 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 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 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 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) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModManager.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModManager.java index 69909323c..987b4808b 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModManager.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModManager.java @@ -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) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModpackUpdateTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModpackUpdateTask.java index c4e357b60..72108e26b 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModpackUpdateTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModpackUpdateTask.java @@ -38,7 +38,7 @@ public class ModpackUpdateTask extends Task { 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 { @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 { // Restore backup repository.removeVersionFromDisk(id); - FileUtils.copyDirectory(backupFolder, repository.getVersionRoot(id).toPath()); + FileUtils.copyDirectory(backupFolder, repository.getVersionRoot(id)); repository.refreshVersionsAsync().start(); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseCompletionTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseCompletionTask.java index 3f0ebbc94..bf8007f4f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseCompletionTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseCompletionTask.java @@ -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 { 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 { 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 { } }) .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 { /** * 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. */ diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseInstallTask.java index 7c5e4cee0..1d2e8b437 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseInstallTask.java @@ -68,10 +68,10 @@ public final class CurseInstallTask extends Task { 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 { ModpackConfiguration 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 { } 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 { } } - Path root = repository.getVersionRoot(name).toPath(); + Path root = repository.getVersionRoot(name); Files.createDirectories(root); JsonUtils.writeToJsonFile(root.resolve("manifest.json"), manifest); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackCompletionTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackCompletionTask.java index dc2e2c4dc..d313924d2 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackCompletionTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackCompletionTask.java @@ -73,7 +73,7 @@ public class McbbsModpackCompletionTask extends CompletableFutureTask { 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 { 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 localFiles = manifest.getFiles().stream().collect(Collectors.toMap(Function.identity(), Function.identity())); @@ -172,7 +172,7 @@ public class McbbsModpackCompletionTask extends CompletableFutureTask { 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 { @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; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackExportTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackExportTask.java index fabe37aec..796c82042 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackExportTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackExportTask.java @@ -67,7 +67,7 @@ public class McbbsModpackExportTask extends Task { 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 files = new ArrayList<>(); zip.putDirectory(runDirectory, "overrides", path -> { if (Modpack.acceptFile(path, blackList, info.getWhitelist())) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackLocalInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackLocalInstallTask.java index 70d51a976..042c00f62 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackLocalInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackLocalInstallTask.java @@ -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 { 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 { ModpackConfiguration 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")); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackRemoteInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackRemoteInstallTask.java index 491316c4e..b3a0e10e2 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackRemoteInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackRemoteInstallTask.java @@ -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 { 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 { ModpackConfiguration 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."); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthCompletionTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthCompletionTask.java index 043ed8824..452a114da 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthCompletionTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthCompletionTask.java @@ -79,7 +79,7 @@ public class ModrinthCompletionTask extends Task { 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 { 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()) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthInstallTask.java index ce406f4f2..6e875660c 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthInstallTask.java @@ -51,10 +51,10 @@ public class ModrinthInstallTask extends Task { 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 { ModpackConfiguration 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 { this.config = config; List 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 { } } - Path root = repository.getVersionRoot(name).toPath(); + Path root = repository.getVersionRoot(name); Files.createDirectories(root); JsonUtils.writeToJsonFile(root.resolve("modrinth.index.json"), manifest); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthModpackExportTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthModpackExportTask.java index 6366f0ef0..1ffe76db2 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthModpackExportTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthModpackExportTask.java @@ -108,7 +108,7 @@ public class ModrinthModpackExportTask extends Task { 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 files = new ArrayList<>(); Set filesInManifest = new HashSet<>(); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackExportTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackExportTask.java index 93670a4d5..b4a218797 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackExportTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackExportTask.java @@ -69,7 +69,7 @@ public class MultiMCModpackExportTask extends Task { 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)); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackInstallTask.java index e3db99fc5..716f4caad 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackInstallTask.java @@ -94,8 +94,8 @@ public final class MultiMCModpackInstallTask extends Task { @@ -113,13 +113,13 @@ public final class MultiMCModpackInstallTask extends Task 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(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 { 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 { dependencies.add(builder.buildAsync()); } - Path rootPath = repository.getVersionRoot(version).toPath().toAbsolutePath().normalize(); + Path rootPath = repository.getVersionRoot(version).toAbsolutePath().normalize(); Map files = manifest.getManifest().getFiles().stream() .collect(Collectors.toMap(ModpackConfiguration.FileInformation::getPath, Function.identity())); @@ -129,7 +128,7 @@ public class ServerModpackCompletionTask extends Task { Set 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 { @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())); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackExportTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackExportTask.java index e172f1850..1bf0d6069 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackExportTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackExportTask.java @@ -63,7 +63,7 @@ public class ServerModpackExportTask extends Task { 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 files = new ArrayList<>(); zip.putDirectory(runDirectory, "overrides", path -> { if (Modpack.acceptFile(path, blackList, exportInfo.getWhitelist())) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackLocalInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackLocalInstallTask.java index e49a6c9c5..d91cc114b 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackLocalInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackLocalInstallTask.java @@ -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 { 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 { ModpackConfiguration 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 diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackRemoteInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackRemoteInstallTask.java index 9282d5768..f1dd1ee9b 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackRemoteInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackRemoteInstallTask.java @@ -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 { 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 { ModpackConfiguration 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."); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/FileUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/FileUtils.java index cb5fb63b8..74a2c90c1 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/FileUtils.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/FileUtils.java @@ -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 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);