Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27361c65fe | ||
|
|
ffa7afcbab | ||
|
|
9aa1367823 | ||
|
|
acc96b95c8 | ||
|
|
46502875c5 | ||
|
|
43b769923b | ||
|
|
fe3fc0413c | ||
|
|
fd13088726 | ||
|
|
195db2ee6d | ||
|
|
96f68e1017 | ||
|
|
24d3bbf4fe | ||
|
|
d60a923841 |
No files matched your search
@@ -1,11 +1,13 @@
|
||||
name: Check Translations
|
||||
name: Check Codes
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '**.java'
|
||||
- '**.properties'
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.java'
|
||||
- '**.properties'
|
||||
|
||||
jobs:
|
||||
@@ -19,5 +21,5 @@ jobs:
|
||||
distribution: 'zulu'
|
||||
java-version: '11'
|
||||
java-package: 'jdk+fx'
|
||||
- name: Check style test
|
||||
run: ./gradlew checkTranslations --no-daemon
|
||||
- name: Check Codes
|
||||
run: ./gradlew checkstyleMain checkstyleTest checkTranslations --no-daemon --parallel
|
||||
@@ -1,25 +0,0 @@
|
||||
name: Check Style
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '**.java'
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.java'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: '11'
|
||||
java-package: 'jdk+fx'
|
||||
- name: Check style main
|
||||
run: ./gradlew checkstyleMain --no-daemon
|
||||
- name: Check style test
|
||||
run: ./gradlew checkstyleTest --no-daemon
|
||||
@@ -18,6 +18,7 @@ minecraft-exported-crash-info*
|
||||
/build/
|
||||
/HMCL/build/
|
||||
/HMCLCore/build/
|
||||
/HMCLBoot/build/
|
||||
/HMCLTransformerDiscoveryService/build/
|
||||
/minecraft/libraries/HMCLTransformerDiscoveryService/build/
|
||||
/buildSrc/build/
|
||||
|
||||
+7
-15
@@ -39,6 +39,7 @@ version = "$versionRoot.$buildNumber"
|
||||
|
||||
dependencies {
|
||||
implementation(project(":HMCLCore"))
|
||||
implementation(project(":HMCLBoot"))
|
||||
implementation("libs:JFoenix")
|
||||
implementation(libs.twelvemonkeys.imageio.webp)
|
||||
implementation(libs.java.info)
|
||||
@@ -89,18 +90,15 @@ fun attachSignature(jar: File) {
|
||||
}
|
||||
}
|
||||
|
||||
val java11 = sourceSets.create("java11") {
|
||||
java {
|
||||
srcDir("src/main/java11")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.getByName<JavaCompile>(java11.compileJavaTaskName) {
|
||||
options.compilerArgs.add("--add-exports=java.base/jdk.internal.loader=ALL-UNNAMED")
|
||||
tasks.withType<JavaCompile> {
|
||||
sourceCompatibility = "11"
|
||||
targetCompatibility = "11"
|
||||
}
|
||||
|
||||
tasks.compileJava {
|
||||
options.compilerArgs.add("--add-exports=java.base/jdk.internal.loader=ALL-UNNAMED")
|
||||
}
|
||||
|
||||
tasks.jar {
|
||||
enabled = false
|
||||
dependsOn(tasks["shadowJar"])
|
||||
@@ -126,6 +124,7 @@ tasks.shadowJar {
|
||||
exclude(dependency("com.google.code.gson:.*:.*"))
|
||||
exclude(dependency("net.java.dev.jna:jna:.*"))
|
||||
exclude(dependency("libs:JFoenix:.*"))
|
||||
exclude(project(":HMCLBoot"))
|
||||
}
|
||||
|
||||
manifest {
|
||||
@@ -174,13 +173,6 @@ tasks.shadowJar {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
into("META-INF/versions/11") {
|
||||
from(sourceSets["java11"].output)
|
||||
}
|
||||
dependsOn(tasks["java11Classes"])
|
||||
}
|
||||
|
||||
val makeExecutables by tasks.registering {
|
||||
val extensions = listOf("exe", "sh")
|
||||
|
||||
|
||||
+34
-101
@@ -17,41 +17,26 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.Alert;
|
||||
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.ui.SwingUtils;
|
||||
import org.jackhuang.hmcl.util.SwingUtils;
|
||||
import org.jackhuang.hmcl.java.JavaRuntime;
|
||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
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.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.CancellationException;
|
||||
|
||||
import static org.jackhuang.hmcl.util.Lang.thread;
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
public final class Main {
|
||||
public final class EntryPoint {
|
||||
|
||||
private Main() {
|
||||
private EntryPoint() {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
@@ -64,10 +49,6 @@ public final class Main {
|
||||
|
||||
checkDirectoryPath();
|
||||
|
||||
if (JavaRuntime.CURRENT_VERSION < 9)
|
||||
// This environment check will take ~300ms
|
||||
thread(Main::fixLetsEncrypt, "CA Certificate Check", true);
|
||||
|
||||
if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS)
|
||||
initIcon();
|
||||
|
||||
@@ -97,6 +78,8 @@ public final class Main {
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Logger has not been started yet, so print directly to System.err
|
||||
System.err.println("Failed to create HMCL directory: " + Metadata.HMCL_CURRENT_DIRECTORY);
|
||||
e.printStackTrace(System.err);
|
||||
showErrorAndExit(i18n("fatal.create_hmcl_current_directory_failure", Metadata.HMCL_CURRENT_DIRECTORY));
|
||||
}
|
||||
@@ -112,16 +95,17 @@ public final class Main {
|
||||
}
|
||||
|
||||
private static void initIcon() {
|
||||
java.awt.Image image = java.awt.Toolkit.getDefaultToolkit().getImage(Main.class.getResource("/assets/img/icon-mac.png"));
|
||||
java.awt.Image image = java.awt.Toolkit.getDefaultToolkit().getImage(EntryPoint.class.getResource("/assets/img/icon-mac.png"));
|
||||
AwtUtils.setAppleIcon(image);
|
||||
}
|
||||
|
||||
private static void checkDirectoryPath() {
|
||||
String currentDirectory = new File("").getAbsolutePath();
|
||||
if (currentDirectory.contains("!")) {
|
||||
String currentDir = System.getProperty("user.dir", "");
|
||||
if (currentDir.contains("!")) {
|
||||
LOG.error("The current working path contains an exclamation mark: " + currentDir);
|
||||
// No Chinese translation because both Swing and JavaFX cannot render Chinese character properly when exclamation mark exists in the path.
|
||||
showErrorAndExit("Exclamation mark(!) is not allowed in the path where HMCL is in.\n"
|
||||
+ "The path is " + currentDirectory);
|
||||
+ "The path is " + currentDir);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,10 +113,10 @@ public final class Main {
|
||||
try {
|
||||
SelfDependencyPatcher.patch();
|
||||
} catch (SelfDependencyPatcher.PatchException e) {
|
||||
LOG.error("unable to patch JVM", e);
|
||||
LOG.error("Unable to patch JVM", e);
|
||||
showErrorAndExit(i18n("fatal.javafx.missing"));
|
||||
} catch (SelfDependencyPatcher.IncompatibleVersionException e) {
|
||||
LOG.error("unable to patch JVM", e);
|
||||
LOG.error("Unable to patch JVM", e);
|
||||
showErrorAndExit(i18n("fatal.javafx.incompatible"));
|
||||
} catch (CancellationException e) {
|
||||
LOG.error("User cancels downloading JavaFX", e);
|
||||
@@ -149,7 +133,7 @@ public final class Main {
|
||||
Class.forName("javafx.stage.Stage"); // javafx.graphics
|
||||
Class.forName("javafx.scene.control.Skin"); // javafx.controls
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
LOG.warning("JavaFX is incomplete or not found", e);
|
||||
showErrorAndExit(i18n("fatal.javafx.incomplete"));
|
||||
}
|
||||
}
|
||||
@@ -157,9 +141,20 @@ public final class Main {
|
||||
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) {
|
||||
e.printStackTrace(System.err);
|
||||
LOG.error("Failed to add enable native access for JavaFX", e);
|
||||
showErrorAndExit(i18n("fatal.javafx.incomplete"));
|
||||
}
|
||||
}
|
||||
@@ -170,11 +165,11 @@ public final class Main {
|
||||
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) {
|
||||
e.printStackTrace(System.err);
|
||||
LOG.warning("Failed to enable unsafe memory access", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,70 +177,8 @@ public final class Main {
|
||||
/**
|
||||
* Indicates that a fatal error has occurred, and that the application cannot start.
|
||||
*/
|
||||
static void showErrorAndExit(String message) {
|
||||
System.err.println(message);
|
||||
System.err.println("A fatal error has occurred, forcibly exiting.");
|
||||
|
||||
try {
|
||||
if (Platform.isFxApplicationThread()) {
|
||||
new Alert(Alert.AlertType.ERROR, message).showAndWait();
|
||||
exit(1);
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
private static void showErrorAndExit(String message) {
|
||||
SwingUtils.showErrorDialog(message);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that potential issues have been detected, and that the application may not function properly (but it can still run).
|
||||
*/
|
||||
static void showWarningAndContinue(String message) {
|
||||
System.err.println(message);
|
||||
System.err.println("Potential issues have been detected.");
|
||||
|
||||
try {
|
||||
if (Platform.isFxApplicationThread()) {
|
||||
new Alert(Alert.AlertType.WARNING, message).showAndWait();
|
||||
return;
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
SwingUtils.showWarningDialog(message);
|
||||
}
|
||||
|
||||
private static void fixLetsEncrypt() {
|
||||
try {
|
||||
KeyStore defaultKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
Path ksPath = Paths.get(System.getProperty("java.home"), "lib", "security", "cacerts");
|
||||
|
||||
try (InputStream ksStream = Files.newInputStream(ksPath)) {
|
||||
defaultKeyStore.load(ksStream, "changeit".toCharArray());
|
||||
}
|
||||
|
||||
KeyStore letsEncryptKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
try (InputStream letsEncryptFile = Main.class.getResourceAsStream("/assets/lekeystore.jks")) {
|
||||
letsEncryptKeyStore.load(letsEncryptFile, "supersecretpassword".toCharArray());
|
||||
}
|
||||
|
||||
KeyStore merged = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
merged.load(null, new char[0]);
|
||||
for (String alias : Collections.list(letsEncryptKeyStore.aliases()))
|
||||
merged.setCertificateEntry(alias, letsEncryptKeyStore.getCertificate(alias));
|
||||
for (String alias : Collections.list(defaultKeyStore.aliases()))
|
||||
merged.setCertificateEntry(alias, defaultKeyStore.getCertificate(alias));
|
||||
|
||||
TrustManagerFactory instance = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
instance.init(merged);
|
||||
SSLContext tls = SSLContext.getInstance("TLS");
|
||||
tls.init(null, instance.getTrustManagers(), null);
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(tls.getSocketFactory());
|
||||
LOG.info("Added Lets Encrypt root certificates as additional trust");
|
||||
} catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException |
|
||||
KeyManagementException e) {
|
||||
LOG.error("Failed to load lets encrypt certificate. Expect problems", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,13 +81,14 @@ public final class Launcher extends Application {
|
||||
try {
|
||||
try {
|
||||
ConfigHolder.init();
|
||||
} catch (SambaException ignored) {
|
||||
Main.showWarningAndContinue(i18n("fatal.samba"));
|
||||
} catch (SambaException e) {
|
||||
showAlert(AlertType.WARNING, i18n("fatal.samba"));
|
||||
} catch (IOException e) {
|
||||
LOG.error("Failed to load config", e);
|
||||
checkConfigInTempDir();
|
||||
checkConfigOwner();
|
||||
Main.showErrorAndExit(i18n("fatal.config_loading_failure", ConfigHolder.configLocation().getParent()));
|
||||
showAlert(AlertType.ERROR, i18n("fatal.config_loading_failure", ConfigHolder.configLocation().getParent()));
|
||||
EntryPoint.exit(1);
|
||||
}
|
||||
|
||||
// https://lapcatsoftware.com/articles/app-translocation.html
|
||||
@@ -106,7 +107,7 @@ public final class Launcher extends Application {
|
||||
}
|
||||
|
||||
if (Metadata.HMCL_CURRENT_DIRECTORY.toString().indexOf('=') >= 0) {
|
||||
Main.showWarningAndContinue(i18n("fatal.illegal_char"));
|
||||
showAlert(AlertType.WARNING, i18n("fatal.illegal_char"));
|
||||
}
|
||||
|
||||
// runLater to ensure ConfigHolder.init() finished initialization
|
||||
@@ -169,7 +170,7 @@ public final class Launcher extends Application {
|
||||
private static void checkConfigInTempDir() {
|
||||
if (ConfigHolder.isNewlyCreated() && isConfigInTempDir()
|
||||
&& showAlert(AlertType.WARNING, i18n("fatal.config_in_temp_dir"), ButtonType.YES, ButtonType.NO) == ButtonType.NO) {
|
||||
Main.exit(0);
|
||||
EntryPoint.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +210,7 @@ public final class Launcher extends Application {
|
||||
Clipboard.getSystemClipboard()
|
||||
.setContent(Collections.singletonMap(DataFormat.PLAIN_TEXT, command));
|
||||
}
|
||||
Main.exit(1);
|
||||
EntryPoint.exit(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,13 +19,10 @@ package org.jackhuang.hmcl;
|
||||
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.io.JarUtils;
|
||||
import org.jackhuang.hmcl.util.platform.Architecture;
|
||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* Stores metadata about this application.
|
||||
@@ -38,9 +35,6 @@ public final class Metadata {
|
||||
public static final String FULL_NAME = "Hello Minecraft! Launcher";
|
||||
public static final String VERSION = System.getProperty("hmcl.version.override", JarUtils.getManifestAttribute("Implementation-Version", "@develop@"));
|
||||
|
||||
public static final int MINIMUM_REQUIRED_JAVA_VERSION = 8;
|
||||
public static final int MINIMUM_SUPPORTED_JAVA_VERSION = 11;
|
||||
|
||||
public static final String TITLE = NAME + " " + VERSION;
|
||||
public static final String FULL_TITLE = FULL_NAME + " v" + VERSION;
|
||||
|
||||
@@ -100,31 +94,4 @@ public final class Metadata {
|
||||
return !isStable() && !isDev();
|
||||
}
|
||||
|
||||
public static @Nullable String getSuggestedJavaDownloadLink() {
|
||||
if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX && Architecture.SYSTEM_ARCH == Architecture.LOONGARCH64_OW)
|
||||
return "https://www.loongnix.cn/zh/api/java/downloads-jdk21/index.html";
|
||||
else {
|
||||
EnumSet<Architecture> supportedArchitectures;
|
||||
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS)
|
||||
supportedArchitectures = EnumSet.of(Architecture.X86_64, Architecture.X86, Architecture.ARM64);
|
||||
else if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX)
|
||||
supportedArchitectures = EnumSet.of(
|
||||
Architecture.X86_64, Architecture.X86,
|
||||
Architecture.ARM64, Architecture.ARM32,
|
||||
Architecture.RISCV64, Architecture.LOONGARCH64
|
||||
);
|
||||
else if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS)
|
||||
supportedArchitectures = EnumSet.of(Architecture.X86_64, Architecture.ARM64);
|
||||
else
|
||||
supportedArchitectures = EnumSet.noneOf(Architecture.class);
|
||||
|
||||
if (supportedArchitectures.contains(Architecture.SYSTEM_ARCH))
|
||||
return String.format("https://docs.hmcl.net/downloads/%s/%s.html",
|
||||
OperatingSystem.CURRENT_OS.getCheckedName(),
|
||||
Architecture.SYSTEM_ARCH.getCheckedName()
|
||||
);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,7 +170,7 @@ public class HMCLGameRepository extends DefaultGameRepository {
|
||||
}
|
||||
Files.copy(fromJson, toJson);
|
||||
|
||||
FileUtils.writeText(toJson.toFile(), JsonUtils.GSON.toJson(fromVersion.setId(dstId)));
|
||||
FileUtils.writeText(toJson, JsonUtils.GSON.toJson(fromVersion.setId(dstId)));
|
||||
|
||||
VersionSetting oldVersionSetting = getVersionSetting(srcId).clone();
|
||||
GameDirectoryType originalGameDirType = oldVersionSetting.getGameDirType();
|
||||
@@ -194,7 +194,7 @@ public class HMCLGameRepository extends DefaultGameRepository {
|
||||
File file = getLocalVersionSettingFile(id);
|
||||
if (file.exists())
|
||||
try {
|
||||
VersionSetting versionSetting = GSON.fromJson(FileUtils.readText(file), VersionSetting.class);
|
||||
VersionSetting versionSetting = GSON.fromJson(Files.readString(file.toPath()), VersionSetting.class);
|
||||
initLocalVersionSetting(id, versionSetting);
|
||||
} catch (Exception ex) {
|
||||
// If [JsonParseException], [IOException] or [NullPointerException] happens, the json file is malformed and needed to be recreated.
|
||||
@@ -427,7 +427,7 @@ public class HMCLGameRepository extends DefaultGameRepository {
|
||||
File json = getModpackConfiguration(version);
|
||||
if (json.exists()) {
|
||||
try {
|
||||
String jsonText = FileUtils.readText(json);
|
||||
String jsonText = Files.readString(json.toPath());
|
||||
ModpackConfiguration<?> modpackConfiguration = JsonUtils.GSON.fromJson(jsonText, ModpackConfiguration.class);
|
||||
ModpackProvider provider = ModpackHelper.getProviderByType(modpackConfiguration.getType());
|
||||
if (provider != null) provider.injectLaunchOptions(jsonText, builder);
|
||||
|
||||
@@ -28,10 +28,10 @@ import org.jackhuang.hmcl.setting.Profile;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -66,7 +66,7 @@ public final class HMCLModpackInstallTask extends Task<Void> {
|
||||
ModpackConfiguration<Modpack> config = null;
|
||||
try {
|
||||
if (json.exists()) {
|
||||
config = JsonUtils.GSON.fromJson(FileUtils.readText(json), ModpackConfiguration.typeOf(Modpack.class));
|
||||
config = JsonUtils.GSON.fromJson(Files.readString(json.toPath()), 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.");
|
||||
|
||||
@@ -59,6 +59,7 @@ import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import static javafx.application.Platform.runLater;
|
||||
import static javafx.application.Platform.setImplicitExit;
|
||||
@@ -125,6 +126,9 @@ public final class LauncherHelper {
|
||||
}
|
||||
|
||||
private void launch0() {
|
||||
// https://github.com/HMCL-dev/HMCL/pull/4121
|
||||
PROCESSES.removeIf(it -> it.get() == null);
|
||||
|
||||
HMCLGameRepository repository = profile.getRepository();
|
||||
DefaultDependencyManager dependencyManager = profile.getDependency();
|
||||
AtomicReference<Version> version = new AtomicReference<>(MaintainTask.maintain(repository, repository.getResolvedVersion(selectedVersion)));
|
||||
@@ -209,7 +213,7 @@ public final class LauncherHelper {
|
||||
}
|
||||
}).thenAcceptAsync(process -> { // process is LaunchTask's result
|
||||
if (scriptFile == null) {
|
||||
PROCESSES.add(process);
|
||||
PROCESSES.add(new WeakReference<>(process));
|
||||
if (launcherVisibility == LauncherVisibility.CLOSE)
|
||||
Launcher.stopApplication();
|
||||
else
|
||||
@@ -896,10 +900,10 @@ public final class LauncherHelper {
|
||||
|
||||
}
|
||||
|
||||
public static final Queue<ManagedProcess> PROCESSES = new ConcurrentLinkedQueue<>();
|
||||
public static final Queue<WeakReference<ManagedProcess>> PROCESSES = new ConcurrentLinkedQueue<>();
|
||||
|
||||
public static void stopManagedProcesses() {
|
||||
while (!PROCESSES.isEmpty())
|
||||
Optional.ofNullable(PROCESSES.poll()).ifPresent(ManagedProcess::stop);
|
||||
Optional.ofNullable(PROCESSES.poll()).map(WeakReference::get).ifPresent(ManagedProcess::stop);
|
||||
}
|
||||
}
|
||||
@@ -140,7 +140,7 @@ public final class ModpackHelper {
|
||||
throw new FileNotFoundException(file.getPath());
|
||||
else
|
||||
try {
|
||||
return JsonUtils.GSON.fromJson(FileUtils.readText(file), ModpackConfiguration.class);
|
||||
return JsonUtils.GSON.fromJson(Files.readString(file.toPath()), ModpackConfiguration.class);
|
||||
} catch (JsonParseException e) {
|
||||
throw new IOException("Malformed modpack configuration");
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.gson.TolerableValidationException;
|
||||
import org.jackhuang.hmcl.util.gson.Validation;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.io.JarUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -73,7 +72,7 @@ public final class AuthlibInjectorServers implements Validation {
|
||||
if (ConfigHolder.isNewlyCreated() && Files.exists(configLocation)) {
|
||||
AuthlibInjectorServers configInstance;
|
||||
try {
|
||||
String content = FileUtils.readText(configLocation);
|
||||
String content = Files.readString(configLocation);
|
||||
configInstance = JsonUtils.GSON.fromJson(content, AuthlibInjectorServers.class);
|
||||
} catch (IOException | JsonParseException e) {
|
||||
LOG.warning("Malformed authlib-injectors.json", e);
|
||||
|
||||
@@ -101,6 +101,7 @@ public final class ConfigHolder {
|
||||
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS
|
||||
&& configLocation.getFileSystem() == FileSystems.getDefault()
|
||||
&& configLocation.toFile().canWrite()) {
|
||||
LOG.warning("Config at " + configLocation + " is not writable, but it seems to be a Samba share or OpenJDK bug");
|
||||
// There are some serious problems with the implementation of Samba or OpenJDK
|
||||
throw new SambaException();
|
||||
} else {
|
||||
@@ -157,7 +158,7 @@ public final class ConfigHolder {
|
||||
LOG.warning("Failed to get owner");
|
||||
}
|
||||
try {
|
||||
String content = FileUtils.readText(configLocation);
|
||||
String content = Files.readString(configLocation);
|
||||
Config deserialized = Config.fromJson(content);
|
||||
if (deserialized == null) {
|
||||
LOG.info("Config is empty");
|
||||
@@ -179,7 +180,7 @@ public final class ConfigHolder {
|
||||
private static GlobalConfig loadGlobalConfig() throws IOException {
|
||||
if (Files.exists(GLOBAL_CONFIG_PATH)) {
|
||||
try {
|
||||
String content = FileUtils.readText(GLOBAL_CONFIG_PATH);
|
||||
String content = Files.readString(GLOBAL_CONFIG_PATH);
|
||||
GlobalConfig deserialized = GlobalConfig.fromJson(content);
|
||||
if (deserialized == null) {
|
||||
LOG.info("Config is empty");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -21,10 +21,7 @@ import com.google.gson.*;
|
||||
import com.google.gson.annotations.JsonAdapter;
|
||||
import javafx.beans.InvalidationListener;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableSet;
|
||||
import org.jackhuang.hmcl.util.javafx.ObservableHelper;
|
||||
@@ -57,6 +54,8 @@ public final class GlobalConfig implements Observable {
|
||||
|
||||
private final BooleanProperty enableOfflineAccount = new SimpleBooleanProperty(false);
|
||||
|
||||
private final StringProperty fontAntiAliasing = new SimpleStringProperty();
|
||||
|
||||
private final ObservableSet<String> userJava = FXCollections.observableSet(new LinkedHashSet<>());
|
||||
|
||||
private final ObservableSet<String> disabledJava = FXCollections.observableSet(new LinkedHashSet<>());
|
||||
@@ -131,6 +130,18 @@ public final class GlobalConfig implements Observable {
|
||||
enableOfflineAccount.set(value);
|
||||
}
|
||||
|
||||
public StringProperty fontAntiAliasingProperty() {
|
||||
return fontAntiAliasing;
|
||||
}
|
||||
|
||||
public String getFontAntiAliasing() {
|
||||
return fontAntiAliasing.get();
|
||||
}
|
||||
|
||||
public void setFontAntiAliasing(String value) {
|
||||
this.fontAntiAliasing.set(value);
|
||||
}
|
||||
|
||||
public ObservableSet<String> getUserJava() {
|
||||
return userJava;
|
||||
}
|
||||
@@ -146,7 +157,8 @@ public final class GlobalConfig implements Observable {
|
||||
"logRetention",
|
||||
"userJava",
|
||||
"disabledJava",
|
||||
"enableOfflineAccount"
|
||||
"enableOfflineAccount",
|
||||
"fontAntiAliasing"
|
||||
));
|
||||
|
||||
@Override
|
||||
@@ -159,6 +171,7 @@ public final class GlobalConfig implements Observable {
|
||||
jsonObject.add("agreementVersion", context.serialize(src.getAgreementVersion()));
|
||||
jsonObject.add("platformPromptVersion", context.serialize(src.getPlatformPromptVersion()));
|
||||
jsonObject.add("logRetention", context.serialize(src.getLogRetention()));
|
||||
jsonObject.add("fontAntiAliasing", context.serialize(src.getFontAntiAliasing()));
|
||||
if (src.enableOfflineAccount.get())
|
||||
jsonObject.addProperty("enableOfflineAccount", true);
|
||||
|
||||
@@ -186,6 +199,7 @@ public final class GlobalConfig implements Observable {
|
||||
config.setPlatformPromptVersion(Optional.ofNullable(obj.get("platformPromptVersion")).map(JsonElement::getAsInt).orElse(0));
|
||||
config.setLogRetention(Optional.ofNullable(obj.get("logRetention")).map(JsonElement::getAsInt).orElse(20));
|
||||
config.setEnableOfflineAccount(Optional.ofNullable(obj.get("enableOfflineAccount")).map(JsonElement::getAsBoolean).orElse(false));
|
||||
config.setFontAntiAliasing(Optional.ofNullable(obj.get("fontAntiAliasing")).map(JsonElement::getAsString).orElse(null));
|
||||
|
||||
JsonElement userJava = obj.get("userJava");
|
||||
if (userJava != null && userJava.isJsonArray()) {
|
||||
|
||||
@@ -23,7 +23,6 @@ import javafx.collections.ObservableList;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.paint.Color;
|
||||
import org.jackhuang.hmcl.ui.FXUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
@@ -68,7 +67,7 @@ public final class StyleSheets {
|
||||
Path temp = Files.createTempFile("hmcl", ".css");
|
||||
// For JavaFX 17 or earlier, CssParser uses the default charset
|
||||
// https://bugs.openjdk.org/browse/JDK-8279328
|
||||
FileUtils.writeText(temp, styleSheet, Charset.defaultCharset());
|
||||
Files.writeString(temp, styleSheet, Charset.defaultCharset());
|
||||
temp.toFile().deleteOnExit();
|
||||
return temp.toUri().toString();
|
||||
} catch (IOException | NullPointerException e) {
|
||||
|
||||
@@ -42,7 +42,6 @@ import org.jackhuang.hmcl.Launcher;
|
||||
import org.jackhuang.hmcl.Metadata;
|
||||
import org.jackhuang.hmcl.game.ModpackHelper;
|
||||
import org.jackhuang.hmcl.java.JavaManager;
|
||||
import org.jackhuang.hmcl.java.JavaRuntime;
|
||||
import org.jackhuang.hmcl.setting.*;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.task.TaskExecutor;
|
||||
@@ -176,6 +175,18 @@ public final class Controllers {
|
||||
public static void initialize(Stage stage) {
|
||||
LOG.info("Start initializing application");
|
||||
|
||||
if (System.getProperty("prism.lcdtext") == null) {
|
||||
String fontAntiAliasing = globalConfig().getFontAntiAliasing();
|
||||
if ("lcd".equalsIgnoreCase(fontAntiAliasing)) {
|
||||
LOG.info("Enable sub-pixel antialiasing");
|
||||
System.getProperties().put("prism.lcdtext", "true");
|
||||
} else if ("gray".equalsIgnoreCase(fontAntiAliasing)
|
||||
|| OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS && SCREEN.getOutputScaleX() > 1) {
|
||||
LOG.info("Disable sub-pixel antialiasing");
|
||||
System.getProperties().put("prism.lcdtext", "false");
|
||||
}
|
||||
}
|
||||
|
||||
Controllers.stage = stage;
|
||||
|
||||
stageSizeChangeListener = o -> {
|
||||
@@ -310,26 +321,6 @@ public final class Controllers {
|
||||
}
|
||||
}
|
||||
|
||||
if (JavaRuntime.CURRENT_VERSION < 10) {
|
||||
Number shownTipVersion = null;
|
||||
|
||||
try {
|
||||
shownTipVersion = (Number) config().getShownTips().get(JAVA_VERSION_TIP);
|
||||
} catch (ClassCastException e) {
|
||||
LOG.warning("Invalid type for shown tips key: " + JAVA_VERSION_TIP, e);
|
||||
}
|
||||
|
||||
if (shownTipVersion == null || shownTipVersion.intValue() < Metadata.MINIMUM_SUPPORTED_JAVA_VERSION) {
|
||||
MessageDialogPane.Builder builder = new MessageDialogPane.Builder(i18n("fatal.deprecated_java_version"), null, MessageType.WARNING);
|
||||
String downloadLink = Metadata.getSuggestedJavaDownloadLink();
|
||||
if (downloadLink != null)
|
||||
builder.addHyperLink(i18n("fatal.deprecated_java_version.download_link", 21), downloadLink);
|
||||
Controllers.dialog(builder
|
||||
.ok(() -> config().getShownTips().put(JAVA_VERSION_TIP, Metadata.MINIMUM_SUPPORTED_JAVA_VERSION))
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
if (globalConfig().getAgreementVersion() < 1) {
|
||||
JFXDialogLayout agreementPane = new JFXDialogLayout();
|
||||
agreementPane.setHeading(new Label(i18n("launcher.agreement")));
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2024 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,13 @@
|
||||
package org.jackhuang.hmcl.ui.main;
|
||||
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import com.jfoenix.controls.JFXComboBox;
|
||||
import com.jfoenix.controls.JFXTextField;
|
||||
import com.jfoenix.effects.JFXDepthManager;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.When;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.ColorPicker;
|
||||
@@ -34,6 +36,7 @@ import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.scene.text.FontSmoothingType;
|
||||
import org.jackhuang.hmcl.setting.EnumBackgroundImage;
|
||||
import org.jackhuang.hmcl.setting.FontManager;
|
||||
import org.jackhuang.hmcl.setting.Theme;
|
||||
@@ -44,8 +47,11 @@ import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.javafx.SafeStringConverter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||
import static org.jackhuang.hmcl.setting.ConfigHolder.globalConfig;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
public class PersonalizationPage extends StackPane {
|
||||
@@ -216,6 +222,46 @@ public class PersonalizationPage extends StackPane {
|
||||
fontPane.getContent().add(vbox);
|
||||
}
|
||||
|
||||
{
|
||||
BorderPane fontAntiAliasingPane = new BorderPane();
|
||||
{
|
||||
Label left = new Label(i18n("settings.launcher.font.anti_aliasing"));
|
||||
BorderPane.setAlignment(left, Pos.CENTER_LEFT);
|
||||
fontAntiAliasingPane.setLeft(left);
|
||||
}
|
||||
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
JFXComboBox<Optional<FontSmoothingType>> cboAntiAliasing = new JFXComboBox<>(FXCollections.observableArrayList(
|
||||
Optional.empty(),
|
||||
Optional.of(FontSmoothingType.LCD),
|
||||
Optional.of(FontSmoothingType.GRAY)
|
||||
));
|
||||
String fontAntiAliasing = globalConfig().getFontAntiAliasing();
|
||||
if ("lcd".equalsIgnoreCase(fontAntiAliasing)) {
|
||||
cboAntiAliasing.setValue(Optional.of(FontSmoothingType.LCD));
|
||||
} else if ("gray".equalsIgnoreCase(fontAntiAliasing)) {
|
||||
cboAntiAliasing.setValue(Optional.of(FontSmoothingType.GRAY));
|
||||
} else {
|
||||
cboAntiAliasing.setValue(Optional.empty());
|
||||
}
|
||||
cboAntiAliasing.setConverter(FXUtils.stringConverter(value -> {
|
||||
if (value.isPresent()) {
|
||||
return i18n("settings.launcher.font.anti_aliasing." + value.get().name().toLowerCase(Locale.ROOT));
|
||||
} else {
|
||||
return i18n("settings.launcher.font.anti_aliasing.auto");
|
||||
}
|
||||
}));
|
||||
FXUtils.onChange(cboAntiAliasing.valueProperty(), value ->
|
||||
globalConfig().setFontAntiAliasing(value.map(it -> it.name().toLowerCase(Locale.ROOT))
|
||||
.orElse(null)));
|
||||
|
||||
fontAntiAliasingPane.setRight(cboAntiAliasing);
|
||||
}
|
||||
|
||||
fontPane.getContent().add(fontAntiAliasingPane);
|
||||
}
|
||||
|
||||
content.getChildren().addAll(ComponentList.createComponentListTitle(i18n("settings.launcher.font")), fontPane);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -64,7 +64,7 @@ final class ExecutableHeaderHelper {
|
||||
ZipEntry entry = zip.getEntry(location);
|
||||
if (entry != null && !entry.isDirectory()) {
|
||||
try (InputStream in = zip.getInputStream(entry)) {
|
||||
return Optional.of(IOUtils.readFullyAsByteArray(in));
|
||||
return Optional.of(IOUtils.readFully(in));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public final class IntegrityChecker {
|
||||
if (in == null) {
|
||||
throw new IOException("Public key not found");
|
||||
}
|
||||
return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(IOUtils.readFullyAsByteArray(in)));
|
||||
return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(IOUtils.readFully(in)));
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new IOException("Failed to load public key", e);
|
||||
}
|
||||
@@ -76,7 +76,7 @@ public final class IntegrityChecker {
|
||||
}
|
||||
|
||||
if (SIGNATURE_FILE.equals(filename)) {
|
||||
signature = IOUtils.readFullyAsByteArray(in);
|
||||
signature = IOUtils.readFully(in);
|
||||
} else {
|
||||
md.reset();
|
||||
fileFingerprints.put(filename, DigestUtils.digest(md, in));
|
||||
|
||||
@@ -21,18 +21,17 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.JsonParseException;
|
||||
import javafx.application.Platform;
|
||||
|
||||
import org.jackhuang.hmcl.EntryPoint;
|
||||
import org.jackhuang.hmcl.Main;
|
||||
import org.jackhuang.hmcl.Metadata;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.task.TaskExecutor;
|
||||
import org.jackhuang.hmcl.ui.Controllers;
|
||||
import org.jackhuang.hmcl.ui.UpgradeDialog;
|
||||
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
|
||||
import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.ui.SwingUtils;
|
||||
import org.jackhuang.hmcl.util.SwingUtils;
|
||||
import org.jackhuang.hmcl.util.TaskCancellationAction;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.io.JarUtils;
|
||||
import org.jackhuang.hmcl.java.JavaRuntime;
|
||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||
@@ -103,16 +102,6 @@ public final class UpdateHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
if (JavaRuntime.CURRENT_VERSION < Metadata.MINIMUM_SUPPORTED_JAVA_VERSION) {
|
||||
MessageDialogPane.Builder builder = new MessageDialogPane.Builder(i18n("fatal.deprecated_java_version.update"), i18n("message.error"), MessageType.ERROR);
|
||||
String downloadLink = Metadata.getSuggestedJavaDownloadLink();
|
||||
if (downloadLink != null)
|
||||
builder.addHyperLink(i18n("fatal.deprecated_java_version.download_link", 21), downloadLink);
|
||||
builder.ok(null);
|
||||
Controllers.dialog(builder.build());
|
||||
return;
|
||||
}
|
||||
|
||||
Controllers.dialog(new UpgradeDialog(version, () -> {
|
||||
Path downloaded;
|
||||
try {
|
||||
@@ -136,7 +125,7 @@ public final class UpdateHandler {
|
||||
}
|
||||
|
||||
requestUpdate(downloaded, getCurrentLocation());
|
||||
Main.exit(0);
|
||||
EntryPoint.exit(0);
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Failed to update to " + version, e);
|
||||
Platform.runLater(() -> Controllers.dialog(StringUtils.getStackTrace(e), i18n("update.failed"), MessageType.ERROR));
|
||||
@@ -275,7 +264,7 @@ public final class UpdateHandler {
|
||||
Path hmclVersionJson = Metadata.HMCL_GLOBAL_DIRECTORY.resolve("hmclver.json");
|
||||
if (Files.isRegularFile(hmclVersionJson)) {
|
||||
try {
|
||||
Map<?, ?> content = new Gson().fromJson(FileUtils.readText(hmclVersionJson), Map.class);
|
||||
Map<?, ?> content = new Gson().fromJson(Files.readString(hmclVersionJson), Map.class);
|
||||
Object ver = content.get("ver");
|
||||
if (ver instanceof String && ((String) ver).startsWith("3.")) {
|
||||
Files.delete(hmclVersionJson);
|
||||
|
||||
@@ -17,11 +17,16 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.util;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.module.Configuration;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
|
||||
/**
|
||||
* Utility for Adding JavaFX to module path.
|
||||
*
|
||||
@@ -31,7 +36,43 @@ public final class JavaFXPatcher {
|
||||
private JavaFXPatcher() {
|
||||
}
|
||||
|
||||
public static void patch(Set<String> modules, Path[] jarPaths, String[] addOpens) {
|
||||
LOG.info("No need to patch JavaFX with Java 8");
|
||||
/**
|
||||
* Add JavaFX to module path at runtime.
|
||||
*
|
||||
* @param modules All module names
|
||||
* @param jarPaths All jar paths
|
||||
* @throws ReflectiveOperationException When the call to add these jars to the system module path failed.
|
||||
*/
|
||||
public static void patch(Set<String> modules, Path[] jarPaths, String[] addOpens) throws ReflectiveOperationException {
|
||||
// Find all modules
|
||||
ModuleFinder finder = ModuleFinder.of(jarPaths);
|
||||
|
||||
// Load all modules as unnamed module
|
||||
for (ModuleReference mref : finder.findAll()) {
|
||||
((jdk.internal.loader.BuiltinClassLoader) ClassLoader.getSystemClassLoader()).loadModule(mref);
|
||||
}
|
||||
|
||||
// Define all modules
|
||||
Configuration config = Configuration.resolveAndBind(finder, List.of(ModuleLayer.boot().configuration()), finder, modules);
|
||||
ModuleLayer layer = ModuleLayer.defineModules(config, List.of(ModuleLayer.boot()), name -> ClassLoader.getSystemClassLoader()).layer();
|
||||
|
||||
// Add-Exports and Add-Opens
|
||||
try {
|
||||
// Some hacks
|
||||
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Module.class, MethodHandles.lookup());
|
||||
MethodHandle handle = lookup.findVirtual(Module.class, "implAddOpensToAllUnnamed", MethodType.methodType(void.class, String.class));
|
||||
for (String target : addOpens) {
|
||||
String[] name = target.split("/", 2); // <module>/<package>
|
||||
layer.findModule(name[0]).ifPresent(m -> {
|
||||
try {
|
||||
handle.invokeWithArguments(m, name[1]);
|
||||
} catch (Throwable throwable) {
|
||||
throw new RuntimeException(throwable);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
throw new ReflectiveOperationException(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,9 +41,8 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.util;
|
||||
|
||||
import org.jackhuang.hmcl.Main;
|
||||
import org.jackhuang.hmcl.EntryPoint;
|
||||
import org.jackhuang.hmcl.Metadata;
|
||||
import org.jackhuang.hmcl.ui.SwingUtils;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.ChecksumMismatchException;
|
||||
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||
@@ -181,12 +180,6 @@ public final class SelfDependencyPatcher {
|
||||
// We are probably on 8 and its on 11
|
||||
throw new IncompatibleVersionException();
|
||||
}
|
||||
// So the problem with Java 8 is that some distributions DO NOT BUNDLE JAVAFX
|
||||
// Why is this a problem? OpenJFX does not come in public bundles prior to Java 11
|
||||
// So you're out of luck unless you change your JDK or update Java.
|
||||
if (JavaRuntime.CURRENT_VERSION < 11) {
|
||||
throw new IncompatibleVersionException();
|
||||
}
|
||||
|
||||
SelfDependencyPatcher patcher = new SelfDependencyPatcher();
|
||||
|
||||
@@ -246,7 +239,7 @@ public final class SelfDependencyPatcher {
|
||||
}
|
||||
} else {
|
||||
LOG.info("User choose not to download JavaFX");
|
||||
Main.exit(0);
|
||||
EntryPoint.exit(0);
|
||||
}
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ package org.jackhuang.hmcl.util.i18n;
|
||||
import com.google.gson.annotations.JsonAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import org.jackhuang.hmcl.java.JavaInfo;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -116,10 +115,7 @@ public final class Locales {
|
||||
if (resourceBundle == null) {
|
||||
if (this != DEFAULT && this.locale == DEFAULT.locale) {
|
||||
bundle = DEFAULT.getResourceBundle();
|
||||
} else if (JavaInfo.CURRENT_ENVIRONMENT.getParsedVersion() < 9) {
|
||||
bundle = ResourceBundle.getBundle("assets.lang.I18N", locale, UTF8Control.INSTANCE);
|
||||
} else {
|
||||
// Java 9+ uses UTF-8 as the default encoding for resource bundles
|
||||
bundle = ResourceBundle.getBundle("assets.lang.I18N", locale);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2021 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.util;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.module.Configuration;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utility for Adding JavaFX to module path.
|
||||
*
|
||||
* @author ZekerZhayard
|
||||
*/
|
||||
public final class JavaFXPatcher {
|
||||
private JavaFXPatcher() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add JavaFX to module path at runtime.
|
||||
*
|
||||
* @param modules All module names
|
||||
* @param jarPaths All jar paths
|
||||
* @throws ReflectiveOperationException When the call to add these jars to the system module path failed.
|
||||
*/
|
||||
public static void patch(Set<String> modules, Path[] jarPaths, String[] addOpens) throws ReflectiveOperationException {
|
||||
// Find all modules
|
||||
ModuleFinder finder = ModuleFinder.of(jarPaths);
|
||||
|
||||
// Load all modules as unnamed module
|
||||
for (ModuleReference mref : finder.findAll()) {
|
||||
((jdk.internal.loader.BuiltinClassLoader) ClassLoader.getSystemClassLoader()).loadModule(mref);
|
||||
}
|
||||
|
||||
// Define all modules
|
||||
Configuration config = Configuration.resolveAndBind(finder, List.of(ModuleLayer.boot().configuration()), finder, modules);
|
||||
ModuleLayer layer = ModuleLayer.defineModules(config, List.of(ModuleLayer.boot()), name -> ClassLoader.getSystemClassLoader()).layer();
|
||||
|
||||
// Add-Exports and Add-Opens
|
||||
try {
|
||||
// Some hacks
|
||||
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Module.class, MethodHandles.lookup());
|
||||
MethodHandle handle = lookup.findVirtual(Module.class, "implAddOpensToAllUnnamed", MethodType.methodType(void.class, String.class));
|
||||
for (String target : addOpens) {
|
||||
String[] name = target.split("/", 2); // <module>/<package>
|
||||
layer.findModule(name[0]).ifPresent(m -> {
|
||||
try {
|
||||
handle.invokeWithArguments(m, name[1]);
|
||||
} catch (Throwable throwable) {
|
||||
throw new RuntimeException(throwable);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
throw new ReflectiveOperationException(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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() {
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package org.jackhuang.hmcl.util.logging;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author Glavo
|
||||
*/
|
||||
final class CallerFinder {
|
||||
private static final String PACKAGE_PREFIX = CallerFinder.class.getPackageName() + ".";
|
||||
private static final Predicate<StackWalker.StackFrame> PREDICATE = stackFrame -> !stackFrame.getClassName().startsWith(PACKAGE_PREFIX);
|
||||
private static final Function<Stream<StackWalker.StackFrame>, Optional<StackWalker.StackFrame>> FUNCTION = stream -> stream.filter(PREDICATE).findFirst();
|
||||
private static final Function<StackWalker.StackFrame, String> FRAME_MAPPING = frame -> frame.getClassName() + "." + frame.getMethodName();
|
||||
|
||||
static String getCaller() {
|
||||
return StackWalker.getInstance().walk(FUNCTION).map(FRAME_MAPPING).orElse(null);
|
||||
}
|
||||
|
||||
private CallerFinder() {
|
||||
}
|
||||
}
|
||||
@@ -398,16 +398,6 @@ fatal.apply_update_failure=We are sorry, but Hello Minecraft! Launcher is unable
|
||||
fatal.apply_update_need_win7=Hello Minecraft! Launcher cannot automatically update on Windows XP/Vista.\n\
|
||||
\n\
|
||||
You can update manually by downloading a newer launcher version from %s.
|
||||
fatal.deprecated_java_version=HMCL will require Java 11 or later to run in the future, but will still support launching games with Java 8.\n\
|
||||
\n\
|
||||
It is recommended to install the latest version of Java to ensure that HMCL works properly.\n\
|
||||
\n\
|
||||
You can continue to keep the old version of Java. HMCL can recognize and manage multiple Java versions and will automatically select the appropriate Java for you based on the game version.
|
||||
fatal.deprecated_java_version.update=HMCL will require Java 11 or later to run in the future. Please install the latest version of Java to ensure that HMCL can complete the upgrade.\n\
|
||||
\n\
|
||||
You can continue to keep the old version of Java.\
|
||||
HMCL can recognize and manage multiple Java versions and will automatically select the appropriate Java for you based on the game version.
|
||||
fatal.deprecated_java_version.download_link=Download Java %d
|
||||
fatal.samba=If you opened Hello Minecraft! Launcher from a Samba network drive, some features might not be working. Please try updating your Java or moving the launcher to another directory.
|
||||
fatal.illegal_char=Your user path contains an illegal character "=". You will not be able to use authlib-injector or change the skin of your offline account.
|
||||
fatal.unsupported_platform=Minecraft is not fully supported on your platform yet, so you may experience missing features or even be unable to launch the game.\n\
|
||||
@@ -495,7 +485,7 @@ game.crash.reason.java_version_is_too_high=The game crashed because the Java ver
|
||||
Please use the previous major Java version in "Global/Instance-specific Settings → Java" and then launch the game.\n\
|
||||
\n\
|
||||
If not, you can download it from <a href="https://www.java.com/download/">java.com (Java 8)</a> or <a href="https://bell-sw.com/pages/downloads/#downloads">BellSoft Liberica Full JRE (Java 17)</a> and other distributions to download and install one (restart the launcher after installation).
|
||||
game.crash.reason.need_jdk11=The game crashed because of an inappropriate Java VM version.\n\
|
||||
game.crash.reason.need_jdk11=The game crashed because of an inappropriate Java version.\n\
|
||||
\n\
|
||||
You need to download and install Java 11, and set it in "Global/Instance-specific Settings → Java".
|
||||
game.crash.reason.mod_name=The game crashed because of mod filename problems.\n\
|
||||
@@ -565,7 +555,7 @@ game.crash.reason.optifine_causes_the_world_to_fail_to_load=The game may not con
|
||||
game.crash.reason.jdk_9=The game crashed because the Java version is too new for this instance.\n\
|
||||
\n\
|
||||
You need to download and install Java 8 and choose it in "Global/Instance-specific Settings → Java".
|
||||
game.crash.reason.jvm_32bit=The game crashed because the current memory allocation exceeded the 32-bit Java VM limit.\n\
|
||||
game.crash.reason.jvm_32bit=The game crashed because the current memory allocation exceeded the 32-bit JVM limit.\n\
|
||||
\n\
|
||||
If your OS is 64-bit, please install and use a 64-bit Java version. Otherwise, you may need to reinstall a 64-bit OS or get a moderner computer.\n\
|
||||
\n\
|
||||
@@ -646,7 +636,7 @@ game.crash.reason.opengl_not_supported=The game crashed because your graphics dr
|
||||
Or, you can update your graphic driver to the latest version and then try again.\n\
|
||||
\n\
|
||||
If your computer has a dedicated graphics card, please make sure the game is indeed using it for rendering. If the problem persists, please consider getting a new graphics card or a new computer.
|
||||
game.crash.reason.openj9=The game is unable to run on an OpenJ9 VM. Please switch to a Java that uses the Hotspot VM in "Global/Instance-specific Settings → Java" and relaunch the game. If you do not have one, you can download one.
|
||||
game.crash.reason.openj9=The game is unable to run on an OpenJ9 JVM. Please switch to a Java that uses the Hotspot JVM in "Global/Instance-specific Settings → Java" and relaunch the game. If you do not have one, you can download one.
|
||||
game.crash.reason.out_of_memory=The game crashed because the computer ran out of memory.\n\
|
||||
\n\
|
||||
Maybe there is not enough memory available or too many mods installed. You can try resolving it by increasing the allocated memory in "Global/Instance-specific Settings → Memory".\n\
|
||||
@@ -660,7 +650,7 @@ game.crash.reason.stacktrace=The crash reason is unknown. You can view its detai
|
||||
There are some keywords that might contain some mod names. You can search them online to figure out the problem yourself.\n\
|
||||
\n\
|
||||
%s
|
||||
game.crash.reason.too_old_java=The game crashed because you are using an outdated Java VM version.\n\
|
||||
game.crash.reason.too_old_java=The game crashed because you are using an outdated Java version.\n\
|
||||
\n\
|
||||
You need to switch to a newer Java version (%1$s) in "Global/Instance-specific Settings → Java" and then relaunch the game. You can download Java from <a href="https://learn.microsoft.com/java/openjdk/download">here</a>.
|
||||
game.crash.reason.unknown=We are not able to figure out why the game crashed. Please refer to the game logs.
|
||||
@@ -769,10 +759,10 @@ lang.default=Use System Locales
|
||||
|
||||
launch.advice=%s Do you still want to continue to launch?
|
||||
launch.advice.multi=The following problems were detected:\n\n%s\n\nThese problems may prevent you from launching the game or affect gaming experience.\nDo you still want to continue to launch?
|
||||
launch.advice.java.auto=The current Java VM version is not compatible with the instance.\n\nClick "Yes" to automatically choose the most compatible Java VM version. Or, you can navigate to "Global/Instance-specific Settings → Java" to choose one yourself.
|
||||
launch.advice.java.auto=The current Java version is not compatible with the instance.\n\nClick "Yes" to automatically choose the most compatible Java version. Or, you can navigate to "Global/Instance-specific Settings → Java" to choose one yourself.
|
||||
launch.advice.java.modded_java_7=Minecraft 1.7.2 and previous versions require Java 7 or earlier.
|
||||
launch.advice.corrected=We have resolved the Java VM problem. If you still want to use your choice of Java version, you can disable "Do not check Java VM compatibility" in "Global/Instance-specific Settings → Advanced Settings".
|
||||
launch.advice.uncorrected=If you still want to use your choice of Java version, you can disable "Do not check Java VM compatibility" in "Global/Instance-specific Settings → Advanced Settings".
|
||||
launch.advice.corrected=We have resolved the Java problem. If you still want to use your choice of Java version, you can disable "Do not check JVM compatibility" in "Global/Instance-specific Settings → Advanced Settings".
|
||||
launch.advice.uncorrected=If you still want to use your choice of Java version, you can disable "Do not check JVM compatibility" in "Global/Instance-specific Settings → Advanced Settings".
|
||||
launch.advice.different_platform=The 64-bit Java version is recommended for your device, but you have installed a 32-bit one.
|
||||
launch.advice.forge2760_liteloader=Forge version 2760 is not compatible with LiteLoader. Please consider upgrading Forge to version 2773 or later.
|
||||
launch.advice.forge28_2_2_optifine=Forge version 28.2.2 or later is not compatible with OptiFine. Please consider downgrading Forge to version 28.2.1 or earlier.
|
||||
@@ -790,7 +780,7 @@ launch.advice.vanilla_linux_java_8=Minecraft 1.12.2 or earlier only supports Jav
|
||||
launch.advice.vanilla_x86.translation=Minecraft is not fully supported on your platform, so you may experience missing features or even be unable to launch the game.\nYou can download Java for the <b>x86-64</b> architecture <a href="https://learn.microsoft.com/java/openjdk/download">here</a> for a full gaming experience.
|
||||
launch.advice.unknown=The game cannot be launched due to the following reasons:
|
||||
launch.failed=Failed to launch
|
||||
launch.failed.cannot_create_jvm=We are unable to create a Java VM. It may be caused by incorrect Java VM arguments. You can try resolving it by removing all arguments you added in "Global/Instance-specific Settings → Advanced Settings → Java VM Options".
|
||||
launch.failed.cannot_create_jvm=We are unable to create a JVM. It may be caused by incorrect JVM arguments. You can try resolving it by removing all arguments you added in "Global/Instance-specific Settings → Advanced Settings → JVM Options".
|
||||
launch.failed.creating_process=We are unable to create a new process. Please check your Java path.\n
|
||||
launch.failed.command_too_long=The command length exceeds the maximum length of a batch script. Please try exporting it as a PowerShell script.
|
||||
launch.failed.decompressing_natives=Failed to extract native libraries.\n
|
||||
@@ -1239,18 +1229,18 @@ settings.advanced.custom_commands.hint=The following environment variables are p
|
||||
\ · $INST_FABRIC: set if Fabric is installed.\n\
|
||||
\ · $INST_QUILT: set if Quilt is installed.
|
||||
settings.advanced.dont_check_game_completeness=Do not check game integrity
|
||||
settings.advanced.dont_check_jvm_validity=Do not check Java VM compatibility
|
||||
settings.advanced.dont_check_jvm_validity=Do not check JVM compatibility
|
||||
settings.advanced.dont_patch_natives=Do not attempt to automatically replace native libraries
|
||||
settings.advanced.environment_variables=Environment Variables
|
||||
settings.advanced.game_dir.default=Default (".minecraft/")
|
||||
settings.advanced.game_dir.independent=Isolated (".minecraft/versions/<instance name>/", except for assets and libraries)
|
||||
settings.advanced.java_permanent_generation_space=PermGen Space
|
||||
settings.advanced.java_permanent_generation_space.prompt=in MiB
|
||||
settings.advanced.jvm=Java VM Options
|
||||
settings.advanced.jvm_args=Java VM Arguments
|
||||
settings.advanced.jvm_args.prompt=\ · If the arguments entered in "Java VM arguments" are the same as the default arguments, it will not be added.\n\
|
||||
\ · Enter any GC arguments in "Java VM arguments", and the G1 argument of the default arguments will be disabled.\n\
|
||||
\ · Enable "Do not add default Java VM arguments" to launch the game without adding default arguments.
|
||||
settings.advanced.jvm=JVM Options
|
||||
settings.advanced.jvm_args=JVM Arguments
|
||||
settings.advanced.jvm_args.prompt=\ · If the arguments entered in "JVM Arguments" are the same as the default arguments, it will not be added.\n\
|
||||
\ · Enter any GC arguments in "JVM Arguments", and the G1 argument of the default arguments will be disabled.\n\
|
||||
\ · Enable "Do not add default JVM arguments" to launch the game without adding default arguments.
|
||||
settings.advanced.launcher_visibility.close=Close the launcher after the game launches
|
||||
settings.advanced.launcher_visibility.hide=Hide the launcher after the game launches
|
||||
settings.advanced.launcher_visibility.hide_and_reopen=Hide the launcher and show it when the game closes
|
||||
@@ -1266,7 +1256,7 @@ settings.advanced.natives_directory.hint=This option is intended only for users
|
||||
\n\
|
||||
Before proceeding, please make sure all libraries (e.g. lwjgl.dll, libopenal.so) are provided in your desired directory.\n\
|
||||
Note: It is recommended to use a fully English-letters path for the specified local library file. Otherwise it may lead to game launch failure.
|
||||
settings.advanced.no_jvm_args=Do not add default Java VM arguments
|
||||
settings.advanced.no_jvm_args=Do not add default JVM arguments
|
||||
settings.advanced.precall_command=Pre-launch Command
|
||||
settings.advanced.precall_command.prompt=Commands to execute before the game launches
|
||||
settings.advanced.process_priority=Process Priority
|
||||
@@ -1331,6 +1321,10 @@ settings.launcher.download_source=Download Source
|
||||
settings.launcher.download_source.auto=Automatically Choose Download Sources
|
||||
settings.launcher.enable_game_list=Show instance list in homepage
|
||||
settings.launcher.font=Font
|
||||
settings.launcher.font.anti_aliasing=Anti-aliasing
|
||||
settings.launcher.font.anti_aliasing.auto=Auto
|
||||
settings.launcher.font.anti_aliasing.gray=Grayscale
|
||||
settings.launcher.font.anti_aliasing.lcd=Sub-pixel
|
||||
settings.launcher.general=General
|
||||
settings.launcher.language=Language (Applies After Restart)
|
||||
settings.launcher.launcher_log.export=Export Launcher Logs
|
||||
@@ -1443,7 +1437,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
|
||||
|
||||
@@ -400,17 +400,6 @@ fatal.apply_update_failure=Lo sentimos, pero Hello Minecraft! Launcher no puede
|
||||
fatal.apply_update_need_win7=Hello Minecraft! Launcher no puede actualizarse automáticamente en Windows XP/Vista.\n\
|
||||
\n\
|
||||
Puedes actualizar manualmente descargando una versión más reciente del launcher desde %s.
|
||||
fatal.deprecated_java_version=HMCL requerirá Java 11 o posterior para funcionar en el futuro, pero seguirá siendo compatible con el lanzamiento de juegos con Java 8.\n\
|
||||
\n\
|
||||
Se recomienda instalar la última versión de Java para garantizar el correcto funcionamiento de HMCL.\n\
|
||||
\n\
|
||||
Puedes conservar la versión antigua de Java. HMCL puede reconocer y gestionar varias versiones de Java y elegirá automáticamente la adecuada para usted en función de la versión del juego.
|
||||
fatal.deprecated_java_version.update=HMCL requerirá Java 11 o posterior para funcionar en el futuro. Por favor, instalar la última versión de Java para asegurarse de que el lanzador puede completar la actualización.\n\
|
||||
\n\
|
||||
Puedes conservar la versión antigua de Java.\
|
||||
HMCL puede reconocer y gestionar varias versiones de Java \
|
||||
y elegirá automáticamente la adecuada para usted en función de la versión del juego.
|
||||
fatal.deprecated_java_version.download_link=Descargar Java %d
|
||||
fatal.samba=Si ha abierto Hello Minecraft! Launcher desde una unidad de red Samba, es posible que algunas funciones no funcionen. Intenta actualizar tu Java o mover el launcher a otro directorio.
|
||||
fatal.illegal_char=Su ruta de usuario contiene un carácter ilegal «=», por lo que algunas características podrían no funcionar correctamente.\n\
|
||||
Por ejemplo, no podrá utilizar authlib-injector o cambiar el skin de su cuenta offline.
|
||||
@@ -446,7 +435,6 @@ folder.shaderpacks=Paquetes de sombreados
|
||||
folder.saves=Mundos
|
||||
folder.schematics=Esquemas
|
||||
folder.screenshots=Capturas de pantalla
|
||||
folder.world=Directorio del mundo
|
||||
|
||||
game=Juegos
|
||||
game.crash.feedback=<b>¡Por favor, no comparta capturas de pantalla de esta interfaz con otras personas!</b> Si pide ayuda a otras personas, haga clic en <b>Exportar registros de colgado</b> y envíe el archivo exportado a otras personas para que lo analicen.
|
||||
@@ -514,7 +502,7 @@ game.crash.reason.jdk_9=El juego se ha colgado porque la versión de Java es dem
|
||||
game.crash.reason.need_jdk11=El juego se ha colgado debido a una versión inadecuada de Java.\n\
|
||||
\n\
|
||||
Debes descargar e instalar Java 11 y configurarlo en «Config. Global/Específica de instancia → Java».
|
||||
game.crash.reason.jvm_32bit=El juego se ha colgado porque la asignación de memoria actual excedía el límite de 32 bits JVM.\n\
|
||||
game.crash.reason.jvm_32bit=El juego se ha colgado porque la asignación de memoria actual excedía el límite de 32 bits de la JVM.\n\
|
||||
\n\
|
||||
Si su sistema operativo es de 64 bits, instale y utilice una versión de Java de 64 bits. De lo contrario, es posible que tenga que volver a instalar un sistema operativo de 64 bits o adquirir un ordenador más moderno.\n\
|
||||
\n\
|
||||
@@ -647,7 +635,7 @@ game.crash.reason.stacktrace=El motivo del cuelgue es desconocido. Puedes ver lo
|
||||
Hay algunas palabras clave que pueden contener algunos nombres de mods. Puedes buscarlas en Internet para averiguar el problema tú mismo.\n\
|
||||
\n\
|
||||
%s
|
||||
game.crash.reason.too_old_java=El juego se ha colgado porque estás utilizando una versión de Java VM obsoleta.\n\
|
||||
game.crash.reason.too_old_java=El juego se ha colgado porque estás utilizando una versión de Java obsoleta.\n\
|
||||
\n\
|
||||
Tienes que cambiar a una versión de Java más reciente (%1$s) en «Config. Global/Específica de instancia → Java» y, a continuación, volver a ejecutar el juego. Puede descargar Java desde <a href="https://learn.microsoft.com/java/openjdk/download">aquí</a>.
|
||||
game.crash.reason.unknown=No somos capaces de averiguar por qué se ha colgado el juego. Por favor, refiérase a los registros del juego.
|
||||
@@ -775,10 +763,10 @@ lang.default=Usar idioma del sistema
|
||||
|
||||
launch.advice=%s ¿Todavía quieres continuar?
|
||||
launch.advice.multi=Se han detectado los siguientes problemas:\n\n%s\n\nEstos problemas pueden impedir que inicies el juego o afectar a la experiencia de juego.\n\n¿Todavía quieres continuar?
|
||||
launch.advice.java.auto=La versión actual de la máquina virtual de Java no cumple los requisitos del juego.\n\nHaga clic en «Sí» para elegir automáticamente la versión de Java VM más compatible. O bien, puede navegar hasta «Config. Global/Específica de instancia → Java» para elegir uno usted mismo.
|
||||
launch.advice.java.auto=La versión actual de Java no es compatible con la instancia.\n\nHaga clic en «Sí» para elegir automáticamente la versión de Java más compatible. O bien, puede navegar hasta «Config. Global/Específica de instancia → Java» para elegir uno usted mismo.
|
||||
launch.advice.java.modded_java_7=Minecraft 1.7.2 y versiones anteriores requieren Java 7 o anterior.
|
||||
launch.advice.corrected=Hemos solucionado el problema de la máquina virtual de Java. Si todavía quieres utilizar la versión de Java que elijas, puedes desactivar la opción «No comprobar la compatibilidad de la JVM» en «Config. Global/Específica de instancia → Configuración avanzada».
|
||||
launch.advice.uncorrected=Si todavía quieres utilizar la versión de Java que elijas, puedes desactivar la opción «No comprobar la compatibilidad de la JVM» en «Config. Global/Específica de instancia → Configuración avanzada».
|
||||
launch.advice.corrected=Hemos resuelto el problema de Java. Si aún desea utilizar la versión de Java que elija, puede desactivar «No comprobar la compatibilidad con JVM» en «Config. Global/Específica de instancia → Configuración avanzada».
|
||||
launch.advice.uncorrected=Si aún desea utilizar la versión de Java que elija, puede desactivar «No comprobar la compatibilidad con JVM» en «Config. Global/Específica de instancia → Configuración avanzada».
|
||||
launch.advice.different_platform=Se recomienda la versión de 64 bits de Java para tu dispositivo, pero has instalado una de 32 bits.
|
||||
launch.advice.forge2760_liteloader=La versión 2760 o posterior de Forge no es compatible con LiteLoader, por favor considere actualizar Forge a la versión 2773 o posterior.
|
||||
launch.advice.forge28_2_2_optifine=La versión 28.2.2 o posterior de Forge no es compatible con OptiFine. Considere la posibilidad de actualizar Forge a la versión 28.2.1 o anterior.
|
||||
@@ -796,7 +784,7 @@ launch.advice.vanilla_linux_java_8=Minecraft 1.12.2 o inferior sólo admite Java
|
||||
launch.advice.vanilla_x86.translation=Minecraft no proporciona actualmente soporte oficial para arquitecturas distintas de x86 y x86-64.\n\nPor favor, instale Java para x86-64 para jugar a Minecraft a través del entorno de traducción Rosetta, o descargue sus bibliotecas nativas correspondientes y especifique su ruta.
|
||||
launch.advice.unknown=El juego no puede iniciarse por las siguientes razones:
|
||||
launch.failed=No se puede ejecutar
|
||||
launch.failed.cannot_create_jvm=No podemos crear una máquina virtual Java. Puede deberse a un problema con los argumentos de ejecución proporcionados, puede intentar solucionarlo eliminando todos los argumentos que haya añadido en la configuración de la instancia.
|
||||
launch.failed.cannot_create_jvm=No podemos crear una JVM. Puede deberse a un problema con los argumentos de ejecución proporcionados, puede intentar solucionarlo eliminando todos los argumentos que haya añadido en la configuración de la instancia.
|
||||
launch.failed.creating_process=No podemos crear un nuevo proceso, por favor compruebe la ruta de Java.\n
|
||||
launch.failed.command_too_long=La longitud del comando excede la longitud máxima de un script bat. Por favor, intente exportarlo como un script de PowerShell.
|
||||
launch.failed.decompressing_natives=No se han podido descomprimir las bibliotecas nativas.\n
|
||||
@@ -944,16 +932,11 @@ modpack.wizard.step.initialization.warning=Antes de hacer un modpack, por favor
|
||||
modpack.wizard.step.initialization.server=Haga clic aquí para ver más tutoriales para hacer un modpack de servidor que se pueda actualizar automáticamente.
|
||||
|
||||
modrinth.category.adventure=Aventura
|
||||
modrinth.category.atmosphere=Atmósfera
|
||||
modrinth.category.audio=Audio
|
||||
modrinth.category.blocks=Bloqueos
|
||||
modrinth.category.bloom=Resplandor
|
||||
modrinth.category.bukkit=Bukkit
|
||||
modrinth.category.bungeecord=BungeeCord
|
||||
modrinth.category.canvas=Canvas
|
||||
modrinth.category.cartoon=Caricatura
|
||||
modrinth.category.challenging=Desafío
|
||||
modrinth.category.colored-lighting=Iluminación de color
|
||||
modrinth.category.core-shaders=Sombreadores de núcleo
|
||||
modrinth.category.combat=Combate
|
||||
modrinth.category.cursed=Maldición
|
||||
@@ -963,25 +946,19 @@ modrinth.category.entities=Entidades
|
||||
modrinth.category.environment=Medio ambiente
|
||||
modrinth.category.equipment=Equipo
|
||||
modrinth.category.fabric=Fabric
|
||||
modrinth.category.fantasy=Fantasía
|
||||
modrinth.category.foliage=Vegetación
|
||||
modrinth.category.fonts=Fonts
|
||||
modrinth.category.food=Alimentos
|
||||
modrinth.category.forge=Forge
|
||||
modrinth.category.game-mechanics=Mecánica de juego
|
||||
modrinth.category.gui=GUI
|
||||
modrinth.category.high=Alto
|
||||
modrinth.category.iris=Iris
|
||||
modrinth.category.items=Objetos
|
||||
modrinth.category.kitchen-sink=Fregadero de cocina
|
||||
modrinth.category.library=Biblioteca
|
||||
modrinth.category.lightweight=Peso ligero
|
||||
modrinth.category.liteloader=LiteLoader
|
||||
modrinth.category.locale=Locale
|
||||
modrinth.category.low=Bajo
|
||||
modrinth.category.magic=Magia
|
||||
modrinth.category.management=Gestión
|
||||
modrinth.category.medium=Medio
|
||||
modrinth.category.minecraft=Minecraft
|
||||
modrinth.category.minigame=Minijuego
|
||||
modrinth.category.misc=Misceláneo
|
||||
@@ -991,21 +968,13 @@ modrinth.category.models=Modelos
|
||||
modrinth.category.modloader=Cargador de mods
|
||||
modrinth.category.multiplayer=Multijugador
|
||||
modrinth.category.neoforge=NeoForge
|
||||
modrinth.category.optifine=OptiFine
|
||||
modrinth.category.optimization=Optimización
|
||||
modrinth.category.paper=Paper
|
||||
modrinth.category.path-tracing=Trazado de rutas
|
||||
modrinth.category.pbr=PBR
|
||||
modrinth.category.potato=Mínimo
|
||||
modrinth.category.purpur=Purpur
|
||||
modrinth.category.quests=Misiones
|
||||
modrinth.category.quilt=Quilt
|
||||
modrinth.category.realistic=Realista
|
||||
modrinth.category.reflections=Reflexiones
|
||||
modrinth.category.rift=Rift
|
||||
modrinth.category.screenshot=Extremo
|
||||
modrinth.category.semi-realistic=Semirrealista
|
||||
modrinth.category.shadows=Sombras
|
||||
modrinth.category.simplistic=Simplista
|
||||
modrinth.category.social=Social
|
||||
modrinth.category.spigot=Spigot
|
||||
@@ -1016,7 +985,6 @@ modrinth.category.themed=Temática
|
||||
modrinth.category.transportation=Transporte
|
||||
modrinth.category.tweaks=Ajustes
|
||||
modrinth.category.utility=Utilidad
|
||||
modrinth.category.vanilla=Vainilla
|
||||
modrinth.category.vanilla-like=Similar a la vainilla
|
||||
modrinth.category.velocity=Velocity
|
||||
modrinth.category.waterfall=Waterfall
|
||||
@@ -1104,12 +1072,7 @@ world.backup.create.locked=El mundo está actualmente en uso. Por favor, cierra
|
||||
world.backup.create.success=Creada con éxito una nueva copia de seguridad: %s
|
||||
world.backup.delete=Eliminar esta copia de seguridad
|
||||
world.backup.processing=Creando nueva copia de seguridad ...
|
||||
world.chunkbase=Chunk Base
|
||||
world.chunkbase.end_city=Ciudad del End
|
||||
world.chunkbase.seed_map=Vista previa de la generación mundial
|
||||
world.chunkbase.stronghold=Fortaleza
|
||||
world.chunkbase.nether_fortress=Fortaleza del Nether
|
||||
world.datapack=Paquetes de datos
|
||||
world.datapack=Gestionar paquetes de datos
|
||||
world.datetime=Jugado por última vez en %s
|
||||
world.download=Descargar Mundo
|
||||
world.download.title=Descargar mundo - %1s
|
||||
@@ -1154,8 +1117,7 @@ world.info.time=Tiempo de juego
|
||||
world.info.time.format=%s días
|
||||
world.locked=En uso
|
||||
world.manage=Mundos
|
||||
world.manage.button=Administrar
|
||||
world.manage.title=Mundo - %s
|
||||
world.manage.title=Mundos - %s
|
||||
world.name=Nombre del mundo
|
||||
world.name.enter=Introducir el nombre del mundo
|
||||
world.show_all=Mostrar todo
|
||||
@@ -1245,18 +1207,18 @@ settings.advanced.custom_commands.hint=Se proporcionan las siguientes variables
|
||||
\ · $INST_FABRIC: disponible si Fabric está instalado.\n\
|
||||
\ · $INST_QUILT: disponible si Quilt está instalado.
|
||||
settings.advanced.dont_check_game_completeness=No chequear integridad del juego
|
||||
settings.advanced.dont_check_jvm_validity=No comprobar la compatibilidad de la JVM
|
||||
settings.advanced.dont_check_jvm_validity=No comprobar la compatibilidad con JVM
|
||||
settings.advanced.dont_patch_natives=No intente sustituir automáticamente las bibliotecas nativas
|
||||
settings.advanced.environment_variables=Variables de entorno
|
||||
settings.advanced.game_dir.default=Por defecto («.minecraft/»)
|
||||
settings.advanced.game_dir.independent=Aislar («.minecraft/versions/<nombre de la instancia>/», excepto para los activos y las bibliotecas)
|
||||
settings.advanced.java_permanent_generation_space=Espacio PermGen
|
||||
settings.advanced.java_permanent_generation_space.prompt=en MiB
|
||||
settings.advanced.jvm=Opciones de la máquina virtual de Java
|
||||
settings.advanced.jvm_args=Argumentos de la máquina virtual de Java
|
||||
settings.advanced.jvm_args.prompt=\ · Si los argumentos introducidos en «Argumentos de la máquina virtual de Java» son los mismos que los argumentos por defecto, no se añadirán.\n\
|
||||
\ · Introduzca cualquier argumento GC en «Argumentos de la máquina virtual de Java», y se desactivará el argumento G1 de los argumentos por defecto.\n\
|
||||
\ · Activa «No añadir argumentos por defecto de JVM» para ejecutar el juego sin añadir argumentos por defecto.
|
||||
settings.advanced.jvm=Opciones de JVM
|
||||
settings.advanced.jvm_args=Argumentos JVM
|
||||
settings.advanced.jvm_args.prompt=\ · Si los argumentos introducidos en «Argumentos JVM» son los mismos que los argumentos por defecto, no se añadirán.\n\
|
||||
\ · Introduzca cualquier argumento GC en «Argumentos JVM», y se desactivará el argumento G1 de los argumentos por defecto.\n\
|
||||
\ · Activa «No añadir argumentos JVM por defecto» para ejecutar el juego sin añadir argumentos por defecto.
|
||||
settings.advanced.launcher_visibility.close=Cerrar el launcher después de ejecutar el juego.
|
||||
settings.advanced.launcher_visibility.hide=Ocultar el launcher después de ejecutar el juego.
|
||||
settings.advanced.launcher_visibility.hide_and_reopen=Ocultar el launcher y volver a abrirlo cuando se cierra el juego.
|
||||
@@ -1271,7 +1233,7 @@ settings.advanced.natives_directory.default=Por defecto
|
||||
settings.advanced.natives_directory.hint=Esta opción está pensada sólo para usuarios de Apple M1 u otras plataformas no soportadas oficialmente. Por favor, no modifique esta opción a menos que sepa lo que está haciendo.\n\
|
||||
\n\
|
||||
Antes de proceder, por favor, asegúrese de que todas las bibliotecas (por ejemplo, lwjgl.dll, libopenal.so) se proporcionan en su directorio deseado.
|
||||
settings.advanced.no_jvm_args=No añadir argumentos por defecto de JVM
|
||||
settings.advanced.no_jvm_args=No añadir argumentos JVM por defecto
|
||||
settings.advanced.precall_command=Comando pre-lanzamiento:
|
||||
settings.advanced.precall_command.prompt=El comando se ejecuta antes de que los juegos se lance
|
||||
settings.advanced.process_priority=Prioridad del proceso
|
||||
@@ -1444,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
|
||||
|
||||
@@ -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=すべてのゲームリソースファイルの削除
|
||||
|
||||
@@ -398,17 +398,6 @@ fatal.apply_update_failure=Мы сожалеем, лаунчер не смог
|
||||
Вы можете обновить программу вручную, скачав более новую версию с %s.
|
||||
fatal.apply_update_need_win7=Лаунчер не может автоматически обновляться на Windows XP/Vista.\n\
|
||||
Вы можете обновить программу вручную, скачав более новую версию с %s.
|
||||
fatal.deprecated_java_version=В будущем для работы HMCL потребуется Java 11 или более поздняя версия, однако запуск игр будет поддерживаться и на Java 8.\n\
|
||||
\n\
|
||||
Рекомендуется установить последнюю версию Java, чтобы обеспечить правильную работу HMCL.\n\
|
||||
\n\
|
||||
Вы можете продолжать использовать старую версию Java. HMCL может распознавать и управлять несколькими версиями Java и автоматически выбирать подходящую Java в зависимости от версии игры.
|
||||
fatal.deprecated_java_version.update=В будущем для работы HMCL потребуется Java 11 или более поздняя версия. Пожалуйста, установить последнюю версию Java, чтобы убедиться, что приложение сможет завершить обновление.\n\
|
||||
\n\
|
||||
Вы можете продолжать использовать старую версию Java.\
|
||||
HMCL может распознавать и управлять несколькими версиями Java \
|
||||
и автоматически выбирать подходящую Java в зависимости от версии игры.
|
||||
fatal.deprecated_java_version.download_link=Скачать Java %d
|
||||
fatal.samba=Если вы пытаетесь открыть лаунчер в общей папке Samba, он может не работать, попробуйте обновить Java или запустить лаунчер из локальной папки.
|
||||
fatal.illegal_char=Недопустимый символ «=» в пути к папке пользователя. Лаунчер может работать, но некоторые функции не будут работать.\n\
|
||||
Вы не сможете использовать аккаунт authlib-injector или изменить скин для аккаунта в режиме офлайн.
|
||||
@@ -444,7 +433,6 @@ folder.shaderpacks=Пакеты шейдеров
|
||||
folder.saves=Миры
|
||||
folder.schematics=Схемы
|
||||
folder.screenshots=Снимки экрана
|
||||
folder.world=Папка мира
|
||||
|
||||
game=Игры
|
||||
game.crash.feedback=<b>Пожалуйста, не делитесь скриншотами этого интерфейса с другими!</b> Если вы просите помощи у других, нажмите <b>«Экспорт журналов с ошибками»</b> и отправьте экспортированный файл другим для анализа.
|
||||
@@ -943,16 +931,11 @@ modpack.wizard.step.initialization.warning=Перед созданием мод
|
||||
modpack.wizard.step.initialization.server=Нажмите здесь для получения дополнительных руководств по созданию модпака на сервере, который может автообновляться.
|
||||
|
||||
modrinth.category.adventure=Приключение
|
||||
modrinth.category.atmosphere=Атмосфера
|
||||
modrinth.category.audio=Аудио
|
||||
modrinth.category.blocks=Блоки
|
||||
modrinth.category.bloom=Свечение
|
||||
modrinth.category.bukkit=Bukkit
|
||||
modrinth.category.bungeecord=BungeeCord
|
||||
modrinth.category.canvas=Canvas
|
||||
modrinth.category.cartoon=Мультяшный
|
||||
modrinth.category.challenging=Вызов
|
||||
modrinth.category.colored-lighting=Цветное освещение
|
||||
modrinth.category.core-shaders=Ядро шейдеров
|
||||
modrinth.category.combat=Бой
|
||||
modrinth.category.cursed=Cursed
|
||||
@@ -962,25 +945,19 @@ modrinth.category.entities=Сущности
|
||||
modrinth.category.environment=Окружающая среда
|
||||
modrinth.category.equipment=Оборудование
|
||||
modrinth.category.fabric=Fabric
|
||||
modrinth.category.fantasy=Фэнтези
|
||||
modrinth.category.foliage=Растительность
|
||||
modrinth.category.fonts=Шрифты
|
||||
modrinth.category.food=Еда
|
||||
modrinth.category.forge=Forge
|
||||
modrinth.category.game-mechanics=Игровая механика
|
||||
modrinth.category.gui=ГИП
|
||||
modrinth.category.high=Высокий
|
||||
modrinth.category.iris=Iris
|
||||
modrinth.category.items=Предметы
|
||||
modrinth.category.kitchen-sink=Kitchen-Sink
|
||||
modrinth.category.library=Библиотека
|
||||
modrinth.category.lightweight=Легкий
|
||||
modrinth.category.liteloader=LiteLoader
|
||||
modrinth.category.locale=Язык
|
||||
modrinth.category.low=Низкий
|
||||
modrinth.category.magic=Магия
|
||||
modrinth.category.management=Управление
|
||||
modrinth.category.medium=Средний
|
||||
modrinth.category.minecraft=Minecraft
|
||||
modrinth.category.minigame=Мини-игра
|
||||
modrinth.category.misc=Разное
|
||||
@@ -990,21 +967,13 @@ modrinth.category.models=Модели
|
||||
modrinth.category.modloader=Мод-загрузчик
|
||||
modrinth.category.multiplayer=Сетевая игра
|
||||
modrinth.category.neoforge=NeoForge
|
||||
modrinth.category.optifine=OptiFine
|
||||
modrinth.category.optimization=Оптимизация
|
||||
modrinth.category.paper=Paper
|
||||
modrinth.category.path-tracing=Трассировка пути
|
||||
modrinth.category.pbr=PBR
|
||||
modrinth.category.potato=Минимум
|
||||
modrinth.category.purpur=Purpur
|
||||
modrinth.category.quests=Квесты
|
||||
modrinth.category.quilt=Quilt
|
||||
modrinth.category.realistic=Реалистичный
|
||||
modrinth.category.reflections=Отражения
|
||||
modrinth.category.rift=Rift
|
||||
modrinth.category.screenshot=Экстрим
|
||||
modrinth.category.semi-realistic=Полуреалистичный
|
||||
modrinth.category.shadows=Тени
|
||||
modrinth.category.simplistic=Упрощенный
|
||||
modrinth.category.social=Социальная
|
||||
modrinth.category.spigot=Spigot
|
||||
@@ -1015,7 +984,6 @@ modrinth.category.themed=Тематический
|
||||
modrinth.category.transportation=Транспорт
|
||||
modrinth.category.tweaks=Усовершенствование
|
||||
modrinth.category.utility=Утилиты
|
||||
modrinth.category.vanilla=Ванильное
|
||||
modrinth.category.vanilla-like=Ванильное
|
||||
modrinth.category.velocity=Velocity
|
||||
modrinth.category.waterfall=Waterfall
|
||||
@@ -1103,12 +1071,7 @@ world.backup.create.locked=В настоящее время мир находи
|
||||
world.backup.create.success=Успешно создано новое резервное копирование: %s
|
||||
world.backup.delete=Удалить эту резервную копию
|
||||
world.backup.processing=Создание новой резервной копии ...
|
||||
world.chunkbase=Chunk Base
|
||||
world.chunkbase.end_city=Город Края
|
||||
world.chunkbase.seed_map=Предпросмотр генерации мира
|
||||
world.chunkbase.stronghold=Крепость
|
||||
world.chunkbase.nether_fortress=Крепость Нижнего мира
|
||||
world.datapack=Наборы данных
|
||||
world.datapack=Управлять наборами данных
|
||||
world.datetime=Последний запуск игры %s
|
||||
world.download=Скачать мир
|
||||
world.download.title=Скачать мир - %1s
|
||||
@@ -1153,8 +1116,7 @@ world.info.time=Время игры
|
||||
world.info.time.format=%s дн.
|
||||
world.locked=В эксплуатации
|
||||
world.manage=Миры
|
||||
world.manage.button=Управлять
|
||||
world.manage.title=Мир - %s
|
||||
world.manage.title=Миры - %s
|
||||
world.name=Название мира
|
||||
world.name.enter=Введите название мира
|
||||
world.show_all=Показать все
|
||||
@@ -1244,18 +1206,18 @@ settings.advanced.custom_commands.hint=Пользовательские кома
|
||||
\ · $INST_FABRIC: устанавливается, если установлен Fabric.\n\
|
||||
\ · $INST_QUILT: устанавливается, если установлен Quilt.
|
||||
settings.advanced.dont_check_game_completeness=Не проверять целостность игры
|
||||
settings.advanced.dont_check_jvm_validity=Не проверять совместимость Java VM
|
||||
settings.advanced.dont_check_jvm_validity=Не проверять совместимость JVM
|
||||
settings.advanced.dont_patch_natives=Не пытайтесь автоматически заменить нативные библиотеки
|
||||
settings.advanced.environment_variables=Переменные среды
|
||||
settings.advanced.game_dir.default=По умолчанию («.minecraft/»)
|
||||
settings.advanced.game_dir.independent=Раздельно («.minecraft/versions/<имя сборки>/», кроме assets и библиотек)
|
||||
settings.advanced.java_permanent_generation_space=Пространство PermGen
|
||||
settings.advanced.java_permanent_generation_space.prompt=в МиБ
|
||||
settings.advanced.jvm=Настройки Java VM
|
||||
settings.advanced.jvm_args=Аргументы Java VM
|
||||
settings.advanced.jvm_args.prompt=\ · Если параметр, введённый в «Аргументы Java VM», совпадает с параметром по умолчанию, он не будет добавлен.\n\
|
||||
\ · Введите любые параметры GC в «Аргументы Java VM», параметр G1 по умолчанию будет отключен.\n\
|
||||
\ · Нажмите «Не добавлять аргументы Java VM по умолчанию» ниже, чтобы запустить игру без добавления аргументов по умолчанию.
|
||||
settings.advanced.jvm=Настройки JVM
|
||||
settings.advanced.jvm_args=Аргументы JVM
|
||||
settings.advanced.jvm_args.prompt=\ · Если параметр, введённый в «Аргументы JVM», совпадает с параметром по умолчанию, он не будет добавлен.\n\
|
||||
\ · Введите любые параметры GC в «Аргументы JVM», параметр G1 по умолчанию будет отключен.\n\
|
||||
\ · Нажмите «Не добавлять аргументы JVM по умолчанию» ниже, чтобы запустить игру без добавления аргументов по умолчанию.
|
||||
settings.advanced.launcher_visibility.close=Закрывать после запуска игры
|
||||
settings.advanced.launcher_visibility.hide=Скрыть после запуска игры
|
||||
settings.advanced.launcher_visibility.hide_and_reopen=Скрыть после запуска и показать после закрытия игры
|
||||
@@ -1271,7 +1233,7 @@ settings.advanced.natives_directory.hint=Параметр предназначе
|
||||
\n\
|
||||
Прежде чем продолжить, убедитесь что все библиотеки (например, lwjgl.dll, libopenal.so) находятся в нужной папке.\n\
|
||||
Примечание: Рекомендуется использовать полностью английские пути для указанных файлов локальных библиотек, иначе игра может не запуститься.
|
||||
settings.advanced.no_jvm_args=Не добавлять аргументы Java VM по умолчанию
|
||||
settings.advanced.no_jvm_args=Не добавлять аргументы JVM по умолчанию
|
||||
settings.advanced.precall_command=Команда перед запуском
|
||||
settings.advanced.precall_command.prompt=Команды, которые необходимо выполнить перед запуском игры
|
||||
settings.advanced.process_priority=Приоритет процесса
|
||||
@@ -1444,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=Удалить файлы игровых активов
|
||||
|
||||
@@ -360,7 +360,7 @@ exception.access_denied=無法存取檔案「%s」。因為 HMCL 沒有對該檔
|
||||
請你檢查目前作業系統帳戶是否能訪存取檔案,比如非管理員使用者可能不能訪問其他帳戶的個人目錄內的檔案。\n\
|
||||
對於 Windows 使用者,你還可以嘗試透過資源監視器查看是否有程式占用了該檔案。如果是,你可以關閉占用此檔案的程式,或者重啟電腦再試。
|
||||
exception.artifact_malformed=下載的檔案正確,但無法透過校驗。
|
||||
exception.ssl_handshake=無法建立 SSL 連線。因為目前 Java 虛擬機缺少相關的 SSL 證書。你可以嘗試使用其他的 Java 虛擬機或關閉網路代理開啟 HMCL 再試。
|
||||
exception.ssl_handshake=無法建立 SSL 連線。目前 Java 缺少相關的 SSL 證書。你可以嘗試使用其他 Java 或關閉網路代理開啟 HMCL 再試。
|
||||
|
||||
extension.bat=Windows 批次檔
|
||||
extension.mod=模組檔案
|
||||
@@ -380,9 +380,6 @@ fatal.mac_app_translocation=由於 macOS 的安全機制,Hello Minecraft! Laun
|
||||
fatal.migration_requires_manual_reboot=Hello Minecraft! Launcher 即將升級完成,請重新開啟 HMCL。
|
||||
fatal.apply_update_failure=我們很抱歉 Hello Minecraft! Launcher 無法自動完成升級程式,因為出現了一些問題。\n但你依然可以從 %s 處手動下載 HMCL 來完成升級。
|
||||
fatal.apply_update_need_win7=Hello Minecraft! Launcher 無法在 Windows XP/Vista 上進行自動更新。請從 %s 處手動下載 HMCL 來完成升級。
|
||||
fatal.deprecated_java_version=HMCL 未來需要 Java 11 或更高版本才能執行,但依然支援使用 Java 8 啟動遊戲。建議安裝最新版本的 Java 以確保 HMCL 正常執行。\n你可以繼續保留舊版本 Java。HMCL 能夠識別與管理多個 Java,並會自動根據遊戲版本為你選取合適的 Java。
|
||||
fatal.deprecated_java_version.update=更高版本的 HMCL 需要 Java 11 或更高版本才能執行,請安裝最新版本的 Java 以確保 HMCL 能夠完成升級。\n你可以繼續保留舊版本 Java。HMCL 能夠識別與管理多個 Java,並會自動根據遊戲版本為你選取合適的 Java。
|
||||
fatal.deprecated_java_version.download_link=下載 Java %d
|
||||
fatal.samba=如果您正在透過 Samba 共亯的目錄中開啟 Hello Minecraft! Launcher,啟動器可能無法正常工作,請嘗試更新您的 Java 或在本機目錄內開啟 HMCL。
|
||||
fatal.illegal_char=由於您的使用者目錄路徑中存在無效字元『=』,您將無法使用外部登入帳戶以及離線登入更換外觀功能。
|
||||
fatal.unsupported_platform=Minecraft 尚未你您的平臺提供完善支援,所以可能影響遊戲體驗或無法啟動遊戲。\n若無法啟動 Minecraft 1.17 及更高版本,可以嘗試在「(全域/實例特定) 遊戲設定 → 進階設定 → 除錯選項」中將「繪製器」切換為「軟繪製器」,以獲得更好的相容性。
|
||||
@@ -431,7 +428,7 @@ game.crash.reason.modmixin_failure=目前遊戲由於某些模組注入失敗,
|
||||
game.crash.reason.mod_repeat_installation=目前遊戲由於重複安裝了多個相同的模組,無法繼續執行。\n每個模組只能出現一次,請刪除重複的模組,然後再啟動遊戲。
|
||||
game.crash.reason.forge_error=Forge/NeoForge 可能已經提供了錯誤資訊。\n你可以查看日誌,並根據錯誤報告中的日誌資訊進行對應處。\n如果沒有看到報錯資訊,可以查看錯誤報告了解錯誤具體是如何發生的。\n%1$s
|
||||
game.crash.reason.mod_resolution0=目前遊戲由於一些模組出現問題,無法繼續執行。\n你可以查看日誌尋找出錯模組。
|
||||
game.crash.reason.need_jdk11=目前遊戲由於 Java 虛擬機版本不合適,無法繼續執行。\n你需要下載安裝 Java 11,並在「(全域/實例特定) 遊戲設定 → 遊戲 Java」中將 Java 設定為 11.x 的版本。
|
||||
game.crash.reason.need_jdk11=目前遊戲由於 Java 版本不合適,無法繼續執行。\n你需要下載安裝 Java 11,並在「(全域/實例特定) 遊戲設定 → 遊戲 Java」中將 Java 設定為 11.x 的版本。
|
||||
game.crash.reason.java_version_is_too_high=目前遊戲由於使用的 Java 版本過高而崩潰了,無法繼續執行。\n請在「(全域/實例特定) 遊戲設定 → 遊戲 Java」中改用較低版本的 Java,然後再啟動遊戲。\n如果沒有,可以從 <a href="https://www.java.com/download/">java.com (Java 8)</a> 或 <a href="https://bell-sw.com/pages/downloads/#downloads">BellSoft Liberica Full JRE (Java 17)</a> 等平台下載、安裝一個 (安裝完後需重啟啟動器)。
|
||||
game.crash.reason.mod_name=目前遊戲由於模組檔案名稱問題,無法繼續執行。\n模組檔案名稱應只使用半型的大小寫字母 (Aa~Zz)、數位 (0~9)、橫線 (-)、底線 (_)和點 (.)。\n請到模組目錄中將所有不合規的模組檔案名稱修正為上述合規字元。
|
||||
game.crash.reason.incomplete_forge_installation=目前遊戲由於 Forge 安裝不完整,無法繼續執行。\n請在「實例管理 - 自動安裝」中移除 Forge 並重新安裝。
|
||||
@@ -445,7 +442,7 @@ game.crash.reason.macos_failed_to_find_service_port_for_display=目前遊戲由
|
||||
game.crash.reason.illegal_access_error=目前遊戲由於某些模組的問題,無法繼續執行。\n如果你認識「%1$s」,你可以更新或刪除對應模組再試。
|
||||
game.crash.reason.install_mixinbootstrap=目前遊戲由於缺失 MixinBootstrap,無法繼續執行。\n你可以嘗試安裝 <a href="https://www.curseforge.com/minecraft/mc-mods/mixinbootstrap">MixinBootstrap</a> 解決該問題。若安裝後崩潰,可以嘗試在該模組的檔案名前新增半形驚嘆號 (!) 解決。
|
||||
game.crash.reason.jdk_9=目前遊戲由於 Java 版本過高,無法繼續執行。\n你需要下載安裝 Java 8,並在「(全域/實例特定) 遊戲設定 → 遊戲 Java」中將 Java 設定為 1.8.x 的版本。
|
||||
game.crash.reason.jvm_32bit=目前遊戲由於記憶體分配過大,超過了 32 位 Java 記憶體限制,無法繼續執行。\n如果你的電腦是 64 位系統,請下載安裝並更換 64 位 Java。\n如果你的電腦是 32 位系統,你或許可以重新安裝 64 位系統,或換一台新電腦。\n或者,你可以關閉「(全域/實例特定) 遊戲設定 → 遊戲記憶體」中的「自動分配」,並且把記憶體分配值調節為 1024 MiB 或以下。
|
||||
game.crash.reason.jvm_32bit=目前遊戲由於記憶體分配過大,超過了 32 位 Java 虛擬機記憶體限制,無法繼續執行。\n如果你的電腦是 64 位系統,請下載安裝並更換 64 位 Java。\n如果你的電腦是 32 位系統,你或許可以重新安裝 64 位系統,或換一台新電腦。\n或者,你可以關閉「(全域/實例特定) 遊戲設定 → 遊戲記憶體」中的「自動分配」,並且把記憶體分配值調節為 1024 MiB 或以下。
|
||||
game.crash.reason.loading_crashed_forge=目前遊戲由於模組「%1$s (%2$s)」錯誤,無法繼續執行。\n你可以嘗試刪除或更新該模組以解決問題。
|
||||
game.crash.reason.loading_crashed_fabric=目前遊戲由於模組「%1$s」錯誤,無法繼續執行。\n你可以嘗試刪除或更新該模組以解決問題。
|
||||
game.crash.reason.mac_jdk_8u261=目前遊戲由於你所使用的 Forge 或 OptiFine 與 Java 衝突而崩潰。\n請嘗試更新 Forge 和 OptiFine,或使用 Java 8u251 及更早版本啟動。
|
||||
@@ -473,11 +470,11 @@ game.crash.reason.rtss_forest_sodium=目前遊戲由於 RivaTuner Statistics Ser
|
||||
game.crash.reason.no_class_def_found_error=目前遊戲由於程式碼不完整,無法繼續執行。\n你的遊戲可能缺失了某個模組,或者某些模組檔案不完整,或者模組與遊戲的版本不匹配。\n你可能需要重新安裝遊戲和模組,或請求他人幫助。\n缺失:%1$s
|
||||
game.crash.reason.no_such_method_error=目前遊戲由於程式碼不完整,無法繼續執行。\n你的遊戲可能缺失了某個模組,或者某些模組檔案不完整,或者模組與遊戲的版本不匹配。\n你可能需要重新安裝遊戲和模組,或請求他人幫助。
|
||||
game.crash.reason.opengl_not_supported=目前遊戲由於你的顯示卡驅動存在問題,無法繼續執行。\n原因是 OpenGL 不受支援,你現在是否在遠端桌面或者串流模式下?如果是,請直接使用原電腦啟動遊戲。\n或者嘗試升級你的顯示卡驅動到最新版本後再嘗試啟動遊戲。如果你的電腦同時存在獨立顯示卡與整合式顯示卡,你需要檢查遊戲是否使用整合式顯示卡啟動。如果是,請嘗試使用獨立顯示卡開啟 HMCL 與遊戲。如果仍有問題,你可能需要考慮換一個新顯示卡或新電腦。
|
||||
game.crash.reason.openj9=目前遊戲無法執行在 OpenJ9 虛擬機上。請你在「(全域/實例特定) 遊戲設定 → 遊戲 Java」中更換 Hotspot Java 虛擬機,並重新啟動遊戲。如果沒有下載安裝,你可以在網路上自行下載。
|
||||
game.crash.reason.openj9=目前遊戲無法執行在 OpenJ9 虛擬機上。請你在「(全域/實例特定) 遊戲設定 → 遊戲 Java」中更換為使用 Hotspot 虛擬機的 Java,並重新啟動遊戲。如果沒有下載安裝,你可以在網路上自行下載。
|
||||
game.crash.reason.out_of_memory=目前遊戲由於記憶體不足,無法繼續執行。\n這可能是記憶體分配過小,或者模組數量過多導致的。\n你可以在「(全域/實例特定) 遊戲設定 → 遊戲記憶體」中調整遊戲記憶體分配值以允許遊戲在更大的記憶體下執行。\n如果仍然出現該錯誤,你可能需要換一台更好的電腦。
|
||||
game.crash.reason.resolution_too_high=目前遊戲由於資源包/紋理包解析度過高,無法繼續執行。\n你可以更換一個解析度更低的資源包/紋理包,或者更換一個視訊記憶體更大的顯示卡。
|
||||
game.crash.reason.stacktrace=原因未知。請點擊日誌按鈕查看詳細訊息。\n下面是一些關鍵字,其中可能包含模組名稱,你可以透過搜尋的方式尋找有關訊息。\n%s
|
||||
game.crash.reason.too_old_java=目前遊戲由於 Java 虛擬機版本過低,無法繼續執行。\n你需要在「(全域/實例特定) 遊戲設定 → 遊戲 Java」中更換 %1$s 或更高版本的 Java 虛擬機,並重新啟動遊戲。如果沒有下載安裝,你可以點擊 <a href="https://learn.microsoft.com/java/openjdk/download">此處</a> 下載 Microsoft JDK。
|
||||
game.crash.reason.too_old_java=目前遊戲由於 Java 版本過低,無法繼續執行。\n你需要在「(全域/實例特定) 遊戲設定 → 遊戲 Java」中更換 %1$s 或更高版本的 Java,並重新啟動遊戲。如果沒有下載安裝,你可以點擊 <a href="https://learn.microsoft.com/java/openjdk/download">此處</a> 下載 Microsoft JDK。
|
||||
game.crash.reason.unknown=原因未知。請點擊日誌按鈕查看詳細訊息。
|
||||
game.crash.reason.unsatisfied_link_error=目前遊戲由於缺少本機庫,無法繼續執行。\n這些本機庫缺失:%1$s。\n如果你在「(全域/實例特定) 遊戲設定 → 進階設定」中修改了本機庫路徑選項,請你修改回預設模式。\n如果你正在使用預設模式,請檢查遊戲目錄路徑是否只包含英文字母、數字和底線。\n如果是,那麼請檢查是否為模組或 HMCL 導致了本機庫缺失的問題。如果你確定是 HMCL 引起的,建議你向我們回報。\n<b>對於 Windows 使用者,你還可以嘗試在「控制台 → 時鐘和區域 → 地區 → 系統管理 → 變更系統區域設定」中,關閉「Beta:使用 Unicode UTF-8 提供全球語言支援」選項;</b>\n<b>或將遊戲目錄路徑中的所有非英文字母的名稱 (例如中文、空格等) 修改為英文字母。</b>\n如果你確實需要自訂本機庫路徑,你需要保證其中包含缺失的本機庫!
|
||||
game.crash.title=遊戲意外退出
|
||||
@@ -578,10 +575,10 @@ lang.default=使用系統語言
|
||||
|
||||
launch.advice=%s 是否繼續啟動?
|
||||
launch.advice.multi=檢測到以下問題:\n\n%s\n\n這些問題可能導致遊戲無法正常啟動或影響遊戲體驗,是否繼續啟動?
|
||||
launch.advice.java.auto=目前選取的 Java 虛擬機版本不滿足遊戲要求,是否自動選取合適的 Java 虛擬機版本?\n或者你可以到「(全域/實例特定) 遊戲設定 → 遊戲 Java」中選取一個合適的 Java 虛擬機版本。
|
||||
launch.advice.java.auto=目前選取的 Java 版本不滿足遊戲要求,是否自動選取合適的 Java 版本?\n或者你可以到「(全域/實例特定) 遊戲設定 → 遊戲 Java」中選取一個合適的 Java 版本。
|
||||
launch.advice.java.modded_java_7=Minecraft 1.7.2 及更低版本需要 Java 7 及更低版本。
|
||||
launch.advice.corrected=我們已經修正了問題。如果你確實希望使用你自訂的 Java 虛擬機,你可以在「(全域/實例特定) 遊戲設定 → 進階設定」中往下滑,開啟「不檢查 JVM 與遊戲的相容性」。
|
||||
launch.advice.uncorrected=如果你確實希望使用你自訂的 Java 虛擬機,你可以在「(全域/實例特定) 遊戲設定 → 進階設定」中往下滑,開啟「不檢查 JVM 與遊戲的相容性」。
|
||||
launch.advice.corrected=我們已經修正了 Java 版本問題。如果你確實希望使用你自訂的 Java,你可以在「(全域/實例特定) 遊戲設定 → 進階設定」中往下滑,開啟「不檢查 Java 虛擬機與遊戲的相容性」。
|
||||
launch.advice.uncorrected=如果你確實希望使用你自訂的 Java,你可以在「(全域/實例特定) 遊戲設定 → 進階設定」中往下滑,開啟「不檢查 Java 虛擬機與遊戲的相容性」。
|
||||
launch.advice.different_platform=你正在使用 32 位元 Java 啟動遊戲。建議更換至 64 位元 Java。
|
||||
launch.advice.forge2760_liteloader=Forge 14.23.5.2760 與 LiteLoader 不相容。請更新 Forge 至 14.23.5.2773 或更高版本。
|
||||
launch.advice.forge28_2_2_optifine=Forge 28.2.2 及更高版本與 OptiFine 不相容,請降級 Forge 至 28.2.1 或更低版本。
|
||||
@@ -599,7 +596,7 @@ launch.advice.vanilla_linux_java_8=對於 Linux x86-64 平台,Minecraft 1.12.2
|
||||
launch.advice.vanilla_x86.translation=Minecraft 尚未為你的平臺提供完善支援,所以可能影響遊戲體驗或無法啟動遊戲。\n你可以在 <a href="https://learn.microsoft.com/java/openjdk/download">這裡</a> 下載 <b>x86-64</b> 架構的 Java 以獲得更完整的體驗。\n是否繼續啟動?
|
||||
launch.advice.unknown=由於以下原因,無法繼續啟動遊戲:
|
||||
launch.failed=啟動失敗
|
||||
launch.failed.cannot_create_jvm=無法建立 Java 虛擬機,可能是 Java 參數有問題。可以在「(全域/實例特定) 遊戲設定 → 進階設定 → Java 虛擬機設定」中移除所有 Java 虛擬機參數後,嘗試再次啟動遊戲。
|
||||
launch.failed.cannot_create_jvm=無法建立 Java 虛擬機。可能是虛擬機參數有問題。可以在「(全域/實例特定) 遊戲設定 → 進階設定 → Java 虛擬機設定」中移除所有虛擬機參數後,嘗試再次啟動遊戲。
|
||||
launch.failed.creating_process=啟動失敗,在建立新處理程式時發生錯誤。可能是 Java 路徑錯誤。
|
||||
launch.failed.command_too_long=指令長度超過限制,無法建立批次檔指令碼,請匯出為 PowerShell 指令碼。
|
||||
launch.failed.decompressing_natives=無法解壓縮遊戲本機庫。
|
||||
@@ -610,7 +607,7 @@ launch.failed.execution_policy.failed_to_set=設定執行策略失敗
|
||||
launch.failed.execution_policy.hint=目前執行策略封鎖你執行 PowerShell 指令碼。\n點擊「確定」允許目前使用者執行本機 PowerShell 指令碼,或點擊「取消」保持現狀。
|
||||
launch.failed.exited_abnormally=遊戲非正常退出。請查看日誌檔案,或聯絡他人尋求幫助。
|
||||
launch.failed.java_version_too_low=你所指定的 Java 版本過低。請重新設定 Java 版本。
|
||||
launch.failed.no_accepted_java=找不到適合目前遊戲使用的 Java。是否使用預設 Java 啟動遊戲?點擊「是」使用預設 Java 繼續啟動遊戲,\n或者請到「(全域/實例特定) 遊戲設定 → 遊戲 Java」中選取一個合適的 Java 虛擬機版本。
|
||||
launch.failed.no_accepted_java=找不到適合目前遊戲使用的 Java。是否使用預設 Java 啟動遊戲?點擊「是」使用預設 Java 繼續啟動遊戲,\n或者請到「(全域/實例特定) 遊戲設定 → 遊戲 Java」中選取一個合適的 Java 版本。
|
||||
launch.failed.sigkill=遊戲被使用者或系統強制終止。
|
||||
launch.state.dependencies=處理遊戲相依元件
|
||||
launch.state.done=啟動完成
|
||||
@@ -1045,7 +1042,7 @@ settings.advanced.jvm=Java 虛擬機設定
|
||||
settings.advanced.jvm_args=Java 虛擬機參數
|
||||
settings.advanced.jvm_args.prompt=\ · 若在「Java 虛擬機參數」中輸入的參數與預設參數相同,則不會新增;\n\
|
||||
\ · 若在「Java 虛擬機參數」輸入任何 GC 參數,預設參數的 G1 參數會被禁用;\n\
|
||||
\ · 啟用下方「不新增預設的 JVM 參數」可在啟動遊戲時不新增預設參數。
|
||||
\ · 啟用下方「不新增預設的 Java 虛擬機參數」可在啟動遊戲時不新增預設參數。
|
||||
settings.advanced.launcher_visibility.close=遊戲啟動後結束啟動器
|
||||
settings.advanced.launcher_visibility.hide=遊戲啟動後隱藏啟動器
|
||||
settings.advanced.launcher_visibility.hide_and_reopen=隱藏啟動器並在遊戲結束後重新開啟
|
||||
@@ -1121,6 +1118,10 @@ settings.launcher.download_source=下載來源
|
||||
settings.launcher.download_source.auto=自動選取下載來源
|
||||
settings.launcher.enable_game_list=在首頁內顯示遊戲清單
|
||||
settings.launcher.font=字體
|
||||
settings.launcher.font.anti_aliasing=抗鋸齒 (重啟後生效)
|
||||
settings.launcher.font.anti_aliasing.auto=自動
|
||||
settings.launcher.font.anti_aliasing.gray=灰度
|
||||
settings.launcher.font.anti_aliasing.lcd=子像素
|
||||
settings.launcher.general=一般
|
||||
settings.launcher.language=語言 (重啟後生效)
|
||||
settings.launcher.launcher_log.export=匯出啟動器日誌
|
||||
@@ -1229,7 +1230,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=刪除所有遊戲資源檔案
|
||||
|
||||
@@ -369,7 +369,7 @@ exception.access_denied=无法访问文件“%s”。HMCL 没有对该文件的
|
||||
对于 Windows 用户,你还可以尝试通过资源监视器查看是否有程序占用了该文件。如果是,请关闭占用该文件的程序,或者重启电脑再试。\n\
|
||||
如遇到问题,你可以点击右上角帮助按钮进行求助。
|
||||
exception.artifact_malformed=下载的文件无法通过校验。\n你可以点击右上角帮助按钮进行求助。
|
||||
exception.ssl_handshake=无法建立 SSL 连接。当前 Java 虚拟机缺少相关的 SSL 证书。你可以尝试使用其他 Java 虚拟机启动 HMCL 再试。\n你可以点击右上角帮助按钮进行求助。
|
||||
exception.ssl_handshake=无法建立 SSL 连接。当前 Java 缺少相关的 SSL 证书。你可以尝试使用其他 Java 启动 HMCL 再试。\n你可以点击右上角帮助按钮进行求助。
|
||||
|
||||
extension.bat=Windows 脚本
|
||||
extension.mod=模组文件
|
||||
@@ -389,9 +389,6 @@ fatal.mac_app_translocation=由于 macOS 的安全机制,Hello Minecraft! Laun
|
||||
fatal.migration_requires_manual_reboot=Hello Minecraft! Launcher 即将完成升级,请重新打开 HMCL。\n如遇到问题,你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。
|
||||
fatal.apply_update_failure=我们很抱歉 Hello Minecraft! Launcher 无法自动完成升级,因为出现了一些问题。\n但你依可以从 %s 手动下载 HMCL 来完成升级。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。
|
||||
fatal.apply_update_need_win7=Hello Minecraft! Launcher 无法在 Windows XP/Vista 上进行自动更新。请从 %s 手动下载 HMCL 来完成升级。
|
||||
fatal.deprecated_java_version=HMCL 未来需要 Java 11 或更高版本才能运行,但依然支持使用 Java 8 启动游戏。建议安装最新版本的 Java 以确保 HMCL 能正常工作。\n你可以继续保留旧版本 Java。HMCL 能够识别与管理多个 Java,并会自动根据游戏版本为你选择合适的 Java。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。
|
||||
fatal.deprecated_java_version.update=更高版本的 HMCL 需要 Java 11 或更高版本才能运行,请安装最新版本的 Java 以确保 HMCL 能够完成升级。\n你可以继续保留旧版本 Java。HMCL 能够识别与管理多个 Java,并会自动根据游戏版本为你选择合适的 Java。
|
||||
fatal.deprecated_java_version.download_link=下载 Java %d
|
||||
fatal.samba=如果你正在通过 Samba 共享的文件夹中运行 Hello Minecraft! Launcher,启动器可能无法正常工作。请尝试更新你的 Java 或在本地文件夹内运行 HMCL。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。
|
||||
fatal.illegal_char=由于你的用户文件夹路径中存在非法字符“=”,你将无法使用外置登录账户以及离线登录更换皮肤功能。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。
|
||||
fatal.unsupported_platform=Minecraft 尚未对你的平台提供完善支持,所以可能影响游戏体验或无法启动游戏。\n若无法启动 Minecraft 1.17 及更高版本,可以尝试在“(全局/版本特定) 游戏设置 → 高级设置 → 调试选项”中将“渲染器”切换为“软渲染器”,以获得更好的兼容性。\n如遇到问题,你可以点击右上角帮助按钮进行求助。
|
||||
@@ -447,9 +444,9 @@ game.crash.reason.graphics_driver=当前游戏由于显卡驱动问题而崩溃
|
||||
game.crash.reason.macos_failed_to_find_service_port_for_display=当前游戏由于 Apple Silicon 平台下初始化 OpenGL 窗口失败,无法继续运行。\n对于该问题,HMCL 暂无直接性的解决方案。请你尝试任意打开一个浏览器并全屏,然后再回到 HMCL 启动游戏。在弹出游戏窗口前<b>迅速切回浏览器页面</b>,等待游戏窗口出现后再切回游戏窗口。
|
||||
game.crash.reason.illegal_access_error=当前游戏由于某些模组的问题,无法继续运行。\n如果你认识“%1$s”,你可以更新或删除对应模组再试。
|
||||
game.crash.reason.install_mixinbootstrap=当前游戏由于缺失 MixinBootstrap,无法继续运行。\n你可以尝试安装 <a href="https://www.curseforge.com/minecraft/mc-mods/mixinbootstrap">MixinBootstrap</a> 解决该问题。若安装后崩溃,可以尝试在该模组的文件名开头添加半角感叹号 (!) 解决。
|
||||
game.crash.reason.need_jdk11=当前游戏由于 Java 虚拟机版本不合适,无法继续运行。\n你需要下载安装 <a href="https://bell-sw.com/pages/downloads/#downloads">Java 11</a>,并在“(全局/版本特定) 游戏设置 → 游戏 Java”中将 Java 设置为 11.x 的版本。
|
||||
game.crash.reason.need_jdk11=当前游戏由于 Java 版本不合适,无法继续运行。\n你需要下载安装 <a href="https://bell-sw.com/pages/downloads/#downloads">Java 11</a>,并在“(全局/版本特定) 游戏设置 → 游戏 Java”中将 Java 设置为 11.x 的版本。
|
||||
game.crash.reason.jdk_9=当前游戏由于 Java 版本过高,无法继续运行。\n你需要下载安装 <a href="https://bell-sw.com/pages/downloads/#downloads">Java 8</a>,并在“(全局/版本特定) 游戏设置 → 游戏 Java”中将 Java 设置为 1.8.x 的版本。
|
||||
game.crash.reason.jvm_32bit=当前游戏由于内存分配过大,超过了 32 位 Java 内存限制,无法继续运行。\n如果你的电脑是 64 位系统,请下载安装并更换 64 位 Java。<a href="https://bell-sw.com/pages/downloads/#downloads">下载 Java</a>\n如果你的电脑是 32 位系统,你或许可以重新安装 64 位系统,或换一台新电脑。\n或者,你可以在“(全局/版本特定) 游戏设置 → 游戏内存”中关闭“自动分配内存”,并把内存分配值调整为 1024 MiB 或以下。
|
||||
game.crash.reason.jvm_32bit=当前游戏由于内存分配过大,超过了 32 位 Java 虚拟机内存限制,无法继续运行。\n如果你的电脑是 64 位系统,请下载安装并更换 64 位 Java。<a href="https://bell-sw.com/pages/downloads/#downloads">下载 Java</a>\n如果你的电脑是 32 位系统,你或许可以重新安装 64 位系统,或换一台新电脑。\n或者,你可以在“(全局/版本特定) 游戏设置 → 游戏内存”中关闭“自动分配内存”,并把内存分配值调整为 1024 MiB 或以下。
|
||||
game.crash.reason.loading_crashed_forge=当前游戏由于模组“%1$s (%2$s)”错误,无法继续运行。\n你可以尝试删除或更新该模组以解决问题。
|
||||
game.crash.reason.loading_crashed_fabric=当前游戏由于模组“%1$s”错误,无法继续运行。\n你可以尝试删除或更新该模组以解决问题。
|
||||
game.crash.reason.memory_exceeded=当前游戏由于内存分配过大,无法继续运行。\n该问题是由于系统页面文件太小导致的。\n你需要在“(全局/版本特定) 游戏设置”中关闭“自动分配内存”,并将内存分配值调低至游戏能正常启动为止。\n你还可以尝试将虚拟内存设置调整为“自动管理所有驱动器分页文件大小”,<a href="https://docs.hmcl.net/assets/img/hmcl/自动管理所有驱动器分页文件大小.webp">详情</a>。
|
||||
@@ -470,7 +467,7 @@ game.crash.reason.modmixin_failure=当前游戏由于某些模组注入失败,
|
||||
game.crash.reason.night_config_fixes=当前游戏由于 Night Config 库的一些问题,无法继续运行。\n你可以尝试安装 <a href="https://www.curseforge.com/minecraft/mc-mods/night-config-fixes">Night Config Fixes</a> 模组,这或许能帮助你解决这个问题。\n更多详情,可访问该模组的 <a href="https://github.com/Fuzss/nightconfigfixes">GitHub 仓库</a>。
|
||||
game.crash.reason.forge_error=Forge/NeoForge 可能已经提供了错误信息。\n你可以查看日志,并根据错误报告中的日志信息进行对应处理。\n如果没有看到报错信息,可以查看错误报告了解错误具体是如何发生的。\n%1$s
|
||||
game.crash.reason.mod_resolution0=当前游戏由于一些模组出现问题,无法继续运行。\n你可以查看日志寻找出错模组。
|
||||
game.crash.reason.java_version_is_too_high=当前游戏由于 Java 虚拟机版本过高,无法继续运行。\n请在“(全局/版本特定) 游戏设置 → 游戏 Java”中改用较低版本的 Java,然后再启动游戏。\n如果没有,可以从 <a href="https://www.java.com/download/">java.com (Java 8)</a> 或 <a href="https://bell-sw.com/pages/downloads/#downloads">BellSoft Liberica Full JRE (Java 17)</a> 等平台下载、安装一个 (安装完后需重启启动器)。
|
||||
game.crash.reason.java_version_is_too_high=当前游戏由于 Java 版本过高,无法继续运行。\n请在“(全局/版本特定) 游戏设置 → 游戏 Java”中改用较低版本的 Java,然后再启动游戏。\n如果没有,可以从 <a href="https://www.java.com/download/">java.com (Java 8)</a> 或 <a href="https://bell-sw.com/pages/downloads/#downloads">BellSoft Liberica Full JRE (Java 17)</a> 等平台下载、安装一个 (安装完后需重启启动器)。
|
||||
game.crash.reason.mod_name=当前游戏由于模组文件名称问题,无法继续运行。\n模组文件名称应只使用半角的大小写字母 (Aa~Zz)、数字 (0~9)、横线 (-)、下划线 (_)和点 (.)。\n请到模组文件夹中将所有不合规的模组文件名修改为上述合规字符。
|
||||
game.crash.reason.incomplete_forge_installation=当前游戏由于 Forge/NeoForge 安装不完整,无法继续运行。\n请在“版本管理 → 自动安装”中卸载 Forge 并重新安装。
|
||||
game.crash.reason.optifine_is_not_compatible_with_forge=当前游戏由于 OptiFine 与当前版本的 Forge 不兼容,导致游戏崩溃。\n点击 <a href="https://zkitefly.github.io/optifine-forge-support-list">此处</a> 查看 OptiFine 所兼容的 Forge 版本,并严格按照对应版本重新安装游戏或在“版本管理 → 自动安装”中更换版本。\n经测试,Forge 版本过高或过低都可能导致崩溃。
|
||||
@@ -483,11 +480,11 @@ game.crash.reason.modlauncher_8=当前游戏由于你所使用的 Forge 版本
|
||||
game.crash.reason.no_class_def_found_error=当前游戏由于代码不完整,无法继续运行。\n你的游戏可能缺失了某个模组,或者某些模组文件不完整,或者模组与游戏的版本不匹配。\n你可能需要重新安装游戏和模组,或寻求他人帮助。\n缺失:\n%1$s
|
||||
game.crash.reason.no_such_method_error=当前游戏由于代码不完整,无法继续运行。\n你的游戏可能缺失了某个模组,或者某些模组文件不完整,或者模组与游戏的版本不匹配。\n你可能需要重新安装游戏和模组,或寻求他人帮助。
|
||||
game.crash.reason.opengl_not_supported=当前游戏由于你的显卡驱动存在问题,无法继续运行。\n原因是 OpenGL 不受支持,你现在是否在远程桌面或者串流模式下?如果是,请直接使用原电脑启动游戏。\n或者尝试升级你的显卡驱动到最新版本后再尝试启动游戏。如果你的电脑同时存在独立显卡和集成显卡,你需要检查游戏是否使用集成显卡启动。如果是,请尝试使用独立显卡启动 HMCL 与游戏。如果仍有问题,你可能需要考虑换一个新显卡或新电脑。
|
||||
game.crash.reason.openj9=当前游戏无法在 OpenJ9 虚拟机上运行。请你在“(全局/版本特定) 游戏设置 → 游戏 Java”中更换 Hotspot Java 虚拟机,并重新启动游戏。如果没有下载安装,你可以在网上自行下载。
|
||||
game.crash.reason.openj9=当前游戏无法在 OpenJ9 虚拟机上运行。请你在“(全局/版本特定) 游戏设置 → 游戏 Java”中更换为使用 Hotspot 虚拟机的 Java,并重新启动游戏。如果没有下载安装,你可以在网上自行下载。
|
||||
game.crash.reason.out_of_memory=当前游戏由于内存不足,无法继续运行。\n这可能是内存分配过小,或者模组数量过多导致的。\n你可以在“(全局/版本特定) 游戏设置 → 游戏内存”中调整内存分配值以允许游戏在更大内存下运行。\n如果仍然出现该错误,你可能需要换一台更好的电脑。
|
||||
game.crash.reason.resolution_too_high=当前游戏由于资源包/纹理包分辨率过高,无法继续运行。\n你可以更换一个分辨率更低的资源包/纹理包,或者更换一个显存更大的显卡。
|
||||
game.crash.reason.stacktrace=原因未知。请点击日志按钮查看详细信息。\n下面是一些关键词,其中可能包含模组名称,你可以通过搜索的方式查找有关信息。\n%s
|
||||
game.crash.reason.too_old_java=当前游戏由于 Java 虚拟机版本过低,无法继续运行。\n你需要在“(全局/版本特定) 游戏设置 → 游戏 Java”中更换 Java %1$s 或更新版本的 Java 虚拟机,并重新启动游戏。如果没有下载安装,你可以点击 <a href="https://learn.microsoft.com/java/openjdk/download">此处</a> 下载 Microsoft JDK。
|
||||
game.crash.reason.too_old_java=当前游戏由于 Java 版本过低,无法继续运行。\n你需要在“(全局/版本特定) 游戏设置 → 游戏 Java”中更换 Java %1$s 或更新版本的 Java,并重新启动游戏。如果没有下载安装,你可以点击 <a href="https://learn.microsoft.com/java/openjdk/download">此处</a> 下载 Microsoft JDK。
|
||||
game.crash.reason.unknown=原因未知。请点击日志按钮查看详细信息。
|
||||
game.crash.reason.unsatisfied_link_error=当前游戏由于缺少本地库,无法继续运行。\n这些本地库缺失:%1$s。\n如果你在“(全局/版本特定) 游戏设置 → 高级设置”中修改了本地库路径选项,请你修改回默认模式。\n如果你正在使用默认模式,请检查游戏文件夹路径是否只包含英文字母、数字和下划线。\n如果是,那么请检查是否为模组或 HMCL 导致了本地库缺失的问题。如果你确定是 HMCL 引起的,建议你向我们反馈。\n<b>对于 Windows 用户,你还可以尝试在“控制面板 → 时钟和区域 → 区域 → 管理 → 更改系统区域设置”中将“当前系统区域设置”修改为“中文(简体,中国大陆)”,并关闭“Beta 版:使用 Unicode UTF-8 提供全球语言支持”选项;</b>\n<b>或将游戏文件夹路径中的所有非英文字符的名称 (例如中文、空格等) 修改为英文字符。</b>\n如果你确实需要自定义本地库路径,你需要保证其中包含缺失的本地库!
|
||||
game.crash.title=游戏意外退出
|
||||
@@ -588,10 +585,10 @@ lang.default=跟随系统语言
|
||||
|
||||
launch.advice=%s 是否继续启动?
|
||||
launch.advice.multi=检测到以下问题:\n\n%s\n\n这些问题可能导致游戏无法正常启动或影响游戏体验,是否继续启动?\n你可以点击右上角帮助按钮进行求助。
|
||||
launch.advice.java.auto=当前选择的 Java 虚拟机版本不满足游戏要求。\n点击“是”即可由 HMCL 来自动选取合适的 Java 虚拟机版本。\n或者你可以在“(全局/版本特定) 游戏设置 → 游戏 Java”中选择一个合适的 Java 虚拟机版本。
|
||||
launch.advice.java.auto=当前选择的 Java 版本不满足游戏要求。\n点击“是”即可由 HMCL 来自动选取合适的 Java 版本。\n或者你可以在“(全局/版本特定) 游戏设置 → 游戏 Java”中选择一个合适的 Java 版本。
|
||||
launch.advice.java.modded_java_7=Minecraft 1.7.2 及更低版本需要 Java 7 及更低版本。
|
||||
launch.advice.corrected=我们已经修复了 Java 虚拟机版本问题。如果你确实希望使用你自定义的 Java 虚拟机,你可以在“(全局/版本特定) 游戏设置 → 高级设置”中往下滑,启用“不检查 JVM 与游戏的兼容性”。
|
||||
launch.advice.uncorrected=如果你确实希望使用你自定义的 Java 虚拟机,你可以在“(全局/版本特定) 游戏设置 → 高级设置”中往下滑,启用“不检查 JVM 与游戏的兼容性”。
|
||||
launch.advice.corrected=我们已经修复了 Java 版本问题。如果你确实希望使用你自定义的 Java,你可以在“(全局/版本特定) 游戏设置 → 高级设置”中往下滑,启用“不检查 Java 虚拟机与游戏的兼容性”。
|
||||
launch.advice.uncorrected=如果你确实希望使用你自定义的 Java,你可以在“(全局/版本特定) 游戏设置 → 高级设置”中往下滑,启用“不检查 Java 虚拟机与游戏的兼容性”。
|
||||
launch.advice.different_platform=你正在使用 32 位 Java 启动游戏。建议更换至 64 位 Java。
|
||||
launch.advice.forge2760_liteloader=Forge 14.23.5.2760 与 LiteLoader 不兼容。请更新 Forge 至 14.23.5.2773 或更高版本。
|
||||
launch.advice.forge28_2_2_optifine=Forge 28.2.2 及更高版本与 OptiFine 不兼容。请降级 Forge 至 28.2.1 或更低版本。
|
||||
@@ -609,7 +606,7 @@ launch.advice.vanilla_linux_java_8=对于 Linux x86-64 平台,Minecraft 1.12.2
|
||||
launch.advice.vanilla_x86.translation=Minecraft 尚未为你的平台提供完善支持,所以可能影响游戏体验或无法启动游戏。\n你可以在 <a href="https://learn.microsoft.com/java/openjdk/download">这里</a> 下载 <b>x86-64</b> 架构的 Java 以获得更完整的体验。
|
||||
launch.advice.unknown=由于以下原因,无法继续启动游戏:
|
||||
launch.failed=启动失败
|
||||
launch.failed.cannot_create_jvm=无法创建 Java 虚拟机。可能是 Java 参数有问题,你可以在“(全局/版本特定) 游戏设置 → 高级设置 → Java 虚拟机设置”中移除所有 Java 虚拟机参数后,尝试再次启动游戏。
|
||||
launch.failed.cannot_create_jvm=无法创建 Java 虚拟机。可能是虚拟机参数有问题。你可以在“(全局/版本特定) 游戏设置 → 高级设置 → Java 虚拟机设置”中移除所有虚拟机参数后,尝试再次启动游戏。
|
||||
launch.failed.creating_process=启动失败。在创建新进程时发生错误,可能是 Java 路径错误。
|
||||
launch.failed.command_too_long=命令长度超过限制,无法创建批处理脚本。请导出为 PowerShell 脚本。
|
||||
launch.failed.decompressing_natives=未能解压游戏本地库。
|
||||
@@ -620,7 +617,7 @@ launch.failed.execution_policy.failed_to_set=设置执行策略失败
|
||||
launch.failed.execution_policy.hint=当前执行策略阻止你执行 PowerShell 脚本。\n点击“确定”允许当前用户执行本地 PowerShell 脚本,或点击“取消”保持现状。
|
||||
launch.failed.exited_abnormally=游戏非正常退出。请查看日志文件,或联系他人寻求帮助。
|
||||
launch.failed.java_version_too_low=你所指定的 Java 版本过低。请重新设置 Java 版本。
|
||||
launch.failed.no_accepted_java=找不到适合当前游戏使用的 Java。是否使用默认 Java 启动游戏?点击“是”使用默认 Java 继续启动游戏,\n或者在“(全局/版本特定) 游戏设置 → 游戏 Java”中选择一个合适的 Java 虚拟机版本。\n你可以点击右上角帮助按钮进行求助。
|
||||
launch.failed.no_accepted_java=找不到适合当前游戏使用的 Java。是否使用默认 Java 启动游戏?点击“是”使用默认 Java 继续启动游戏,\n或者在“(全局/版本特定) 游戏设置 → 游戏 Java”中选择一个合适的 Java 版本。\n你可以点击右上角帮助按钮进行求助。
|
||||
launch.failed.sigkill=游戏被用户或系统强制终止。
|
||||
launch.state.dependencies=处理游戏依赖
|
||||
launch.state.done=启动完成
|
||||
@@ -1055,7 +1052,7 @@ settings.advanced.jvm=Java 虚拟机设置
|
||||
settings.advanced.jvm_args=Java 虚拟机参数
|
||||
settings.advanced.jvm_args.prompt=\ · 若在“Java 虚拟机参数”输入的参数与默认参数相同,则不会添加;\n\
|
||||
\ · 若在“Java 虚拟机参数”输入任何 GC 参数,默认参数的 G1 参数会被禁用;\n\
|
||||
\ · 开启下方“不添加默认的 JVM 参数”可在启动游戏时不添加默认参数。
|
||||
\ · 开启下方“不添加默认的 Java 虚拟机参数”可在启动游戏时不添加默认参数。
|
||||
settings.advanced.launcher_visibility.close=游戏启动后结束启动器
|
||||
settings.advanced.launcher_visibility.hide=游戏启动后隐藏启动器
|
||||
settings.advanced.launcher_visibility.hide_and_reopen=隐藏启动器并在游戏结束后重新打开
|
||||
@@ -1131,6 +1128,10 @@ settings.launcher.download_source=下载源
|
||||
settings.launcher.download_source.auto=自动选择下载源
|
||||
settings.launcher.enable_game_list=在主页内显示版本列表
|
||||
settings.launcher.font=字体
|
||||
settings.launcher.font.anti_aliasing=抗锯齿 (重启后生效)
|
||||
settings.launcher.font.anti_aliasing.auto=自动
|
||||
settings.launcher.font.anti_aliasing.gray=灰度
|
||||
settings.launcher.font.anti_aliasing.lcd=子像素
|
||||
settings.launcher.general=通用
|
||||
settings.launcher.language=语言 (重启后生效)
|
||||
settings.launcher.launcher_log.export=导出启动器日志
|
||||
@@ -1239,7 +1240,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=删除所有游戏资源文件
|
||||
|
||||
Binary file not shown.
@@ -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) {
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.jackhuang.hmcl.game.LaunchOptions;
|
||||
import org.jackhuang.hmcl.java.JavaInfo;
|
||||
import org.jackhuang.hmcl.game.Log;
|
||||
import org.jackhuang.hmcl.launch.ProcessListener;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.java.JavaRuntime;
|
||||
import org.jackhuang.hmcl.util.platform.ManagedProcess;
|
||||
import org.jackhuang.hmcl.util.platform.Platform;
|
||||
@@ -31,6 +30,7 @@ import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
@@ -45,7 +45,7 @@ public class GameCrashWindowTest {
|
||||
|
||||
ManagedProcess process = new ManagedProcess(null, Arrays.asList("commands", "2"));
|
||||
|
||||
String logs = FileUtils.readText(new File("../HMCLCore/src/test/resources/logs/too_old_java.txt"));
|
||||
String logs = Files.readString(new File("../HMCLCore/src/test/resources/logs/too_old_java.txt").toPath());
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
FXUtils.runInFX(() -> {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
plugins {
|
||||
id("java-library")
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
options.release.set(8)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl;
|
||||
|
||||
import org.jackhuang.hmcl.util.UTF8Control;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
final class BootProperties {
|
||||
|
||||
private static ResourceBundle resourceBundle;
|
||||
|
||||
static ResourceBundle getResourceBundle() {
|
||||
if (resourceBundle == null) {
|
||||
resourceBundle = ResourceBundle.getBundle("assets.lang.boot", new UTF8Control());
|
||||
}
|
||||
|
||||
return resourceBundle;
|
||||
}
|
||||
|
||||
private BootProperties() {
|
||||
}
|
||||
}
|
||||
+6
-7
@@ -15,17 +15,16 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.util;
|
||||
package org.jackhuang.hmcl;
|
||||
|
||||
/**
|
||||
* @author Glavo
|
||||
* This is a dummy class and will be overwritten in the shadow jar.
|
||||
*/
|
||||
public final class ModuleHelper {
|
||||
|
||||
public static void addEnableNativeAccess(Class<?> clazzInModule) {
|
||||
// do nothing
|
||||
public final class EntryPoint {
|
||||
private EntryPoint() {
|
||||
}
|
||||
|
||||
private ModuleHelper() {
|
||||
public static void main(String[] args) {
|
||||
throw new AssertionError("This method should not be called, please verify that the HMCL is complete.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl;
|
||||
|
||||
import org.jackhuang.hmcl.util.SwingUtils;
|
||||
|
||||
/**
|
||||
* @author Glavo
|
||||
*/
|
||||
public final class Main {
|
||||
private static final int MINIMUM_JAVA_VERSION = 11;
|
||||
|
||||
private Main() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current Java version is compatible with HMCL.
|
||||
*/
|
||||
static boolean checkJavaVersion(String javaVersion) {
|
||||
if (javaVersion == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
int major;
|
||||
int dot = javaVersion.indexOf('.');
|
||||
|
||||
if (dot >= 0) {
|
||||
major = Integer.parseInt(javaVersion.substring(0, dot));
|
||||
if (major == 1 && dot < javaVersion.length() - 1) {
|
||||
int begin = dot + 1;
|
||||
dot = javaVersion.indexOf('.', begin);
|
||||
|
||||
major = dot > begin
|
||||
? Integer.parseInt(javaVersion.substring(begin, dot))
|
||||
: Integer.parseInt(javaVersion.substring(begin));
|
||||
}
|
||||
} else {
|
||||
major = Integer.parseInt(javaVersion);
|
||||
}
|
||||
|
||||
return major >= MINIMUM_JAVA_VERSION;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
if (checkJavaVersion(System.getProperty("java.version"))) {
|
||||
EntryPoint.main(args);
|
||||
} else {
|
||||
String errorMessage = BootProperties.getResourceBundle().getString("boot.unsupported_java_version");
|
||||
System.err.println(errorMessage);
|
||||
SwingUtils.showErrorDialog(errorMessage);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
-1
@@ -1,7 +1,27 @@
|
||||
package org.jackhuang.hmcl.ui;
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.util;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* @author Glavo
|
||||
*/
|
||||
public final class SwingUtils {
|
||||
static {
|
||||
if (System.getProperty("swing.defaultlaf") == null) {
|
||||
+4
-6
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> 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
|
||||
@@ -15,7 +15,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.i18n;
|
||||
package org.jackhuang.hmcl.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -28,11 +28,9 @@ import java.util.ResourceBundle;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
final class UTF8Control extends ResourceBundle.Control {
|
||||
public final class UTF8Control extends ResourceBundle.Control {
|
||||
|
||||
public static final UTF8Control INSTANCE = new UTF8Control();
|
||||
|
||||
private UTF8Control() {}
|
||||
public UTF8Control() {}
|
||||
|
||||
@Override
|
||||
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IOException {
|
||||
@@ -0,0 +1,19 @@
|
||||
#
|
||||
# Hello Minecraft! Launcher
|
||||
# Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
boot.unsupported_java_version=HMCL requires Java 11 or later to run, but still supports launching games with Java 8. Please install the latest version of Java and try opening HMCL again.\nYou can keep your old version of Java. HMCL can detect and manage multiple Java installations, and will automatically select the appropriate Java version for your game.
|
||||
@@ -0,0 +1,19 @@
|
||||
#
|
||||
# Hello Minecraft! Launcher
|
||||
# Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
boot.unsupported_java_version=HMCL 需要 Java 11 或更高版本才能執行,但依然支援使用 Java 8 啟動遊戲。請安裝最新版本的 Java 再嘗試開啟 HMCL。\n你可以繼續保留舊版本 Java。HMCL 能夠識別與管理多個 Java,並會自動根據遊戲版本為你選取合適的 Java。
|
||||
@@ -0,0 +1,19 @@
|
||||
#
|
||||
# Hello Minecraft! Launcher
|
||||
# Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
boot.unsupported_java_version=HMCL 需要 Java 11 或更高版本才能运行,但依然支持使用 Java 8 启动游戏。请安装最新版本的 Java 再尝试启动 HMCL。\n你可以继续保留旧版本 Java。HMCL 能够识别与管理多个 Java,并会自动根据游戏版本为你选择合适的 Java。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public final class MainTest {
|
||||
@Test
|
||||
public void testCheckJavaVersion() {
|
||||
assertFalse(Main.checkJavaVersion("1.6.0"));
|
||||
assertFalse(Main.checkJavaVersion("1.6.0_45"));
|
||||
assertFalse(Main.checkJavaVersion("1.7.0"));
|
||||
assertFalse(Main.checkJavaVersion("1.7.0_80"));
|
||||
assertFalse(Main.checkJavaVersion("1.8"));
|
||||
assertFalse(Main.checkJavaVersion("1.8.0_321"));
|
||||
|
||||
assertTrue(Main.checkJavaVersion("11"));
|
||||
assertTrue(Main.checkJavaVersion("11.0.26"));
|
||||
assertTrue(Main.checkJavaVersion("21"));
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,15 @@ plugins {
|
||||
`java-library`
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
sourceCompatibility = "11"
|
||||
targetCompatibility = "11"
|
||||
}
|
||||
|
||||
tasks.compileJava {
|
||||
options.compilerArgs.add("--add-exports=jdk.attach/sun.tools.attach=ALL-UNNAMED")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(libs.kala.compress.zip)
|
||||
api(libs.kala.compress.tar)
|
||||
|
||||
+2
-2
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth.authlibinjector;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static org.jackhuang.hmcl.util.Lang.tryCast;
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
@@ -32,7 +33,6 @@ import java.util.Optional;
|
||||
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilService;
|
||||
import org.jackhuang.hmcl.util.io.HttpRequest;
|
||||
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||
import org.jackhuang.hmcl.util.javafx.ObservableHelper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -77,7 +77,7 @@ public class AuthlibInjectorServer implements Observable {
|
||||
|
||||
try {
|
||||
AuthlibInjectorServer server = new AuthlibInjectorServer(url);
|
||||
server.refreshMetadata(IOUtils.readFullyAsStringWithClosing(conn.getInputStream()));
|
||||
server.refreshMetadata(new String(conn.getInputStream().readAllBytes(), UTF_8));
|
||||
return server;
|
||||
} finally {
|
||||
conn.disconnect();
|
||||
|
||||
@@ -79,7 +79,7 @@ public final class BMCLAPIDownloadProvider implements DownloadProvider {
|
||||
pair("https://maven.fabricmc.net", apiRoot + "/maven"),
|
||||
pair("https://authlib-injector.yushi.moe", apiRoot + "/mirrors/authlib-injector"),
|
||||
pair("https://repo1.maven.org/maven2", "https://mirrors.cloud.tencent.com/nexus/repository/maven-public"),
|
||||
pair("https://zkitefly.github.io/unlisted-versions-of-minecraft", "https://vip.123pan.cn/1821946486/unlisted-versions-of-minecraft")
|
||||
pair("https://zkitefly.github.io/unlisted-versions-of-minecraft", "https://alist.8mi.tech/d/mirror/unlisted-versions-of-minecraft/Auto")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,8 +63,9 @@ public class DefaultCacheRepository extends CacheRepository {
|
||||
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
if (Files.isRegularFile(indexFile))
|
||||
index = JsonUtils.fromNonNullJson(FileUtils.readText(indexFile), Index.class);
|
||||
if (Files.isRegularFile(indexFile)) {
|
||||
index = JsonUtils.fromNonNullJson(Files.readString(indexFile), Index.class);
|
||||
}
|
||||
else
|
||||
index = new Index();
|
||||
} catch (IOException | JsonParseException e) {
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -126,7 +125,7 @@ public final class ForgeInstallTask extends Task<Version> {
|
||||
Optional<String> gameVersion = dependencyManager.getGameRepository().getGameVersion(version);
|
||||
if (!gameVersion.isPresent()) throw new IOException();
|
||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(installer)) {
|
||||
String installProfileText = FileUtils.readText(fs.getPath("install_profile.json"));
|
||||
String installProfileText = Files.readString(fs.getPath("install_profile.json"));
|
||||
Map<?, ?> installProfile = JsonUtils.fromNonNullJson(installProfileText, Map.class);
|
||||
if (installProfile.containsKey("spec")) {
|
||||
ForgeNewInstallProfile profile = JsonUtils.fromNonNullJson(installProfileText, ForgeNewInstallProfile.class);
|
||||
@@ -159,7 +158,7 @@ public final class ForgeInstallTask extends Task<Version> {
|
||||
Optional<String> gameVersion = dependencyManager.getGameRepository().getGameVersion(version);
|
||||
if (!gameVersion.isPresent()) throw new IOException();
|
||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(installer)) {
|
||||
String installProfileText = FileUtils.readText(fs.getPath("install_profile.json"));
|
||||
String installProfileText = Files.readString(fs.getPath("install_profile.json"));
|
||||
Map<?, ?> installProfile = JsonUtils.fromNonNullJson(installProfileText, Map.class);
|
||||
if (installProfile.containsKey("spec")) {
|
||||
ForgeNewInstallProfile profile = JsonUtils.fromNonNullJson(installProfileText, ForgeNewInstallProfile.class);
|
||||
|
||||
@@ -278,9 +278,9 @@ public class ForgeNewInstallTask extends Task<Version> {
|
||||
@Override
|
||||
public void preExecute() throws Exception {
|
||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(installer)) {
|
||||
profile = JsonUtils.fromNonNullJson(FileUtils.readText(fs.getPath("install_profile.json")), ForgeNewInstallProfile.class);
|
||||
profile = JsonUtils.fromNonNullJson(Files.readString(fs.getPath("install_profile.json")), ForgeNewInstallProfile.class);
|
||||
processors = profile.getProcessors();
|
||||
forgeVersion = JsonUtils.fromNonNullJson(FileUtils.readText(fs.getPath(profile.getJson())), Version.class);
|
||||
forgeVersion = JsonUtils.fromNonNullJson(Files.readString(fs.getPath(profile.getJson())), Version.class);
|
||||
|
||||
for (Library library : profile.getLibraries()) {
|
||||
Path file = fs.getPath("maven").resolve(library.getPath());
|
||||
|
||||
@@ -25,7 +25,6 @@ import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Path;
|
||||
@@ -78,7 +77,7 @@ public class ForgeOldInstallTask extends Task<Version> {
|
||||
|
||||
ZipEntry forgeEntry = zipFile.getEntry(installProfile.getInstall().getFilePath());
|
||||
try (InputStream is = zipFile.getInputStream(forgeEntry); OutputStream os = new FileOutputStream(forgeFile)) {
|
||||
IOUtils.copyTo(is, os);
|
||||
is.transferTo(os);
|
||||
}
|
||||
|
||||
setResult(installProfile.getVersionInfo()
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.CacheRepository;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
@@ -84,7 +83,7 @@ public final class GameAssetDownloadTask extends Task<Void> {
|
||||
public void execute() throws Exception {
|
||||
AssetIndex index;
|
||||
try {
|
||||
index = JsonUtils.fromNonNullJson(FileUtils.readText(assetIndexFile), AssetIndex.class);
|
||||
index = JsonUtils.fromNonNullJson(Files.readString(assetIndexFile), AssetIndex.class);
|
||||
} catch (IOException | JsonParseException e) {
|
||||
throw new GameAssetIndexDownloadTask.GameAssetIndexMalformedException();
|
||||
}
|
||||
|
||||
+1
-2
@@ -27,7 +27,6 @@ import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.DigestUtils;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@@ -86,7 +85,7 @@ public final class GameAssetIndexDownloadTask extends Task<Void> {
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
JsonUtils.fromNonNullJson(FileUtils.readText(assetIndexFile), AssetIndex.class);
|
||||
JsonUtils.fromNonNullJson(Files.readString(assetIndexFile), AssetIndex.class);
|
||||
return;
|
||||
} catch (IOException | JsonParseException ignore) {
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.jackhuang.hmcl.game.ReleaseType;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
@@ -56,7 +57,12 @@ public final class GameRemoteVersion extends RemoteVersion {
|
||||
if (!(o instanceof GameRemoteVersion))
|
||||
return 0;
|
||||
|
||||
return o.getReleaseDate().compareTo(getReleaseDate());
|
||||
int dateCompare = o.getReleaseDate().compareTo(getReleaseDate());
|
||||
if (dateCompare != 0) {
|
||||
return dateCompare;
|
||||
}
|
||||
|
||||
return GameVersionNumber.compare(getSelfVersion(), o.getSelfVersion());
|
||||
}
|
||||
|
||||
private static Type getReleaseType(ReleaseType type) {
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.jackhuang.hmcl.task.FileDownloadTask.IntegrityCheck;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.DigestUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
@@ -164,7 +163,7 @@ public class LibraryDownloadTask extends Task<Void> {
|
||||
JarInputStream jar = new JarInputStream(new ByteArrayInputStream(data));
|
||||
JarEntry entry = jar.getNextJarEntry();
|
||||
while (entry != null) {
|
||||
byte[] eData = IOUtils.readFullyWithoutClosing(jar);
|
||||
byte[] eData = jar.readAllBytes();
|
||||
if (entry.getName().equals("checksums.sha1")) {
|
||||
hashes = new String(eData, StandardCharsets.UTF_8).split("\n");
|
||||
}
|
||||
|
||||
+1
-2
@@ -9,7 +9,6 @@ import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystem;
|
||||
@@ -87,7 +86,7 @@ public final class NeoForgeInstallTask extends Task<Version> {
|
||||
Optional<String> gameVersion = dependencyManager.getGameRepository().getGameVersion(version);
|
||||
if (!gameVersion.isPresent()) throw new IOException();
|
||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(installer)) {
|
||||
String installProfileText = FileUtils.readText(fs.getPath("install_profile.json"));
|
||||
String installProfileText = Files.readString(fs.getPath("install_profile.json"));
|
||||
Map<?, ?> installProfile = JsonUtils.fromNonNullJson(installProfileText, Map.class);
|
||||
if (LibraryAnalyzer.LibraryType.FORGE.getPatchId().equals(installProfile.get("profile")) && (Files.exists(fs.getPath("META-INF/NEOFORGE.RSA")) || installProfileText.contains("neoforge"))) {
|
||||
ForgeNewInstallProfile profile = JsonUtils.fromNonNullJson(installProfileText, ForgeNewInstallProfile.class);
|
||||
|
||||
+2
-2
@@ -274,9 +274,9 @@ public class NeoForgeOldInstallTask extends Task<Version> {
|
||||
@Override
|
||||
public void preExecute() throws Exception {
|
||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(installer)) {
|
||||
profile = JsonUtils.fromNonNullJson(FileUtils.readText(fs.getPath("install_profile.json")), ForgeNewInstallProfile.class);
|
||||
profile = JsonUtils.fromNonNullJson(Files.readString(fs.getPath("install_profile.json")), ForgeNewInstallProfile.class);
|
||||
processors = profile.getProcessors();
|
||||
neoForgeVersion = JsonUtils.fromNonNullJson(FileUtils.readText(fs.getPath(profile.getJson())), Version.class);
|
||||
neoForgeVersion = JsonUtils.fromNonNullJson(Files.readString(fs.getPath(profile.getJson())), Version.class);
|
||||
|
||||
for (Library library : profile.getLibraries()) {
|
||||
Path file = fs.getPath("maven").resolve(library.getPath());
|
||||
|
||||
+2
-2
@@ -175,7 +175,7 @@ public final class OptiFineInstallTask extends Task<Version> {
|
||||
|
||||
Path launchWrapperVersionText = fs.getPath("launchwrapper-of.txt");
|
||||
if (Files.exists(launchWrapperVersionText)) {
|
||||
String launchWrapperVersion = FileUtils.readText(launchWrapperVersionText).trim();
|
||||
String launchWrapperVersion = Files.readString(launchWrapperVersionText).trim();
|
||||
Path launchWrapperJar = fs.getPath("launchwrapper-of-" + launchWrapperVersion + ".jar");
|
||||
|
||||
Library launchWrapper = new Library(new Artifact("optifine", "launchwrapper-of", launchWrapperVersion));
|
||||
@@ -192,7 +192,7 @@ public final class OptiFineInstallTask extends Task<Version> {
|
||||
|
||||
Path buildofText = fs.getPath("buildof.txt");
|
||||
if (Files.exists(buildofText)) {
|
||||
String buildof = FileUtils.readText(buildofText).trim();
|
||||
String buildof = Files.readString(buildofText).trim();
|
||||
VersionNumber buildofVer = VersionNumber.asVersion(buildof);
|
||||
|
||||
if (LibraryAnalyzer.BOOTSTRAP_LAUNCHER_MAIN.equals(originalMainClass)) {
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
@@ -226,7 +226,7 @@ public final class CrashReportAnalyzer {
|
||||
public static String findCrashReport(String log) throws IOException, InvalidPathException {
|
||||
Matcher matcher = CRASH_REPORT_LOCATION_PATTERN.matcher(log);
|
||||
if (matcher.find()) {
|
||||
return FileUtils.readText(Paths.get(matcher.group("location")));
|
||||
return Files.readString(Paths.get(matcher.group("location")));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ public class DefaultGameRepository implements GameRepository {
|
||||
}
|
||||
|
||||
public Version readVersionJson(File file) throws IOException, JsonParseException {
|
||||
String jsonText = FileUtils.readText(file);
|
||||
String jsonText = Files.readString(file.toPath());
|
||||
try {
|
||||
// Try TLauncher version json format
|
||||
return JsonUtils.fromNonNullJson(jsonText, TLauncherVersion.class).toVersion();
|
||||
@@ -214,7 +214,7 @@ public class DefaultGameRepository implements GameRepository {
|
||||
|
||||
if (fromVersion.getId().equals(fromVersion.getJar()))
|
||||
fromVersion = fromVersion.setJar(null);
|
||||
FileUtils.writeText(toJson.toFile(), JsonUtils.GSON.toJson(fromVersion.setId(to)));
|
||||
FileUtils.writeText(toJson, JsonUtils.GSON.toJson(fromVersion.setId(to)));
|
||||
|
||||
// fix inheritsFrom of versions that inherits from version [from].
|
||||
for (Version version : getVersions()) {
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -384,7 +384,7 @@ public class DefaultGameRepository implements GameRepository {
|
||||
@Override
|
||||
public AssetIndex getAssetIndex(String version, String assetId) throws IOException {
|
||||
try {
|
||||
return Objects.requireNonNull(JsonUtils.GSON.fromJson(FileUtils.readText(getIndexFile(version, assetId)), AssetIndex.class));
|
||||
return Objects.requireNonNull(JsonUtils.GSON.fromJson(Files.readString(getIndexFile(version, assetId)), AssetIndex.class));
|
||||
} catch (JsonParseException | NullPointerException e) {
|
||||
throw new IOException("Asset index file malformed", e);
|
||||
}
|
||||
@@ -445,7 +445,7 @@ public class DefaultGameRepository implements GameRepository {
|
||||
if (!Files.isRegularFile(indexFile))
|
||||
return assetsDir;
|
||||
|
||||
String assetIndexContent = FileUtils.readText(indexFile);
|
||||
String assetIndexContent = Files.readString(indexFile);
|
||||
AssetIndex index = JsonUtils.GSON.fromJson(assetIndexContent, AssetIndex.class);
|
||||
|
||||
if (index == null)
|
||||
@@ -512,7 +512,7 @@ public class DefaultGameRepository implements GameRepository {
|
||||
if (!hasVersion(version)) throw new VersionNotFoundException(version);
|
||||
File file = getModpackConfiguration(version);
|
||||
if (!file.exists()) return null;
|
||||
return JsonUtils.GSON.fromJson(FileUtils.readText(file), ModpackConfiguration.class);
|
||||
return JsonUtils.GSON.fromJson(Files.readString(file.toPath()), ModpackConfiguration.class);
|
||||
}
|
||||
|
||||
public boolean isModpack(String version) {
|
||||
|
||||
@@ -25,7 +25,6 @@ import org.jackhuang.hmcl.util.ServerAddress;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.gson.UUIDTypeAdapter;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||
import org.jackhuang.hmcl.util.io.Unzipper;
|
||||
import org.jackhuang.hmcl.util.platform.Bits;
|
||||
import org.jackhuang.hmcl.util.platform.*;
|
||||
@@ -420,7 +419,7 @@ public class DefaultLauncher extends Launcher {
|
||||
}
|
||||
|
||||
try (InputStream input = source; OutputStream output = new FileOutputStream(targetFile)) {
|
||||
IOUtils.copyTo(input, output);
|
||||
input.transferTo(output);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ public class Datapack {
|
||||
} else if (Files.exists(mcmeta)) { // single datapack
|
||||
isMultiple = false;
|
||||
try {
|
||||
PackMcMeta pack = JsonUtils.fromNonNullJson(FileUtils.readText(mcmeta), PackMcMeta.class);
|
||||
PackMcMeta pack = JsonUtils.fromNonNullJson(Files.readString(mcmeta), PackMcMeta.class);
|
||||
Platform.runLater(() -> info.add(new Pack(path, FileUtils.getNameWithoutExtension(path), pack.getPackInfo().getDescription(), this)));
|
||||
} catch (IOException | JsonParseException e) {
|
||||
LOG.warning("Failed to read datapack " + path, e);
|
||||
@@ -165,8 +165,8 @@ public class Datapack {
|
||||
boolean enabled = Files.exists(mcmeta);
|
||||
|
||||
try {
|
||||
PackMcMeta pack = enabled ? JsonUtils.fromNonNullJson(FileUtils.readText(mcmeta), PackMcMeta.class)
|
||||
: JsonUtils.fromNonNullJson(FileUtils.readText(mcmetaDisabled), PackMcMeta.class);
|
||||
PackMcMeta pack = enabled ? JsonUtils.fromNonNullJson(Files.readString(mcmeta), PackMcMeta.class)
|
||||
: JsonUtils.fromNonNullJson(Files.readString(mcmetaDisabled), PackMcMeta.class);
|
||||
info.add(new Pack(enabled ? mcmeta : mcmetaDisabled, FileUtils.getName(subDir), pack.getPackInfo().getDescription(), this));
|
||||
} catch (IOException | JsonParseException e) {
|
||||
LOG.warning("Failed to read datapack " + subDir, e);
|
||||
@@ -186,7 +186,7 @@ public class Datapack {
|
||||
continue;
|
||||
name = StringUtils.substringBeforeLast(name, ".zip");
|
||||
|
||||
PackMcMeta pack = JsonUtils.fromNonNullJson(FileUtils.readText(mcmeta), PackMcMeta.class);
|
||||
PackMcMeta pack = JsonUtils.fromNonNullJson(Files.readString(mcmeta), PackMcMeta.class);
|
||||
info.add(new Pack(subDir, name, pack.getPackInfo().getDescription(), this));
|
||||
} catch (IOException | JsonParseException e) {
|
||||
LOG.warning("Failed to read datapack " + subDir, e);
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -87,7 +88,7 @@ public final class CurseCompletionTask extends Task<Void> {
|
||||
try {
|
||||
File manifestFile = new File(repository.getVersionRoot(version), "manifest.json");
|
||||
if (manifestFile.exists())
|
||||
this.manifest = JsonUtils.GSON.fromJson(FileUtils.readText(manifestFile), CurseManifest.class);
|
||||
this.manifest = JsonUtils.GSON.fromJson(Files.readString(manifestFile.toPath()), CurseManifest.class);
|
||||
} catch (Exception e) {
|
||||
LOG.warning("Unable to read CurseForge modpack manifest.json", e);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -98,7 +99,7 @@ public final class CurseInstallTask extends Task<Void> {
|
||||
ModpackConfiguration<CurseManifest> config = null;
|
||||
try {
|
||||
if (json.exists()) {
|
||||
config = JsonUtils.GSON.fromJson(FileUtils.readText(json), ModpackConfiguration.typeOf(CurseManifest.class));
|
||||
config = JsonUtils.GSON.fromJson(Files.readString(json.toPath()), 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.");
|
||||
|
||||
@@ -87,7 +87,7 @@ public class McbbsModpackCompletionTask extends CompletableFutureTask<Void> {
|
||||
if (configuration == null) {
|
||||
// Load configuration from disk
|
||||
try {
|
||||
configuration = JsonUtils.fromNonNullJson(FileUtils.readText(configurationFile), ModpackConfiguration.typeOf(McbbsModpackManifest.class));
|
||||
configuration = JsonUtils.fromNonNullJson(Files.readString(configurationFile.toPath()), ModpackConfiguration.typeOf(McbbsModpackManifest.class));
|
||||
} catch (IOException | JsonParseException e) {
|
||||
throw new IOException("Malformed modpack configuration");
|
||||
}
|
||||
|
||||
+2
-2
@@ -28,10 +28,10 @@ import org.jackhuang.hmcl.mod.ModpackConfiguration;
|
||||
import org.jackhuang.hmcl.mod.ModpackInstallTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -79,7 +79,7 @@ public class McbbsModpackLocalInstallTask extends Task<Void> {
|
||||
ModpackConfiguration<McbbsModpackManifest> config = null;
|
||||
try {
|
||||
if (json.exists()) {
|
||||
config = JsonUtils.GSON.fromJson(FileUtils.readText(json), ModpackConfiguration.typeOf(McbbsModpackManifest.class));
|
||||
config = JsonUtils.GSON.fromJson(Files.readString(json.toPath()), 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.");
|
||||
|
||||
+2
-2
@@ -24,10 +24,10 @@ import org.jackhuang.hmcl.game.DefaultGameRepository;
|
||||
import org.jackhuang.hmcl.mod.ModpackConfiguration;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -65,7 +65,7 @@ public class McbbsModpackRemoteInstallTask extends Task<Void> {
|
||||
ModpackConfiguration<McbbsModpackManifest> config = null;
|
||||
try {
|
||||
if (json.exists()) {
|
||||
config = JsonUtils.GSON.fromJson(FileUtils.readText(json), ModpackConfiguration.typeOf(McbbsModpackManifest.class));
|
||||
config = JsonUtils.GSON.fromJson(Files.readString(json.toPath()), ModpackConfiguration.typeOf(McbbsModpackManifest.class));
|
||||
|
||||
if (!MODPACK_TYPE.equals(config.getType()))
|
||||
throw new IllegalArgumentException("Version " + name + " is not a Mcbbs modpack. Cannot update this version.");
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.jackhuang.hmcl.mod.ModLoaderType;
|
||||
import org.jackhuang.hmcl.mod.ModManager;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
@@ -64,7 +63,7 @@ public final class FabricModMetadata {
|
||||
Path mcmod = fs.getPath("fabric.mod.json");
|
||||
if (Files.notExists(mcmod))
|
||||
throw new IOException("File " + modFile + " is not a Fabric mod.");
|
||||
FabricModMetadata metadata = JsonUtils.fromNonNullJson(FileUtils.readText(mcmod), FabricModMetadata.class);
|
||||
FabricModMetadata metadata = JsonUtils.fromNonNullJson(Files.readString(mcmod), FabricModMetadata.class);
|
||||
String authors = metadata.authors == null ? "" : metadata.authors.stream().map(author -> author.name).collect(Collectors.joining(", "));
|
||||
return new LocalModFile(modManager, modManager.getLocalMod(metadata.id, ModLoaderType.FABRIC), modFile, metadata.name, new LocalModFile.Description(metadata.description),
|
||||
authors, metadata.version, "", metadata.contact != null ? metadata.contact.getOrDefault("homepage", "") : "", metadata.icon);
|
||||
|
||||
@@ -6,7 +6,6 @@ import org.jackhuang.hmcl.mod.LocalModFile;
|
||||
import org.jackhuang.hmcl.mod.ModLoaderType;
|
||||
import org.jackhuang.hmcl.mod.ModManager;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -134,7 +133,7 @@ public final class ForgeNewModMetadata {
|
||||
Path modToml = fs.getPath(tomlPath);
|
||||
if (Files.notExists(modToml))
|
||||
throw new IOException("File " + modFile + " is not a Forge 1.13+ or NeoForge mod.");
|
||||
Toml toml = new Toml().read(FileUtils.readText(modToml));
|
||||
Toml toml = new Toml().read(Files.readString(modToml));
|
||||
ForgeNewModMetadata metadata = toml.to(ForgeNewModMetadata.class);
|
||||
if (metadata == null || metadata.getMods().isEmpty())
|
||||
throw new IOException("Mod " + modFile + " `mods.toml` is malformed..");
|
||||
|
||||
@@ -25,7 +25,6 @@ import org.jackhuang.hmcl.mod.ModManager;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystem;
|
||||
@@ -126,7 +125,7 @@ public final class ForgeOldModMetadata {
|
||||
Path mcmod = fs.getPath("mcmod.info");
|
||||
if (Files.notExists(mcmod))
|
||||
throw new IOException("File " + modFile + " is not a Forge mod.");
|
||||
List<ForgeOldModMetadata> modList = JsonUtils.GSON.fromJson(FileUtils.readText(mcmod), listTypeOf(ForgeOldModMetadata.class));
|
||||
List<ForgeOldModMetadata> modList = JsonUtils.GSON.fromJson(Files.readString(mcmod), listTypeOf(ForgeOldModMetadata.class));
|
||||
if (modList == null || modList.isEmpty())
|
||||
throw new IOException("Mod " + modFile + " `mcmod.info` is malformed..");
|
||||
ForgeOldModMetadata metadata = modList.get(0);
|
||||
|
||||
@@ -148,7 +148,7 @@ public class PackMcMeta implements Validation {
|
||||
Path mcmod = fs.getPath("pack.mcmeta");
|
||||
if (Files.notExists(mcmod))
|
||||
throw new IOException("File " + modFile + " is not a resource pack.");
|
||||
PackMcMeta metadata = JsonUtils.fromNonNullJson(FileUtils.readText(mcmod), PackMcMeta.class);
|
||||
PackMcMeta metadata = JsonUtils.fromNonNullJson(Files.readString(mcmod), PackMcMeta.class);
|
||||
return new LocalModFile(
|
||||
modManager,
|
||||
modManager.getLocalMod(FileUtils.getNameWithoutExtension(modFile), ModLoaderType.PACK),
|
||||
|
||||
@@ -7,7 +7,6 @@ import org.jackhuang.hmcl.mod.ModLoaderType;
|
||||
import org.jackhuang.hmcl.mod.ModManager;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystem;
|
||||
@@ -60,7 +59,7 @@ public final class QuiltModMetadata {
|
||||
throw new IOException("File " + modFile + " is not a Quilt mod.");
|
||||
}
|
||||
|
||||
QuiltModMetadata root = JsonUtils.fromNonNullJson(FileUtils.readText(path), QuiltModMetadata.class);
|
||||
QuiltModMetadata root = JsonUtils.fromNonNullJson(Files.readString(path), QuiltModMetadata.class);
|
||||
if (root.schema_version != 1) {
|
||||
throw new IOException("File " + modFile + " is not a supported Quilt mod.");
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public class ModrinthCompletionTask extends Task<Void> {
|
||||
try {
|
||||
File manifestFile = new File(repository.getVersionRoot(version), "modrinth.index.json");
|
||||
if (manifestFile.exists())
|
||||
this.manifest = JsonUtils.GSON.fromJson(FileUtils.readText(manifestFile), ModrinthManifest.class);
|
||||
this.manifest = JsonUtils.GSON.fromJson(Files.readString(manifestFile.toPath()), ModrinthManifest.class);
|
||||
} catch (Exception e) {
|
||||
LOG.warning("Unable to read Modrinth modpack manifest.json", e);
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ public class ModrinthInstallTask extends Task<Void> {
|
||||
ModpackConfiguration<ModrinthManifest> config = null;
|
||||
try {
|
||||
if (json.exists()) {
|
||||
config = JsonUtils.GSON.fromJson(FileUtils.readText(json), ModpackConfiguration.typeOf(ModrinthManifest.class));
|
||||
config = JsonUtils.GSON.fromJson(Files.readString(json.toPath()), 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.");
|
||||
|
||||
+2
-3
@@ -38,7 +38,6 @@ import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Files;
|
||||
@@ -111,7 +110,7 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
||||
ModpackConfiguration<MultiMCInstanceConfiguration> config = null;
|
||||
try {
|
||||
if (json.exists()) {
|
||||
config = JsonUtils.GSON.fromJson(FileUtils.readText(json), ModpackConfiguration.typeOf(MultiMCInstanceConfiguration.class));
|
||||
config = JsonUtils.GSON.fromJson(Files.readString(json.toPath()), 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.");
|
||||
@@ -146,7 +145,7 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
||||
throw new IllegalArgumentException("Json-Patch isn't a file: " + componentID);
|
||||
}
|
||||
|
||||
MultiMCInstancePatch patch = MultiMCInstancePatch.read(componentID, FileUtils.readText(patchPath, StandardCharsets.UTF_8));
|
||||
MultiMCInstancePatch patch = MultiMCInstancePatch.read(componentID, Files.readString(patchPath));
|
||||
patches.add(Task.supplyAsync(() -> patch)); // TODO: Task.completed has unclear compatibility issue.
|
||||
} else {
|
||||
patches.add(
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ public class ServerModpackCompletionTask extends Task<Void> {
|
||||
try {
|
||||
File manifestFile = repository.getModpackConfiguration(version);
|
||||
if (manifestFile.exists()) {
|
||||
this.manifest = JsonUtils.GSON.fromJson(FileUtils.readText(manifestFile), ModpackConfiguration.typeOf(ServerModpackManifest.class));
|
||||
this.manifest = JsonUtils.GSON.fromJson(Files.readString(manifestFile.toPath()), ModpackConfiguration.typeOf(ServerModpackManifest.class));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.warning("Unable to read Server modpack manifest.json", e);
|
||||
|
||||
+2
-2
@@ -27,10 +27,10 @@ import org.jackhuang.hmcl.mod.ModpackConfiguration;
|
||||
import org.jackhuang.hmcl.mod.ModpackInstallTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -71,7 +71,7 @@ public class ServerModpackLocalInstallTask extends Task<Void> {
|
||||
ModpackConfiguration<ServerModpackManifest> config = null;
|
||||
try {
|
||||
if (json.exists()) {
|
||||
config = JsonUtils.GSON.fromJson(FileUtils.readText(json), ModpackConfiguration.typeOf(ServerModpackManifest.class));
|
||||
config = JsonUtils.GSON.fromJson(Files.readString(json.toPath()), 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.");
|
||||
|
||||
+2
-2
@@ -24,10 +24,10 @@ import org.jackhuang.hmcl.game.DefaultGameRepository;
|
||||
import org.jackhuang.hmcl.mod.ModpackConfiguration;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -65,7 +65,7 @@ public class ServerModpackRemoteInstallTask extends Task<Void> {
|
||||
ModpackConfiguration<ServerModpackManifest> config;
|
||||
try {
|
||||
if (json.exists()) {
|
||||
config = JsonUtils.GSON.fromJson(FileUtils.readText(json), ModpackConfiguration.typeOf(ServerModpackManifest.class));
|
||||
config = JsonUtils.GSON.fromJson(Files.readString(json.toPath()), ModpackConfiguration.typeOf(ServerModpackManifest.class));
|
||||
|
||||
if (!MODPACK_TYPE.equals(config.getType()))
|
||||
throw new IllegalArgumentException("Version " + name + " is not a Server modpack. Cannot update this version.");
|
||||
|
||||
@@ -17,13 +17,12 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.task;
|
||||
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
@@ -67,7 +66,7 @@ public final class GetTask extends FetchTask<String> {
|
||||
|
||||
@Override
|
||||
protected void useCachedResult(Path cachedFile) throws IOException {
|
||||
setResult(FileUtils.readText(cachedFile));
|
||||
setResult(Files.readString(cachedFile));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,7 +83,7 @@ public final class GetTask extends FetchTask<String> {
|
||||
public void close() throws IOException {
|
||||
if (!isSuccess()) return;
|
||||
|
||||
String result = baos.toString(charset.name());
|
||||
String result = baos.toString(charset);
|
||||
setResult(result);
|
||||
|
||||
if (checkETag) {
|
||||
|
||||
@@ -21,7 +21,6 @@ import com.google.gson.JsonParseException;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.jackhuang.hmcl.util.function.ExceptionalSupplier;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
@@ -67,7 +66,7 @@ public class CacheRepository {
|
||||
}
|
||||
|
||||
if (Files.isRegularFile(indexFile)) {
|
||||
ETagIndex raw = GSON.fromJson(FileUtils.readText(indexFile), ETagIndex.class);
|
||||
ETagIndex raw = GSON.fromJson(Files.readString(indexFile), ETagIndex.class);
|
||||
if (raw == null)
|
||||
index = new HashMap<>();
|
||||
else
|
||||
@@ -288,7 +287,7 @@ public class CacheRepository {
|
||||
try (FileChannel channel = FileChannel.open(indexFile, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
|
||||
FileLock lock = channel.lock();
|
||||
try {
|
||||
ETagIndex indexOnDisk = fromMaybeMalformedJson(IOUtils.readFullyAsStringWithClosing(Channels.newInputStream(channel)), ETagIndex.class);
|
||||
ETagIndex indexOnDisk = fromMaybeMalformedJson(new String(Channels.newInputStream(channel).readAllBytes(), UTF_8), ETagIndex.class);
|
||||
Map<String, ETagItem> newIndex = joinETagIndexes(indexOnDisk == null ? null : indexOnDisk.eTag, index.values());
|
||||
channel.truncate(0);
|
||||
ByteBuffer writeTo = ByteBuffer.wrap(GSON.toJson(new ETagIndex(newIndex.values())).getBytes(UTF_8));
|
||||
@@ -411,7 +410,7 @@ public class CacheRepository {
|
||||
try {
|
||||
indexFile = cacheDirectory.resolve(name + ".json");
|
||||
if (Files.isRegularFile(indexFile)) {
|
||||
joinEntries(fromNonNullJson(FileUtils.readText(indexFile), mapTypeOf(String.class, Object.class)));
|
||||
joinEntries(fromNonNullJson(Files.readString(indexFile), mapTypeOf(String.class, Object.class)));
|
||||
}
|
||||
} catch (IOException | JsonParseException e) {
|
||||
LOG.warning("Unable to read storage {" + name + "} file");
|
||||
@@ -424,7 +423,7 @@ public class CacheRepository {
|
||||
try (FileChannel channel = FileChannel.open(indexFile, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
|
||||
FileLock lock = channel.lock();
|
||||
try {
|
||||
Map<String, Object> indexOnDisk = fromMaybeMalformedJson(IOUtils.readFullyAsStringWithClosing(Channels.newInputStream(channel)), mapTypeOf(String.class, Object.class));
|
||||
Map<String, Object> indexOnDisk = fromMaybeMalformedJson(new String(Channels.newInputStream(channel).readAllBytes(), UTF_8), mapTypeOf(String.class, Object.class));
|
||||
if (indexOnDisk == null) indexOnDisk = new HashMap<>();
|
||||
indexOnDisk.putAll(storage);
|
||||
channel.truncate(0);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -25,8 +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;
|
||||
import java.time.ZonedDateTime;
|
||||
@@ -114,22 +112,6 @@ public final class FileUtils {
|
||||
else return getName(path);
|
||||
}
|
||||
|
||||
public static String readText(File file) throws IOException {
|
||||
return readText(file, UTF_8);
|
||||
}
|
||||
|
||||
public static String readText(File file, Charset charset) throws IOException {
|
||||
return new String(Files.readAllBytes(file.toPath()), charset);
|
||||
}
|
||||
|
||||
public static String readText(Path file) throws IOException {
|
||||
return readText(file, UTF_8);
|
||||
}
|
||||
|
||||
public static String readText(Path file, Charset charset) throws IOException {
|
||||
return new String(Files.readAllBytes(file), charset);
|
||||
}
|
||||
|
||||
public static String readTextMaybeNativeEncoding(Path file) throws IOException {
|
||||
byte[] bytes = Files.readAllBytes(file);
|
||||
|
||||
@@ -160,7 +142,7 @@ public final class FileUtils {
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public static void writeText(File file, String text) throws IOException {
|
||||
writeText(file, text, UTF_8);
|
||||
writeText(file.toPath(), text);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,39 +157,8 @@ public final class FileUtils {
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public static void writeText(Path file, String text) throws IOException {
|
||||
writeText(file, text, UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write plain text to file.
|
||||
* <p>
|
||||
* We don't care about platform difference of line separator. Because readText accept all possibilities of line separator.
|
||||
* It will create the file if it does not exist, or truncate the existing file to empty for rewriting.
|
||||
* All characters in text will be written into the file in binary format. Existing data will be erased.
|
||||
*
|
||||
* @param file the path to the file
|
||||
* @param text the text being written to file
|
||||
* @param charset the charset to use for encoding
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public static void writeText(File file, String text, Charset charset) throws IOException {
|
||||
writeBytes(file, text.getBytes(charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write plain text to file.
|
||||
* <p>
|
||||
* We don't care about platform difference of line separator. Because readText accept all possibilities of line separator.
|
||||
* It will create the file if it does not exist, or truncate the existing file to empty for rewriting.
|
||||
* All characters in text will be written into the file in binary format. Existing data will be erased.
|
||||
*
|
||||
* @param file the path to the file
|
||||
* @param text the text being written to file
|
||||
* @param charset the charset to use for encoding
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public static void writeText(Path file, String text, Charset charset) throws IOException {
|
||||
writeBytes(file, text.getBytes(charset));
|
||||
Files.createDirectories(file.getParent());
|
||||
Files.writeString(file, text);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -328,18 +279,9 @@ public final class FileUtils {
|
||||
|
||||
/**
|
||||
* Move file to trash.
|
||||
* <p>
|
||||
* This method is only implemented in Java 9. Please check we are using Java 9 by invoking isMovingToTrashSupported.
|
||||
* Example:
|
||||
* <pre>{@code
|
||||
* if (FileUtils.isMovingToTrashSupported()) {
|
||||
* FileUtils.moveToTrash(file);
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @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 +335,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()) {
|
||||
|
||||
@@ -52,7 +52,7 @@ public final class HttpMultipartRequest implements Closeable {
|
||||
addLine(String.format("Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"", name, filename));
|
||||
addLine("Content-Type: " + contentType);
|
||||
addLine("");
|
||||
IOUtils.copyTo(inputStream, stream);
|
||||
inputStream.transferTo(stream);
|
||||
addLine("");
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -62,54 +62,18 @@ public final class IOUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all bytes to a buffer from given input stream. The stream will not be closed.
|
||||
*
|
||||
* @param stream the InputStream being read.
|
||||
* @return all bytes read from the stream
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public static byte[] readFullyWithoutClosing(InputStream stream) throws IOException {
|
||||
ByteArrayOutputStream result = new ByteArrayOutputStream(Math.max(stream.available(), 32));
|
||||
copyTo(stream, result);
|
||||
return result.toByteArray();
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all bytes to a buffer from given input stream, and close the input stream finally.
|
||||
*
|
||||
* @param stream the InputStream being read, closed finally.
|
||||
* @return all bytes read from the stream
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public static ByteArrayOutputStream readFully(InputStream stream) throws IOException {
|
||||
try (InputStream is = stream) {
|
||||
ByteArrayOutputStream result = new ByteArrayOutputStream(Math.max(is.available(), 32));
|
||||
copyTo(is, result);
|
||||
return result;
|
||||
public static byte[] readFully(InputStream stream) throws IOException {
|
||||
try (stream) {
|
||||
return stream.readAllBytes();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] readFullyAsByteArray(InputStream stream) throws IOException {
|
||||
return readFully(stream).toByteArray();
|
||||
}
|
||||
|
||||
public static String readFullyAsString(InputStream stream) throws IOException {
|
||||
return readFully(stream).toString("UTF-8");
|
||||
return new String(readFully(stream), UTF_8);
|
||||
}
|
||||
|
||||
public static String readFullyAsString(InputStream stream, Charset charset) throws IOException {
|
||||
return readFully(stream).toString(charset.name());
|
||||
}
|
||||
|
||||
public static void copyTo(InputStream src, OutputStream dest) throws IOException {
|
||||
copyTo(src, dest, new byte[DEFAULT_BUFFER_SIZE]);
|
||||
return new String(readFully(stream), charset);
|
||||
}
|
||||
|
||||
public static void copyTo(InputStream src, OutputStream dest, byte[] buf) throws IOException {
|
||||
|
||||
@@ -1,27 +1,38 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.logging;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author Glavo
|
||||
*/
|
||||
final class CallerFinder {
|
||||
private static final String PACKAGE_PREFIX = CallerFinder.class.getPackageName() + ".";
|
||||
private static final Predicate<StackWalker.StackFrame> PREDICATE = stackFrame -> !stackFrame.getClassName().startsWith(PACKAGE_PREFIX);
|
||||
private static final Function<Stream<StackWalker.StackFrame>, Optional<StackWalker.StackFrame>> FUNCTION = stream -> stream.filter(PREDICATE).findFirst();
|
||||
private static final Function<StackWalker.StackFrame, String> FRAME_MAPPING = frame -> frame.getClassName() + "." + frame.getMethodName();
|
||||
|
||||
static String getCaller() {
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
|
||||
int i = 0;
|
||||
while (i++ < stackTrace.length) {
|
||||
if (stackTrace[i].getClassName().equals(Logger.CLASS_NAME))
|
||||
break;
|
||||
}
|
||||
|
||||
while (i++ < stackTrace.length) {
|
||||
StackTraceElement element = stackTrace[i];
|
||||
String cname = element.getClassName();
|
||||
if (!cname.equals(Logger.CLASS_NAME) && !cname.startsWith("java.lang.reflect.") && !cname.startsWith("sun.reflect.")) {
|
||||
return cname + '.' + element.getMethodName();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return StackWalker.getInstance().walk(FUNCTION).map(FRAME_MAPPING).orElse(null);
|
||||
}
|
||||
|
||||
private CallerFinder() {
|
||||
|
||||
@@ -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 "";
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.jackhuang.hmcl.util.platform.linux;
|
||||
|
||||
import org.jackhuang.hmcl.util.KeyValuePairUtils;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.platform.hardware.CentralProcessor;
|
||||
import org.jackhuang.hmcl.util.platform.hardware.HardwareVendor;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -119,7 +118,7 @@ final class LinuxCPUDetector {
|
||||
Path compatiblePath = Paths.get("/proc/device-tree/compatible");
|
||||
if (Files.isRegularFile(compatiblePath)) {
|
||||
// device-vendor,device-model\0soc-vendor,soc-model\0
|
||||
String[] data = FileUtils.readText(compatiblePath).split("\0");
|
||||
String[] data = Files.readString(compatiblePath).split("\0");
|
||||
|
||||
for (int i = data.length - 1; i >= 0; i--) {
|
||||
String device = data[i];
|
||||
@@ -207,10 +206,10 @@ final class LinuxCPUDetector {
|
||||
if (!dirNamePattern.matcher(cpuDir.getFileName().toString()).matches() || !Files.isDirectory(cpuDir))
|
||||
continue;
|
||||
|
||||
physicalPackageIds.add(Integer.parseInt(FileUtils.readText(cpuDir.resolve("topology/physical_package_id")).trim()));
|
||||
physicalPackageIds.add(Integer.parseInt(Files.readString(cpuDir.resolve("topology/physical_package_id")).trim()));
|
||||
|
||||
boolean shouldCount = false;
|
||||
for (String item : FileUtils.readText(cpuDir.resolve("topology/core_cpus_list")).trim().split(",")) {
|
||||
for (String item : Files.readString(cpuDir.resolve("topology/core_cpus_list")).trim().split(",")) {
|
||||
String range = item.trim();
|
||||
int idx = range.indexOf('-');
|
||||
if (idx < 0)
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.glavo.pci.ids.model.Device;
|
||||
import org.glavo.pci.ids.model.Vendor;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard;
|
||||
import org.jackhuang.hmcl.util.platform.hardware.HardwareVendor;
|
||||
|
||||
@@ -97,11 +96,11 @@ final class LinuxGPUDetector {
|
||||
|
||||
Path versionFile = deviceDir.resolve("driver/module/version");
|
||||
if (Files.isRegularFile(versionFile)) {
|
||||
builder.setDriverVersion(FileUtils.readText(versionFile).trim());
|
||||
builder.setDriverVersion(Files.readString(versionFile).trim());
|
||||
} else if ("zx".equals(name)) {
|
||||
versionFile = deviceDir.resolve("zx_info/driver_version");
|
||||
if (Files.isRegularFile(versionFile)) {
|
||||
builder.setDriverVersion(FileUtils.readText(versionFile).trim());
|
||||
builder.setDriverVersion(Files.readString(versionFile).trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,7 +157,7 @@ final class LinuxGPUDetector {
|
||||
|
||||
Path revisionFile = deviceDir.resolve("revision");
|
||||
if (Files.isRegularFile(revisionFile)) {
|
||||
String revisionString = FileUtils.readText(revisionFile).trim();
|
||||
String revisionString = Files.readString(revisionFile).trim();
|
||||
int revision = Integer.decode(revisionString);
|
||||
String prefix = String.format("%X,\t%X,\t", deviceId, revision);
|
||||
//noinspection DataFlowIssue
|
||||
@@ -299,7 +298,7 @@ final class LinuxGPUDetector {
|
||||
continue;
|
||||
|
||||
try {
|
||||
String modalias = FileUtils.readText(modaliasFile).trim();
|
||||
String modalias = Files.readString(modaliasFile).trim();
|
||||
GraphicsCard graphicsCard = null;
|
||||
if (modalias.startsWith("pci:"))
|
||||
graphicsCard = detectPCI(deviceDir, modalias);
|
||||
|
||||
@@ -20,7 +20,6 @@ package org.jackhuang.hmcl.util.tree;
|
||||
|
||||
import kala.compress.archivers.tar.TarArchiveEntry;
|
||||
import kala.compress.archivers.tar.TarArchiveReader;
|
||||
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
@@ -42,7 +41,7 @@ public final class TarFileTree extends ArchiveFileTree<TarArchiveReader, TarArch
|
||||
try (GZIPInputStream input = new GZIPInputStream(Files.newInputStream(file));
|
||||
OutputStream output = Files.newOutputStream(tempFile, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)
|
||||
) {
|
||||
IOUtils.copyTo(input, output);
|
||||
input.transferTo(output);
|
||||
tarFile = new TarArchiveReader(tempFile);
|
||||
} catch (Throwable e) {
|
||||
try {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -24,9 +24,6 @@ subprojects {
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
sourceCompatibility = "1.8"
|
||||
targetCompatibility = "1.8"
|
||||
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
|
||||
Loaded 100 of 102 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user