From 96f68e10177dfbec49890596d309dd1ac675a7a8 Mon Sep 17 00:00:00 2001 From: Glavo Date: Fri, 25 Jul 2025 17:02:37 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8D=E5=86=8D=E4=BD=BF=E7=94=A8=E5=8F=8D?= =?UTF-8?q?=E5=B0=84=E8=B0=83=E7=94=A8=20Java=209~11=20=E4=B8=AD=E5=BC=95?= =?UTF-8?q?=E5=85=A5=E7=9A=84=20API=20(#4114)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/jackhuang/hmcl/EntryPoint.java | 24 +++- .../jackhuang/hmcl/setting/FontManager.java | 63 ++++----- .../java/org/jackhuang/hmcl/ui/FXUtils.java | 11 +- .../java/org/jackhuang/hmcl/ui/LogWindow.java | 2 +- .../jackhuang/hmcl/ui/TooltipInstaller.java | 123 ------------------ .../jackhuang/hmcl/ui/versions/Versions.java | 5 +- .../org/jackhuang/hmcl/util/ModuleHelper.java | 46 ------- .../resources/assets/lang/I18N.properties | 1 - .../resources/assets/lang/I18N_es.properties | 1 - .../resources/assets/lang/I18N_ja.properties | 1 - .../resources/assets/lang/I18N_ru.properties | 1 - .../resources/assets/lang/I18N_zh.properties | 1 - .../assets/lang/I18N_zh_CN.properties | 1 - .../org/jackhuang/hmcl/JavaFXLauncher.java | 18 +-- .../hmcl/game/DefaultGameRepository.java | 2 +- .../org/jackhuang/hmcl/util/StringUtils.java | 2 +- .../hmcl/util/io/CompressingUtils.java | 9 +- .../org/jackhuang/hmcl/util/io/FileUtils.java | 33 +---- .../org/jackhuang/hmcl/util/io/IOUtils.java | 6 +- .../jackhuang/hmcl/util/logging/Logger.java | 2 +- .../hmcl/util/platform/ManagedProcess.java | 45 ------- .../hmcl/util/platform/SystemUtils.java | 3 +- .../org/jackhuang/hmcl/JavaFXLauncher.java | 18 +-- 23 files changed, 64 insertions(+), 354 deletions(-) delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/TooltipInstaller.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/util/ModuleHelper.java diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/EntryPoint.java b/HMCL/src/main/java/org/jackhuang/hmcl/EntryPoint.java index 8b9fe5cb5..9b431705c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/EntryPoint.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/EntryPoint.java @@ -19,14 +19,15 @@ package org.jackhuang.hmcl; import org.jackhuang.hmcl.util.FileSaver; import org.jackhuang.hmcl.ui.AwtUtils; -import org.jackhuang.hmcl.util.ModuleHelper; import org.jackhuang.hmcl.util.SelfDependencyPatcher; import org.jackhuang.hmcl.util.SwingUtils; import org.jackhuang.hmcl.java.JavaRuntime; import org.jackhuang.hmcl.util.platform.OperatingSystem; import java.io.IOException; -import java.lang.reflect.Method; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.nio.file.Files; import java.util.concurrent.CancellationException; @@ -140,7 +141,18 @@ public final class EntryPoint { private static void addEnableNativeAccess() { if (JavaRuntime.CURRENT_VERSION > 21) { try { - ModuleHelper.addEnableNativeAccess(Class.forName("javafx.stage.Stage")); // javafx.graphics + // javafx.graphics + Module module = Class.forName("javafx.stage.Stage").getModule(); + if (module.isNamed()) { + try { + MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Module.class, MethodHandles.lookup()); + MethodHandle implAddEnableNativeAccess = lookup.findVirtual(Module.class, + "implAddEnableNativeAccess", MethodType.methodType(Module.class)); + Module ignored = (Module) implAddEnableNativeAccess.invokeExact(module); + } catch (Throwable e) { + e.printStackTrace(System.err); + } + } } catch (ClassNotFoundException e) { LOG.error("Failed to add enable native access for JavaFX", e); showErrorAndExit(i18n("fatal.javafx.incomplete")); @@ -153,9 +165,9 @@ public final class EntryPoint { if (JavaRuntime.CURRENT_VERSION == 24 || JavaRuntime.CURRENT_VERSION == 25) { try { Class clazz = Class.forName("sun.misc.Unsafe"); - Method trySetMemoryAccessWarned = clazz.getDeclaredMethod("trySetMemoryAccessWarned"); - trySetMemoryAccessWarned.setAccessible(true); - trySetMemoryAccessWarned.invoke(null); + boolean ignored = (boolean) MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()) + .findStatic(clazz, "trySetMemoryAccessWarned", MethodType.methodType(boolean.class)) + .invokeExact(); } catch (Throwable e) { LOG.warning("Failed to enable unsafe memory access", e); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/FontManager.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/FontManager.java index 05b68ca4f..126adee54 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/FontManager.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/FontManager.java @@ -21,7 +21,6 @@ import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.scene.text.Font; import org.jackhuang.hmcl.Metadata; -import org.jackhuang.hmcl.java.JavaRuntime; import org.jackhuang.hmcl.util.Lazy; import org.jackhuang.hmcl.util.io.JarUtils; import org.jackhuang.hmcl.util.platform.OperatingSystem; @@ -29,9 +28,6 @@ import org.jackhuang.hmcl.util.platform.SystemUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.net.MalformedURLException; import java.nio.file.Files; import java.nio.file.Path; @@ -152,46 +148,33 @@ public final class FontManager { return null; } - if (JavaRuntime.CURRENT_VERSION >= 9) { - try { - MethodHandle methodHandle = MethodHandles.publicLookup().findStatic(Font.class, "loadFonts", - MethodType.methodType(Font[].class, String.class, double.class)); + Font[] fonts = Font.loadFonts(file.toUri().toURL().toExternalForm(), DEFAULT_FONT_SIZE); + if (fonts == null) { + LOG.warning("Failed to load font from " + path); + return null; + } else if (fonts.length == 0) { + LOG.warning("No fonts loaded from " + path); + return null; + } - Font[] fonts = (Font[]) methodHandle.invokeExact(file.toUri().toURL().toExternalForm(), DEFAULT_FONT_SIZE); - if (fonts == null) { - LOG.warning("Failed to load font from " + path); - return null; - } else if (fonts.length == 0) { - LOG.warning("No fonts loaded from " + path); - return null; - } - - for (Font font : fonts) { - if (font.getFamily().equalsIgnoreCase(family)) { - return font; - } - } - - if (family.indexOf(',') >= 0) { - for (String candidateFamily : family.split(",")) { - for (Font font : fonts) { - if (font.getFamily().equalsIgnoreCase(candidateFamily)) { - return font; - } - } - } - } - - LOG.warning(String.format("Family '%s' not found in font file '%s'", family, path)); - return fonts[0]; - } catch (NoSuchMethodException | IllegalAccessException ignored) { + for (Font font : fonts) { + if (font.getFamily().equalsIgnoreCase(family)) { + return font; } } - Font font = Font.loadFont(file.toUri().toURL().toExternalForm(), DEFAULT_FONT_SIZE); - if (font == null) - LOG.warning("Failed to load font from " + path); - return font; + if (family.indexOf(',') >= 0) { + for (String candidateFamily : family.split(",")) { + for (Font font : fonts) { + if (font.getFamily().equalsIgnoreCase(candidateFamily)) { + return font; + } + } + } + } + + LOG.warning(String.format("Family '%s' not found in font file '%s'", family, path)); + return fonts[0]; } catch (Throwable e) { LOG.warning("Failed to get default font with fc-match", e); return null; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java index b57959142..ba4eb2554 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java @@ -328,8 +328,15 @@ public final class FXUtils { private static final Duration TOOLTIP_SLOW_SHOW_DELAY = Duration.millis(500); private static final Duration TOOLTIP_SHOW_DURATION = Duration.millis(5000); + public static void installTooltip(Node node, Duration showDelay, Duration showDuration, Duration hideDelay, Tooltip tooltip) { + tooltip.setShowDelay(showDelay); + tooltip.setShowDuration(showDuration); + tooltip.setHideDelay(hideDelay); + Tooltip.install(node, tooltip); + } + public static void installFastTooltip(Node node, Tooltip tooltip) { - runInFX(() -> TooltipInstaller.INSTALLER.installTooltip(node, TOOLTIP_FAST_SHOW_DELAY, TOOLTIP_SHOW_DURATION, Duration.ZERO, tooltip)); + runInFX(() -> installTooltip(node, TOOLTIP_FAST_SHOW_DELAY, TOOLTIP_SHOW_DURATION, Duration.ZERO, tooltip)); } public static void installFastTooltip(Node node, String tooltip) { @@ -337,7 +344,7 @@ public final class FXUtils { } public static void installSlowTooltip(Node node, Tooltip tooltip) { - runInFX(() -> TooltipInstaller.INSTALLER.installTooltip(node, TOOLTIP_SLOW_SHOW_DELAY, TOOLTIP_SHOW_DURATION, Duration.ZERO, tooltip)); + runInFX(() -> installTooltip(node, TOOLTIP_SLOW_SHOW_DELAY, TOOLTIP_SHOW_DURATION, Duration.ZERO, tooltip)); } public static void installSlowTooltip(Node node, String tooltip) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java index 992e63817..610dac8c9 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java @@ -224,7 +224,7 @@ public final class LogWindow extends Stage { try { if (gameProcess.isRunning()) { - GameDumpGenerator.writeDumpTo(gameProcess.getPID(), dumpFile); + GameDumpGenerator.writeDumpTo(gameProcess.getProcess().pid(), dumpFile); FXUtils.showFileInExplorer(dumpFile); } } catch (Throwable e) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/TooltipInstaller.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/TooltipInstaller.java deleted file mode 100644 index acc1530d1..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/TooltipInstaller.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2024 huangyuhui and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.jackhuang.hmcl.ui; - -import javafx.scene.Node; -import javafx.scene.control.Tooltip; -import javafx.util.Duration; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; - -import static org.jackhuang.hmcl.util.logging.Logger.LOG; - -/** - * @author Glavo - */ -public class TooltipInstaller { - public static final TooltipInstaller INSTALLER; - - static { - TooltipInstaller installer = null; - - try { - installer = new NewInstaller(); - } catch (Throwable e) { - try { - installer = new OldInstaller(); - } catch (Throwable e2) { - e2.addSuppressed(e); - LOG.warning("Failed to initialize TooltipInstaller", e2); - } - } - - INSTALLER = installer != null ? installer : new TooltipInstaller(); - } - - TooltipInstaller() { - } - - public void installTooltip(Node node, Duration showDelay, Duration showDuration, Duration hideDelay, Tooltip tooltip) { - Tooltip.install(node, tooltip); - } - - // For Java 8 - private static final class OldInstaller extends TooltipInstaller { - private static final Constructor createTooltipBehavior; - private static final Method installTooltipBehavior; - - static { - try { - Class behaviorClass = Class.forName("javafx.scene.control.Tooltip$TooltipBehavior"); - createTooltipBehavior = behaviorClass.getDeclaredConstructor(Duration.class, Duration.class, Duration.class, boolean.class); - createTooltipBehavior.setAccessible(true); - installTooltipBehavior = behaviorClass.getDeclaredMethod("install", Node.class, Tooltip.class); - installTooltipBehavior.setAccessible(true); - } catch (Exception e) { - throw new ExceptionInInitializerError(e); - } - } - - @Override - public void installTooltip(Node node, Duration showDelay, Duration showDuration, Duration hideDelay, Tooltip tooltip) { - try { - Object behavior = createTooltipBehavior.newInstance(showDelay, showDuration, hideDelay, false); - installTooltipBehavior.invoke(behavior, node, tooltip); - } catch (ReflectiveOperationException e) { - LOG.warning("Failed to set tooltip show delay", e); - Tooltip.install(node, tooltip); - } - } - } - - // For Java 9+ - private static final class NewInstaller extends TooltipInstaller { - private static final MethodHandle setTooltipShowDelay; - private static final MethodHandle setTooltipShowDuration; - private static final MethodHandle setTooltipHideDelay; - - static { - try { - MethodHandles.Lookup lookup = MethodHandles.publicLookup(); - MethodType methodType = MethodType.methodType(void.class, Duration.class); - - setTooltipShowDelay = lookup.findVirtual(Tooltip.class, "setShowDelay", methodType); - setTooltipShowDuration = lookup.findVirtual(Tooltip.class, "setShowDuration", methodType); - setTooltipHideDelay = lookup.findVirtual(Tooltip.class, "setHideDelay", methodType); - } catch (Exception e) { - throw new ExceptionInInitializerError(e); - } - } - - @Override - public void installTooltip(Node node, Duration showDelay, Duration showDuration, Duration hideDelay, Tooltip tooltip) { - try { - setTooltipShowDelay.invokeExact(tooltip, showDelay); - setTooltipShowDuration.invokeExact(tooltip, showDuration); - setTooltipHideDelay.invokeExact(tooltip, hideDelay); - } catch (Throwable e) { - LOG.warning("Failed to set tooltip show delay", e); - } - - Tooltip.install(node, tooltip); - } - } -} 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 35b60e6fd..a9ff73ec6 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 @@ -43,7 +43,6 @@ import org.jackhuang.hmcl.ui.download.ModpackInstallWizardProvider; import org.jackhuang.hmcl.ui.export.ExportWizardProvider; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.TaskCancellationAction; -import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.platform.OperatingSystem; import java.io.File; @@ -110,10 +109,8 @@ public final class Versions { public static void deleteVersion(Profile profile, String version) { boolean isIndependent = profile.getVersionSetting(version).getGameDirType() == GameDirectoryType.VERSION_FOLDER; - boolean isMovingToTrashSupported = FileUtils.isMovingToTrashSupported(); String message = isIndependent ? i18n("version.manage.remove.confirm.independent", version) : - isMovingToTrashSupported ? i18n("version.manage.remove.confirm.trash", version, version + "_removed") : - i18n("version.manage.remove.confirm", version); + i18n("version.manage.remove.confirm.trash", version, version + "_removed"); JFXButton deleteButton = new JFXButton(i18n("button.delete")); deleteButton.getStyleClass().add("dialog-error"); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/ModuleHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/ModuleHelper.java deleted file mode 100644 index f578d11dc..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/ModuleHelper.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2025 huangyuhui and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.jackhuang.hmcl.util; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -/** - * @author Glavo - */ -public final class ModuleHelper { - - public static void addEnableNativeAccess(Class clazzInModule) { - Module module = clazzInModule.getModule(); - if (module.isNamed()) { - try { - MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Module.class, MethodHandles.lookup()); - MethodHandle implAddEnableNativeAccess = lookup.findVirtual(Module.class, "implAddEnableNativeAccess", MethodType.methodType(Module.class)); - Module ignored = (Module) implAddEnableNativeAccess.invokeExact(module); - } catch (Throwable e) { - e.printStackTrace(System.err); - } - } else { - System.err.println("TODO: Add enable native access for anonymous modules is not yet supported"); - } - } - - private ModuleHelper() { - } -} diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index b980594cc..944483bf9 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -1433,7 +1433,6 @@ version.manage.manage=Edit Instance version.manage.manage.title=Edit Instance - %1s version.manage.redownload_assets_index=Update Game Assets version.manage.remove=Delete Instance -version.manage.remove.confirm=Are you sure you want to permanently remove the instance "%s"? This operation cannot be undone!!! version.manage.remove.confirm.trash=Are you sure you want to remove the instance "%s"? You can still find its files in your recycle bin by the name of "%s". version.manage.remove.confirm.independent=Since this instance is stored in an isolated directory, deleting it will also delete its saves and other data. Do you still want to delete the instance "%s"? version.manage.remove_assets=Delete All Assets diff --git a/HMCL/src/main/resources/assets/lang/I18N_es.properties b/HMCL/src/main/resources/assets/lang/I18N_es.properties index 14ab218c6..01bf5fe29 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_es.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_es.properties @@ -1406,7 +1406,6 @@ version.manage.manage=Editar instancia version.manage.manage.title=Editar instancia - %1s version.manage.redownload_assets_index=Actualizar activos del juego version.manage.remove=Eliminar instancia -version.manage.remove.confirm=¿Está seguro de que quiere eliminar permanentemente la instancia «%s»? ¡Esta operación no se puede deshacer! version.manage.remove.confirm.trash=¿Estás seguro de que quieres eliminar la instancia «%s»? Todavía puedes encontrar sus archivos en tu papelera de reciclaje con el nombre de «%s». version.manage.remove.confirm.independent=Dado que esta instancia está almacenada en un directorio aislado, al eliminarla también se eliminarán sus guardados y otros datos. ¿Aún quieres borrar la instancia %s? version.manage.remove_assets=Borrar todas las activos del juego diff --git a/HMCL/src/main/resources/assets/lang/I18N_ja.properties b/HMCL/src/main/resources/assets/lang/I18N_ja.properties index 269328655..609bef992 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ja.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ja.properties @@ -949,7 +949,6 @@ version.manage.manage=バージョンの管理 version.manage.manage.title=バージョンの管理 - %1s version.manage.redownload_assets_index=ゲームアセットファイルの更新 version.manage.remove=このバージョンを削除します -version.manage.remove.confirm=このバージョン %s を削除してもよろしいですか?このバージョンを再度復元することはできません。 version.manage.remove.confirm.trash=このバージョン %s を削除してもよろしいですか?このバージョンは、システムのゴミ箱に %s という名前で復元できます。 version.manage.remove.confirm.independent=このバージョンは独立モードであるため、このバージョンを削除すると、このバージョンに属するすべての保存済みワールドも削除されます。このバージョン %s を削除しますか? version.manage.remove_assets=すべてのゲームリソースファイルの削除 diff --git a/HMCL/src/main/resources/assets/lang/I18N_ru.properties b/HMCL/src/main/resources/assets/lang/I18N_ru.properties index d466a3614..106204076 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ru.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ru.properties @@ -1406,7 +1406,6 @@ version.manage.manage=Изменить сборку version.manage.manage.title=Изменить сборку - %1s version.manage.redownload_assets_index=Обновить файлы игровых активов version.manage.remove=Удалить -version.manage.remove.confirm=Удалить %s? Вы не сможете восстановить эту сборку снова! version.manage.remove.confirm.trash=Удалить %s? Вы можете восстановить эту сборку с именем %s из корзины системы. version.manage.remove.confirm.independent=Поскольку эта сборка находится в режиме разделения, удаление этой сборки приведет к удалению всех миров, принадлежащих этой сборке. Удалить %s? version.manage.remove_assets=Удалить файлы игровых активов diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 093be9232..d8f6cd336 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -1226,7 +1226,6 @@ version.manage.manage=實例管理 version.manage.manage.title=實例管理 - %1s version.manage.redownload_assets_index=更新遊戲資源檔案 version.manage.remove=刪除該實例 -version.manage.remove.confirm=真的要刪除實例「%s」嗎? 你將無法找回被刪除的檔案!!! version.manage.remove.confirm.trash=真的要刪除實例「%s」嗎? 你可以在系統的資源回收筒 (或垃圾桶) 中還原目錄「%s」來找回該實例。 version.manage.remove.confirm.independent=由於該實例啟用了「(全域/實例特定) 遊戲設定 → 執行路徑 → 各實例獨立」設定,刪除該實例將導致該遊戲的存檔等資料一同被刪除!真的要刪除實例「%s」嗎? version.manage.remove_assets=刪除所有遊戲資源檔案 diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index ecff01608..381af086a 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1236,7 +1236,6 @@ version.manage.manage=版本管理 version.manage.manage.title=版本管理 - %1s version.manage.redownload_assets_index=更新游戏资源文件 version.manage.remove=删除该版本 -version.manage.remove.confirm=真的要删除版本“%s”吗?你将无法找回被删除的文件!!! version.manage.remove.confirm.trash=真的要删除版本“%s”吗?你可以在系统的回收站中还原“%s”文件夹来找回该版本。 version.manage.remove.confirm.independent=由于该游戏启用了“(全局/版本特定) 游戏设置 → 版本隔离 → 各版本独立”选项,删除该版本将导致该游戏的存档等数据一同被删除!真的要删除版本“%s”吗? version.manage.remove_assets=删除所有游戏资源文件 diff --git a/HMCL/src/test/java/org/jackhuang/hmcl/JavaFXLauncher.java b/HMCL/src/test/java/org/jackhuang/hmcl/JavaFXLauncher.java index a4cbcb924..c59de8f7c 100644 --- a/HMCL/src/test/java/org/jackhuang/hmcl/JavaFXLauncher.java +++ b/HMCL/src/test/java/org/jackhuang/hmcl/JavaFXLauncher.java @@ -17,10 +17,6 @@ */ package org.jackhuang.hmcl; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - public final class JavaFXLauncher { private JavaFXLauncher() { @@ -31,21 +27,9 @@ public final class JavaFXLauncher { static { // init JavaFX Toolkit try { - // Java 9 or Latter - final MethodHandle startup = - MethodHandles.publicLookup().findStatic( - javafx.application.Platform.class, "startup", MethodType.methodType(void.class, Runnable.class)); - startup.invokeExact((Runnable) () -> { + javafx.application.Platform.startup(() -> { }); started = true; - } catch (NoSuchMethodException e) { - // Java 8 - try { - Class.forName("javafx.embed.swing.JFXPanel").getDeclaredConstructor().newInstance(); - started = true; - } catch (Throwable e0) { - e0.printStackTrace(); - } } catch (IllegalStateException e) { started = true; } catch (Throwable e) { 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 dfb082ac2..304916b4f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepository.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepository.java @@ -246,7 +246,7 @@ public class DefaultGameRepository implements GameRepository { try { versions.remove(id); - if (FileUtils.isMovingToTrashSupported() && FileUtils.moveToTrash(removedFile)) { + if (FileUtils.moveToTrash(removedFile)) { return true; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/StringUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/StringUtils.java index 8d2461e01..ccb9a3014 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/StringUtils.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/StringUtils.java @@ -45,7 +45,7 @@ public final class StringUtils { } public static boolean isBlank(String str) { - return str == null || str.trim().isEmpty(); + return str == null || str.isBlank(); } public static boolean isNotBlank(String str) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/CompressingUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/CompressingUtils.java index 00f61ac71..b9ba5da3c 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/CompressingUtils.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/CompressingUtils.java @@ -24,14 +24,12 @@ import org.jackhuang.hmcl.util.platform.OperatingSystem; import java.io.File; import java.io.IOException; -import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.*; import java.nio.file.*; import java.nio.file.spi.FileSystemProvider; import java.util.*; -import java.util.zip.ZipError; import java.util.zip.ZipException; /** @@ -59,7 +57,7 @@ public final class CompressingUtils { } } - public static boolean testEncoding(ZipArchiveReader zipFile, Charset encoding) throws IOException { + public static boolean testEncoding(ZipArchiveReader zipFile, Charset encoding) { CharsetDecoder cd = newCharsetDecoder(encoding); CharBuffer cb = CharBuffer.allocate(32); @@ -71,7 +69,7 @@ public final class CompressingUtils { int clen = (int)(ba.length * cd.maxCharsPerByte()); if (clen == 0) continue; if (clen <= cb.capacity()) - ((Buffer) cb).clear(); // cast to prevent "java.lang.NoSuchMethodError: java.nio.CharBuffer.clear()Ljava/nio/CharBuffer;" when compiling with Java 9+ + cb.clear(); else cb = CharBuffer.allocate(clen); @@ -212,9 +210,6 @@ public final class CompressingUtils { throw new FileSystemNotFoundException("Module jdk.zipfs does not exist"); return ZIPFS_PROVIDER.newFileSystem(zipFile, env); - } catch (ZipError error) { - // Since Java 8 throws ZipError stupidly - throw new ZipException(error.getMessage()); } catch (UnsupportedOperationException ex) { throw new ZipException("Not a zip file"); } catch (FileSystemNotFoundException ex) { 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 4306b99ab..371361e95 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 @@ -25,7 +25,6 @@ import org.jackhuang.hmcl.util.function.ExceptionalConsumer; import org.jackhuang.hmcl.util.platform.OperatingSystem; import java.io.*; -import java.lang.reflect.Method; import java.nio.charset.Charset; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; @@ -328,18 +327,9 @@ public final class FileUtils { /** * Move file to trash. - *

- * This method is only implemented in Java 9. Please check we are using Java 9 by invoking isMovingToTrashSupported. - * Example: - *

{@code
-     * if (FileUtils.isMovingToTrashSupported()) {
-     *     FileUtils.moveToTrash(file);
-     * }
-     * }
* * @param file the file being moved to trash. * @return false if moveToTrash does not exist, or platform does not support Desktop.Action.MOVE_TO_TRASH - * @see FileUtils#isMovingToTrashSupported() */ public static boolean moveToTrash(File file) { if (OperatingSystem.CURRENT_OS.isLinuxOrBSD() && hasKnownDesktop()) { @@ -393,33 +383,12 @@ public final class FileUtils { } try { - java.awt.Desktop desktop = java.awt.Desktop.getDesktop(); - Method moveToTrash = desktop.getClass().getMethod("moveToTrash", File.class); - moveToTrash.invoke(desktop, file); - return true; + return java.awt.Desktop.getDesktop().moveToTrash(file); } catch (Exception e) { return false; } } - /** - * Check if {@code java.awt.Desktop.moveToTrash} exists. - * - * @return true if the method exists. - */ - public static boolean isMovingToTrashSupported() { - if (OperatingSystem.CURRENT_OS.isLinuxOrBSD() && hasKnownDesktop()) { - return true; - } - - try { - java.awt.Desktop.class.getMethod("moveToTrash", File.class); - return true; - } catch (ReflectiveOperationException e) { - return false; - } - } - public static void cleanDirectory(File directory) throws IOException { if (!directory.exists()) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/IOUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/IOUtils.java index 7194e7688..723c33128 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/IOUtils.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/IOUtils.java @@ -78,7 +78,7 @@ public final class IOUtils { public static String readFullyAsStringWithClosing(InputStream stream) throws IOException { ByteArrayOutputStream result = new ByteArrayOutputStream(Math.max(stream.available(), 32)); copyTo(stream, result); - return result.toString("UTF-8"); + return result.toString(UTF_8); } /** @@ -101,11 +101,11 @@ public final class IOUtils { } public static String readFullyAsString(InputStream stream) throws IOException { - return readFully(stream).toString("UTF-8"); + return readFully(stream).toString(UTF_8); } public static String readFullyAsString(InputStream stream, Charset charset) throws IOException { - return readFully(stream).toString(charset.name()); + return readFully(stream).toString(charset); } public static void copyTo(InputStream src, OutputStream dest) throws IOException { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/logging/Logger.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/logging/Logger.java index 1a839410c..3fbf1fbe6 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/logging/Logger.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/logging/Logger.java @@ -294,7 +294,7 @@ public final class Logger { ByteArrayOutputStream output = new ByteArrayOutputStream(); try { exportLogs(output); - return output.toString("UTF-8"); + return output.toString(UTF_8); } catch (IOException e) { log(Level.WARNING, CLASS_NAME + ".getLogs", "Failed to export logs", e); return ""; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/ManagedProcess.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/ManagedProcess.java index e30a9c4bd..4a746ddf6 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/ManagedProcess.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/ManagedProcess.java @@ -17,14 +17,10 @@ */ package org.jackhuang.hmcl.util.platform; -import org.jackhuang.hmcl.java.JavaRuntime; import org.jackhuang.hmcl.launch.StreamPump; import org.jackhuang.hmcl.util.Lang; import java.io.IOException; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.reflect.Field; import java.util.*; import java.util.function.Consumer; import java.util.function.Predicate; @@ -84,47 +80,6 @@ public final class ManagedProcess { return process; } - /** - * The PID of the raw system process - * - * @throws UnsupportedOperationException if current Java environment is not supported. - * @return PID - */ - public long getPID() throws UnsupportedOperationException { - if (JavaRuntime.CURRENT_VERSION >= 9) { - // Method Process.pid() is provided (Java 9 or later). Invoke it to get the pid. - try { - return (long) MethodHandles.publicLookup() - .findVirtual(Process.class, "pid", MethodType.methodType(long.class)) - .invokeExact(process); - } catch (Throwable e) { - throw new UnsupportedOperationException("Cannot get the pid", e); - } - } else { - // Method Process.pid() is not provided. (Java 8). - if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { - // On Windows, we can invoke method Process.pid() to get the pid. - // However, this method is supplied since Java 9. - // So, there is no ways to get the pid. - throw new UnsupportedOperationException("Cannot get the pid of a Process on Java 8 on Windows."); - } else if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS || OperatingSystem.CURRENT_OS.isLinuxOrBSD()) { - // On Linux or Mac, we can get field UnixProcess.pid field to get the pid. - // All the Java version is accepted. - // See https://github.com/openjdk/jdk/blob/jdk8-b120/jdk/src/solaris/classes/java/lang/UNIXProcess.java.linux - try { - Field pidField = process.getClass().getDeclaredField("pid"); - pidField.setAccessible(true); - return pidField.getInt(process); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new UnsupportedOperationException("Cannot get the pid of a Process on Java 8 on macOS/Linux.", e); - } - } else { - // Unknown Operating System, no fallback available. - throw new UnsupportedOperationException(String.format("Cannot get the pid of a Process on Java 8 on Unknown Operating System (%s).", System.getProperty("os.name"))); - } - } - } - /** * The command line. * diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/SystemUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/SystemUtils.java index 66f586b1e..87916d3b6 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/SystemUtils.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/SystemUtils.java @@ -17,7 +17,6 @@ */ package org.jackhuang.hmcl.util.platform; -import org.jackhuang.hmcl.java.JavaRuntime; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.function.ExceptionalFunction; @@ -110,7 +109,7 @@ public final class SystemUtils { } public static boolean supportJVMAttachment() { - return JavaRuntime.CURRENT_VERSION >= 9 && Thread.currentThread().getContextClassLoader().getResource("com/sun/tools/attach/VirtualMachine.class") != null; + return Thread.currentThread().getContextClassLoader().getResource("com/sun/tools/attach/VirtualMachine.class") != null; } private static void onLogLine(String log) { diff --git a/HMCLCore/src/test/java/org/jackhuang/hmcl/JavaFXLauncher.java b/HMCLCore/src/test/java/org/jackhuang/hmcl/JavaFXLauncher.java index a4cbcb924..c59de8f7c 100644 --- a/HMCLCore/src/test/java/org/jackhuang/hmcl/JavaFXLauncher.java +++ b/HMCLCore/src/test/java/org/jackhuang/hmcl/JavaFXLauncher.java @@ -17,10 +17,6 @@ */ package org.jackhuang.hmcl; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - public final class JavaFXLauncher { private JavaFXLauncher() { @@ -31,21 +27,9 @@ public final class JavaFXLauncher { static { // init JavaFX Toolkit try { - // Java 9 or Latter - final MethodHandle startup = - MethodHandles.publicLookup().findStatic( - javafx.application.Platform.class, "startup", MethodType.methodType(void.class, Runnable.class)); - startup.invokeExact((Runnable) () -> { + javafx.application.Platform.startup(() -> { }); started = true; - } catch (NoSuchMethodException e) { - // Java 8 - try { - Class.forName("javafx.embed.swing.JFXPanel").getDeclaredConstructor().newInstance(); - started = true; - } catch (Throwable e0) { - e0.printStackTrace(); - } } catch (IllegalStateException e) { started = true; } catch (Throwable e) {