Compare commits
41
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6133e7e730 | ||
|
|
c5cbafea60 | ||
|
|
167e25e859 | ||
|
|
f47bd8a407 | ||
|
|
464be411d1 | ||
|
|
d3b6eb36d9 | ||
|
|
71458f5167 | ||
|
|
597730389f | ||
|
|
56b227f467 | ||
|
|
213b03ea56 | ||
|
|
959c4d0698 | ||
|
|
57b3bd9ff0 | ||
|
|
68f4038879 | ||
|
|
6010008409 | ||
|
|
4b2e857f08 | ||
|
|
0280a34d00 | ||
|
|
811707b611 | ||
|
|
9152550bda | ||
|
|
6cb4d24600 | ||
|
|
49287453eb | ||
|
|
e7c108d843 | ||
|
|
6c9bf6cb09 | ||
|
|
efc27c8e21 | ||
|
|
7c5ccc906e | ||
|
|
69a6ff6053 | ||
|
|
605d0c6a92 | ||
|
|
9d54ddf456 | ||
|
|
c6afd53e73 | ||
|
|
fd9bb88033 | ||
|
|
316607b333 | ||
|
|
af36a0ac2a | ||
|
|
7356335106 | ||
|
|
d8c96769ea | ||
|
|
d71815aa3d | ||
|
|
9a4286620f | ||
|
|
0eac7b5d12 | ||
|
|
af63c3aa3a | ||
|
|
72a8199453 | ||
|
|
090b83bf9c | ||
|
|
6f70da51f9 | ||
|
|
ed0a4c8cf4 |
No files matched your search
@@ -10,5 +10,5 @@ contact_links:
|
||||
url: https://afdian.net/@huanghongxun
|
||||
about: 前往爱发电赞助 HMCL。赞助后可以申请加入官方 QQ 群反馈问题。
|
||||
- name: 其他反馈
|
||||
url: https://github.com/huanghongxun/HMCL/issues/new
|
||||
about: 通过 Issue 反馈其他问题。
|
||||
url: https://github.com/huanghongxun/HMCL/discussions/new/choose
|
||||
about: 通过 Discussions 反馈其他问题。
|
||||
@@ -0,0 +1,21 @@
|
||||
name: "Feature Request"
|
||||
description: "为 HMCL 提出新功能"
|
||||
labels: feature request
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "提交前请确保查看 issues 列表是否有重复的项目!"
|
||||
- type: textarea
|
||||
id: "yml-2"
|
||||
attributes:
|
||||
label: 描述 Description
|
||||
description: "详细描述你想加入的新功能"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: "yml-3"
|
||||
attributes:
|
||||
label: 原因 Why
|
||||
description: "描述该功能带来的好处及原因"
|
||||
validations:
|
||||
required: true
|
||||
@@ -56,7 +56,12 @@ fun createChecksum(file: File) {
|
||||
}
|
||||
|
||||
fun attachSignature(jar: File) {
|
||||
val keyLocation = System.getenv("HMCL_SIGNATURE_KEY") ?: return
|
||||
val keyLocation = System.getenv("HMCL_SIGNATURE_KEY")
|
||||
if (keyLocation == null) {
|
||||
logger.warn("Missing signature key")
|
||||
return
|
||||
}
|
||||
|
||||
val privatekey = KeyFactory.getInstance("RSA").generatePrivate(PKCS8EncodedKeySpec(File(keyLocation).readBytes()))
|
||||
val signer = Signature.getInstance("SHA512withRSA")
|
||||
signer.initSign(privatekey)
|
||||
|
||||
@@ -19,6 +19,7 @@ public class SkinTransition extends Transition {
|
||||
return count;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public SkinTransition(Duration duration, Function<Double, Double> expression, WritableValue<Number>... observables) {
|
||||
setCycleDuration(duration);
|
||||
this.expression = expression;
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.jackhuang.hmcl;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Alert.AlertType;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.input.Clipboard;
|
||||
import javafx.scene.input.DataFormat;
|
||||
@@ -85,12 +86,18 @@ public final class Launcher extends Application {
|
||||
Main.showErrorAndExit(i18n("fatal.config_loading_failure", ConfigHolder.configLocation().getParent()));
|
||||
}
|
||||
|
||||
checkConfigInTempDir();
|
||||
// https://lapcatsoftware.com/articles/app-translocation.html
|
||||
if (OperatingSystem.CURRENT_OS == OperatingSystem.OSX
|
||||
&& ConfigHolder.isNewlyCreated()
|
||||
&& System.getProperty("user.dir").startsWith("/private/var/folders/")) {
|
||||
if (showAlert(AlertType.WARNING, i18n("fatal.mac_app_translocation"), ButtonType.YES, ButtonType.NO) == ButtonType.NO)
|
||||
return;
|
||||
} else {
|
||||
checkConfigInTempDir();
|
||||
}
|
||||
|
||||
if (ConfigHolder.isOwnerChanged()) {
|
||||
ButtonType res = new Alert(Alert.AlertType.WARNING, i18n("fatal.config_change_owner_root"), ButtonType.YES, ButtonType.NO)
|
||||
.showAndWait()
|
||||
.orElse(null);
|
||||
if (res == ButtonType.NO)
|
||||
if (showAlert(AlertType.WARNING, i18n("fatal.config_change_owner_root"), ButtonType.YES, ButtonType.NO) == ButtonType.NO)
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -114,6 +121,10 @@ public final class Launcher extends Application {
|
||||
}
|
||||
}
|
||||
|
||||
private static ButtonType showAlert(AlertType alertType, String contentText, ButtonType... buttons) {
|
||||
return new Alert(alertType, contentText, buttons).showAndWait().orElse(null);
|
||||
}
|
||||
|
||||
private static boolean isConfigInTempDir() {
|
||||
String configPath = ConfigHolder.configLocation().toString();
|
||||
|
||||
@@ -152,13 +163,9 @@ public final class Launcher extends Application {
|
||||
}
|
||||
|
||||
private static void checkConfigInTempDir() {
|
||||
if (ConfigHolder.isNewlyCreated() && isConfigInTempDir()) {
|
||||
ButtonType res = new Alert(Alert.AlertType.WARNING, i18n("fatal.config_in_temp_dir"), ButtonType.YES, ButtonType.NO)
|
||||
.showAndWait()
|
||||
.orElse(null);
|
||||
if (res == ButtonType.NO) {
|
||||
System.exit(0);
|
||||
}
|
||||
if (ConfigHolder.isNewlyCreated() && isConfigInTempDir()
|
||||
&& showAlert(AlertType.WARNING, i18n("fatal.config_in_temp_dir"), ButtonType.YES, ButtonType.NO) == ButtonType.NO) {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,10 +197,9 @@ public final class Launcher extends Application {
|
||||
String command = new CommandBuilder().add("sudo", "chown", "-R", userName).addAll(files).toString();
|
||||
ButtonType copyAndExit = new ButtonType(i18n("button.copy_and_exit"));
|
||||
|
||||
ButtonType res = new Alert(Alert.AlertType.ERROR, i18n("fatal.config_loading_failure.unix", owner, command), copyAndExit, ButtonType.CLOSE)
|
||||
.showAndWait()
|
||||
.orElse(null);
|
||||
if (res == copyAndExit) {
|
||||
if (showAlert(AlertType.ERROR,
|
||||
i18n("fatal.config_loading_failure.unix", owner, command),
|
||||
copyAndExit, ButtonType.CLOSE) == copyAndExit) {
|
||||
Clipboard.getSystemClipboard()
|
||||
.setContent(Collections.singletonMap(DataFormat.PLAIN_TEXT, command));
|
||||
}
|
||||
@@ -222,7 +228,7 @@ public final class Launcher extends Application {
|
||||
LOG.info("Java Version: " + System.getProperty("java.version") + ", " + System.getProperty("java.vendor"));
|
||||
LOG.info("Java VM Version: " + System.getProperty("java.vm.name") + " (" + System.getProperty("java.vm.info") + "), " + System.getProperty("java.vm.vendor"));
|
||||
LOG.info("Java Home: " + System.getProperty("java.home"));
|
||||
LOG.info("Current Directory: " + Paths.get("").toAbsolutePath());
|
||||
LOG.info("Current Directory: " + System.getProperty("user.dir"));
|
||||
LOG.info("HMCL Directory: " + Metadata.HMCL_DIRECTORY);
|
||||
LOG.info("HMCL Jar Path: " + JarUtils.thisJar().map(it -> it.toAbsolutePath().toString()).orElse("Not Found"));
|
||||
LOG.info("Memory: " + Runtime.getRuntime().maxMemory() / 1024 / 1024 + "MB");
|
||||
@@ -231,6 +237,8 @@ public final class Launcher extends Application {
|
||||
.findAny()
|
||||
.map(bean -> bean.getUsage().getUsed() / 1024 / 1024 + "MB")
|
||||
.orElse("Unknown"));
|
||||
if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX)
|
||||
LOG.info("XDG Session Type: " + System.getenv("XDG_SESSION_TYPE"));
|
||||
|
||||
launch(Launcher.class, args);
|
||||
} catch (Throwable e) { // Fucking JavaFX will suppress the exception and will break our crash reporter.
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.jackhuang.hmcl;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.Alert;
|
||||
import org.jackhuang.hmcl.ui.AwtUtils;
|
||||
import org.jackhuang.hmcl.util.FractureiserDetector;
|
||||
import org.jackhuang.hmcl.util.Logging;
|
||||
import org.jackhuang.hmcl.util.SelfDependencyPatcher;
|
||||
import org.jackhuang.hmcl.ui.SwingUtils;
|
||||
@@ -71,6 +72,7 @@ public final class Main {
|
||||
Logging.start(Metadata.HMCL_DIRECTORY.resolve("logs"));
|
||||
|
||||
checkJavaFX();
|
||||
detectFractureiser();
|
||||
|
||||
Launcher.main(args);
|
||||
}
|
||||
@@ -89,6 +91,13 @@ public final class Main {
|
||||
}
|
||||
}
|
||||
|
||||
private static void detectFractureiser() {
|
||||
if (FractureiserDetector.detect()) {
|
||||
LOG.log(Level.SEVERE, "Detected that this computer is infected by fractureiser");
|
||||
showErrorAndExit(i18n("fatal.fractureiser"));
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkJavaFX() {
|
||||
try {
|
||||
SelfDependencyPatcher.patch();
|
||||
|
||||
@@ -48,11 +48,13 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.newImage;
|
||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||
import static org.jackhuang.hmcl.util.Pair.pair;
|
||||
|
||||
public class HMCLGameRepository extends DefaultGameRepository {
|
||||
private final Profile profile;
|
||||
@@ -335,6 +337,16 @@ public class HMCLGameRepository extends DefaultGameRepository {
|
||||
) / 1024 / 1024))
|
||||
.setMinMemory(vs.getMinMemory())
|
||||
.setMetaspace(Lang.toIntOrNull(vs.getPermSize()))
|
||||
.setEnvironmentVariables(
|
||||
Lang.mapOf(StringUtils.tokenize(vs.getEnvironmentVariables())
|
||||
.stream()
|
||||
.map(it -> {
|
||||
int idx = it.indexOf('=');
|
||||
return idx >= 0 ? pair(it.substring(0, idx), it.substring(idx + 1)) : pair(it, "");
|
||||
})
|
||||
.collect(Collectors.toList())
|
||||
)
|
||||
)
|
||||
.setWidth(vs.getWidth())
|
||||
.setHeight(vs.getHeight())
|
||||
.setFullscreen(vs.isFullscreen())
|
||||
@@ -346,7 +358,7 @@ public class HMCLGameRepository extends DefaultGameRepository {
|
||||
.setNativesDirType(vs.getNativesDirType())
|
||||
.setNativesDir(vs.getNativesDir())
|
||||
.setProcessPriority(vs.getProcessPriority())
|
||||
.setUseSoftwareRenderer(vs.isUseSoftwareRenderer())
|
||||
.setRenderer(vs.getRenderer())
|
||||
.setUseNativeGLFW(vs.isUseNativeGLFW())
|
||||
.setUseNativeOpenAL(vs.isUseNativeOpenAL())
|
||||
.setDaemon(!makeLaunchScript && vs.getLauncherVisibility().isDaemon())
|
||||
|
||||
@@ -150,8 +150,9 @@ public final class LauncherHelper {
|
||||
}
|
||||
}),
|
||||
Task.composeAsync(() -> {
|
||||
if (setting.isUseSoftwareRenderer() && OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
|
||||
Library lib = NativePatcher.getSoftwareRendererLoader(javaVersion);
|
||||
Renderer renderer = setting.getRenderer();
|
||||
if (renderer != Renderer.DEFAULT && OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
|
||||
Library lib = NativePatcher.getMesaLoader(javaVersion, renderer);
|
||||
if (lib == null)
|
||||
return null;
|
||||
File file = dependencyManager.getGameRepository().getLibraryFile(version.get(), lib);
|
||||
@@ -160,11 +161,13 @@ public final class LauncherHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
String agent = file.getAbsolutePath() + "=" + renderer.name().toLowerCase(Locale.ROOT);
|
||||
|
||||
if (GameLibrariesTask.shouldDownloadLibrary(repository, version.get(), lib, integrityCheck)) {
|
||||
return new LibraryDownloadTask(dependencyManager, file, lib)
|
||||
.thenRunAsync(() -> javaAgents.add(file.getAbsolutePath()));
|
||||
.thenRunAsync(() -> javaAgents.add(agent));
|
||||
} else {
|
||||
javaAgents.add(file.getAbsolutePath());
|
||||
javaAgents.add(agent);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.skin.InvalidSkinException;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.nio.file.Files;
|
||||
@@ -427,7 +428,11 @@ public final class Accounts {
|
||||
if (exception instanceof NoCharacterException) {
|
||||
return i18n("account.failed.no_character");
|
||||
} else if (exception instanceof ServerDisconnectException) {
|
||||
return i18n("account.failed.connect_authentication_server");
|
||||
if (exception.getCause() instanceof SSLException) {
|
||||
return i18n("account.failed.ssl");
|
||||
} else {
|
||||
return i18n("account.failed.connect_authentication_server");
|
||||
}
|
||||
} else if (exception instanceof ServerResponseMalformedException) {
|
||||
return i18n("account.failed.server_response_malformed");
|
||||
} else if (exception instanceof RemoteAuthenticationException) {
|
||||
|
||||
@@ -194,6 +194,9 @@ public final class Config implements Cloneable, Observable {
|
||||
@SerializedName("animationDisabled")
|
||||
private BooleanProperty animationDisabled = new SimpleBooleanProperty();
|
||||
|
||||
@SerializedName("shownTips")
|
||||
private ObservableMap<String, Object> shownTips = FXCollections.observableHashMap();
|
||||
|
||||
private transient ObservableHelper helper = new ObservableHelper(this);
|
||||
|
||||
public Config() {
|
||||
@@ -639,4 +642,8 @@ public final class Config implements Cloneable, Observable {
|
||||
public void setPromptedVersion(String promptedVersion) {
|
||||
this.promptedVersion.set(promptedVersion);
|
||||
}
|
||||
|
||||
public ObservableMap<String, Object> getShownTips() {
|
||||
return shownTips;
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ import java.lang.reflect.Type;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -340,6 +341,20 @@ public final class VersionSetting implements Cloneable {
|
||||
minecraftArgsProperty.set(minecraftArgs);
|
||||
}
|
||||
|
||||
private final StringProperty environmentVariablesProperty = new SimpleStringProperty(this, "environmentVariables", "");
|
||||
|
||||
public StringProperty environmentVariablesProperty() {
|
||||
return environmentVariablesProperty;
|
||||
}
|
||||
|
||||
public String getEnvironmentVariables() {
|
||||
return environmentVariablesProperty.get();
|
||||
}
|
||||
|
||||
public void setEnvironmentVariables(String env) {
|
||||
environmentVariablesProperty.set(env);
|
||||
}
|
||||
|
||||
private final BooleanProperty noJVMArgsProperty = new SimpleBooleanProperty(this, "noJVMArgs", false);
|
||||
|
||||
public BooleanProperty noJVMArgsProperty() {
|
||||
@@ -482,7 +497,6 @@ public final class VersionSetting implements Cloneable {
|
||||
widthProperty.set(width);
|
||||
}
|
||||
|
||||
|
||||
private final IntegerProperty heightProperty = new SimpleIntegerProperty(this, "height", 480);
|
||||
|
||||
public IntegerProperty heightProperty() {
|
||||
@@ -553,18 +567,18 @@ public final class VersionSetting implements Cloneable {
|
||||
processPriorityProperty.set(processPriority);
|
||||
}
|
||||
|
||||
private final BooleanProperty useSoftwareRenderer = new SimpleBooleanProperty(this, "softwareRenderer", false);
|
||||
private final ObjectProperty<Renderer> rendererProperty = new SimpleObjectProperty<>(this, "renderer", Renderer.DEFAULT);
|
||||
|
||||
public boolean isUseSoftwareRenderer() {
|
||||
return useSoftwareRenderer.get();
|
||||
public Renderer getRenderer() {
|
||||
return rendererProperty.get();
|
||||
}
|
||||
|
||||
public BooleanProperty useSoftwareRendererProperty() {
|
||||
return useSoftwareRenderer;
|
||||
public ObjectProperty<Renderer> rendererProperty() {
|
||||
return rendererProperty;
|
||||
}
|
||||
|
||||
public void setUseSoftwareRenderer(boolean useSoftwareRenderer) {
|
||||
this.useSoftwareRenderer.set(useSoftwareRenderer);
|
||||
public void setRenderer(Renderer renderer) {
|
||||
this.rendererProperty.set(renderer);
|
||||
}
|
||||
|
||||
private final BooleanProperty useNativeGLFW = new SimpleBooleanProperty(this, "nativeGLFW", false);
|
||||
@@ -692,6 +706,7 @@ public final class VersionSetting implements Cloneable {
|
||||
postExitCommand.addListener(listener);
|
||||
javaArgsProperty.addListener(listener);
|
||||
minecraftArgsProperty.addListener(listener);
|
||||
environmentVariablesProperty.addListener(listener);
|
||||
noJVMArgsProperty.addListener(listener);
|
||||
notCheckGameProperty.addListener(listener);
|
||||
notCheckJVMProperty.addListener(listener);
|
||||
@@ -704,7 +719,7 @@ public final class VersionSetting implements Cloneable {
|
||||
gameDirTypeProperty.addListener(listener);
|
||||
gameDirProperty.addListener(listener);
|
||||
processPriorityProperty.addListener(listener);
|
||||
useSoftwareRenderer.addListener(listener);
|
||||
rendererProperty.addListener(listener);
|
||||
useNativeGLFW.addListener(listener);
|
||||
useNativeOpenAL.addListener(listener);
|
||||
launcherVisibilityProperty.addListener(listener);
|
||||
@@ -730,6 +745,7 @@ public final class VersionSetting implements Cloneable {
|
||||
versionSetting.setPostExitCommand(getPostExitCommand());
|
||||
versionSetting.setJavaArgs(getJavaArgs());
|
||||
versionSetting.setMinecraftArgs(getMinecraftArgs());
|
||||
versionSetting.setEnvironmentVariables(getEnvironmentVariables());
|
||||
versionSetting.setNoJVMArgs(isNoJVMArgs());
|
||||
versionSetting.setNotCheckGame(isNotCheckGame());
|
||||
versionSetting.setNotCheckJVM(isNotCheckJVM());
|
||||
@@ -742,7 +758,7 @@ public final class VersionSetting implements Cloneable {
|
||||
versionSetting.setGameDirType(getGameDirType());
|
||||
versionSetting.setGameDir(getGameDir());
|
||||
versionSetting.setProcessPriority(getProcessPriority());
|
||||
versionSetting.setUseSoftwareRenderer(isUseSoftwareRenderer());
|
||||
versionSetting.setRenderer(getRenderer());
|
||||
versionSetting.setUseNativeGLFW(isUseNativeGLFW());
|
||||
versionSetting.setUseNativeOpenAL(isUseNativeOpenAL());
|
||||
versionSetting.setLauncherVisibility(getLauncherVisibility());
|
||||
@@ -760,6 +776,7 @@ public final class VersionSetting implements Cloneable {
|
||||
obj.addProperty("usesGlobal", src.isUsesGlobal());
|
||||
obj.addProperty("javaArgs", src.getJavaArgs());
|
||||
obj.addProperty("minecraftArgs", src.getMinecraftArgs());
|
||||
obj.addProperty("environmentVariables", src.getEnvironmentVariables());
|
||||
obj.addProperty("maxMemory", src.getMaxMemory() <= 0 ? OperatingSystem.SUGGESTED_MEMORY : src.getMaxMemory());
|
||||
obj.addProperty("minMemory", src.getMinMemory());
|
||||
obj.addProperty("autoMemory", src.isAutoMemory());
|
||||
@@ -781,7 +798,6 @@ public final class VersionSetting implements Cloneable {
|
||||
obj.addProperty("gameDir", src.getGameDir());
|
||||
obj.addProperty("launcherVisibility", src.getLauncherVisibility().ordinal());
|
||||
obj.addProperty("processPriority", src.getProcessPriority().ordinal());
|
||||
obj.addProperty("useSoftwareRenderer", src.isUseSoftwareRenderer());
|
||||
obj.addProperty("useNativeGLFW", src.isUseNativeGLFW());
|
||||
obj.addProperty("useNativeOpenAL", src.isUseNativeOpenAL());
|
||||
obj.addProperty("gameDirType", src.getGameDirType().ordinal());
|
||||
@@ -790,6 +806,10 @@ public final class VersionSetting implements Cloneable {
|
||||
obj.addProperty("nativesDirType", src.getNativesDirType().ordinal());
|
||||
obj.addProperty("versionIcon", src.getVersionIcon().ordinal());
|
||||
|
||||
obj.addProperty("renderer", src.getRenderer().name());
|
||||
if (src.getRenderer() == Renderer.LLVMPIPE)
|
||||
obj.addProperty("useSoftwareRenderer", true);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -815,6 +835,7 @@ public final class VersionSetting implements Cloneable {
|
||||
vs.setUsesGlobal(Optional.ofNullable(obj.get("usesGlobal")).map(JsonElement::getAsBoolean).orElse(false));
|
||||
vs.setJavaArgs(Optional.ofNullable(obj.get("javaArgs")).map(JsonElement::getAsString).orElse(""));
|
||||
vs.setMinecraftArgs(Optional.ofNullable(obj.get("minecraftArgs")).map(JsonElement::getAsString).orElse(""));
|
||||
vs.setEnvironmentVariables(Optional.ofNullable(obj.get("environmentVariables")).map(JsonElement::getAsString).orElse(""));
|
||||
vs.setMaxMemory(maxMemoryN);
|
||||
vs.setMinMemory(Optional.ofNullable(obj.get("minMemory")).map(JsonElement::getAsInt).orElse(null));
|
||||
vs.setAutoMemory(Optional.ofNullable(obj.get("autoMemory")).map(JsonElement::getAsBoolean).orElse(true));
|
||||
@@ -836,7 +857,6 @@ public final class VersionSetting implements Cloneable {
|
||||
vs.setShowLogs(Optional.ofNullable(obj.get("showLogs")).map(JsonElement::getAsBoolean).orElse(false));
|
||||
vs.setLauncherVisibility(getOrDefault(LauncherVisibility.values(), obj.get("launcherVisibility"), LauncherVisibility.HIDE));
|
||||
vs.setProcessPriority(getOrDefault(ProcessPriority.values(), obj.get("processPriority"), ProcessPriority.NORMAL));
|
||||
vs.setUseSoftwareRenderer(Optional.ofNullable(obj.get("useSoftwareRenderer")).map(JsonElement::getAsBoolean).orElse(false));
|
||||
vs.setUseNativeGLFW(Optional.ofNullable(obj.get("useNativeGLFW")).map(JsonElement::getAsBoolean).orElse(false));
|
||||
vs.setUseNativeOpenAL(Optional.ofNullable(obj.get("useNativeOpenAL")).map(JsonElement::getAsBoolean).orElse(false));
|
||||
vs.setGameDirType(getOrDefault(GameDirectoryType.values(), obj.get("gameDirType"), GameDirectoryType.ROOT_FOLDER));
|
||||
@@ -844,6 +864,18 @@ public final class VersionSetting implements Cloneable {
|
||||
vs.setNativesDirType(getOrDefault(NativesDirectoryType.values(), obj.get("nativesDirType"), NativesDirectoryType.VERSION_FOLDER));
|
||||
vs.setVersionIcon(getOrDefault(VersionIconType.values(), obj.get("versionIcon"), VersionIconType.DEFAULT));
|
||||
|
||||
vs.setRenderer(Optional.ofNullable(obj.get("renderer")).map(JsonElement::getAsString)
|
||||
.flatMap(name -> {
|
||||
try {
|
||||
return Optional.of(Renderer.valueOf(name.toUpperCase(Locale.ROOT)));
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}).orElseGet(() -> {
|
||||
boolean useSoftwareRenderer = Optional.ofNullable(obj.get("useSoftwareRenderer")).map(JsonElement::getAsBoolean).orElse(false);
|
||||
return useSoftwareRenderer ? Renderer.LLVMPIPE : Renderer.DEFAULT;
|
||||
}));
|
||||
|
||||
return vs;
|
||||
}
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ public final class Controllers {
|
||||
agreementPane.setHeading(new Label(i18n("launcher.agreement")));
|
||||
agreementPane.setBody(new Label(i18n("launcher.agreement.hint")));
|
||||
JFXHyperlink agreementLink = new JFXHyperlink(i18n("launcher.agreement"));
|
||||
agreementLink.setOnAction(e -> FXUtils.openLink(Metadata.EULA_URL));
|
||||
agreementLink.setExternalLink(Metadata.EULA_URL);
|
||||
JFXButton yesButton = new JFXButton(i18n("launcher.agreement.accept"));
|
||||
yesButton.getStyleClass().add("dialog-accept");
|
||||
yesButton.setOnAction(e -> {
|
||||
@@ -236,9 +236,7 @@ public final class Controllers {
|
||||
});
|
||||
JFXButton noButton = new JFXButton(i18n("launcher.agreement.decline"));
|
||||
noButton.getStyleClass().add("dialog-cancel");
|
||||
noButton.setOnAction(e -> {
|
||||
System.exit(1);
|
||||
});
|
||||
noButton.setOnAction(e -> System.exit(1));
|
||||
agreementPane.setActions(agreementLink, yesButton, noButton);
|
||||
Controllers.dialog(agreementPane);
|
||||
}
|
||||
@@ -325,9 +323,14 @@ public final class Controllers {
|
||||
|
||||
public static void onHyperlinkAction(String href) {
|
||||
if (href.startsWith("hmcl://")) {
|
||||
if ("hmcl://settings/feedback".equals(href)) {
|
||||
Controllers.getSettingsPage().showFeedback();
|
||||
Controllers.navigate(Controllers.getSettingsPage());
|
||||
switch (href) {
|
||||
case "hmcl://settings/feedback":
|
||||
Controllers.getSettingsPage().showFeedback();
|
||||
Controllers.navigate(Controllers.getSettingsPage());
|
||||
break;
|
||||
case "hmcl://hide-announcement":
|
||||
Controllers.getRootPage().getMainPage().hideAnnouncementPane();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
FXUtils.openLink(href);
|
||||
|
||||
@@ -625,16 +625,17 @@ public final class FXUtils {
|
||||
* @param comboBox the combo box being bound with {@code property}.
|
||||
* @param property the property being bound with {@code combo box}.
|
||||
* @see #unbindEnum(JFXComboBox)
|
||||
* @deprecated Use {@link ExtendedProperties#selectedItemPropertyFor(ComboBox)}
|
||||
* @see ExtendedProperties#selectedItemPropertyFor(ComboBox)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
public static void bindEnum(JFXComboBox<?> comboBox, Property<? extends Enum<?>> property) {
|
||||
public static <T extends Enum<T>> void bindEnum(JFXComboBox<T> comboBox, Property<T> property) {
|
||||
unbindEnum(comboBox);
|
||||
@SuppressWarnings("rawtypes")
|
||||
ChangeListener<Number> listener = (a, b, newValue) ->
|
||||
((Property) property).setValue(property.getValue().getClass().getEnumConstants()[newValue.intValue()]);
|
||||
comboBox.getSelectionModel().select(property.getValue().ordinal());
|
||||
|
||||
T currentValue = property.getValue();
|
||||
@SuppressWarnings("unchecked")
|
||||
T[] enumConstants = (T[]) currentValue.getClass().getEnumConstants();
|
||||
ChangeListener<Number> listener = (a, b, newValue) -> property.setValue(enumConstants[newValue.intValue()]);
|
||||
|
||||
comboBox.getSelectionModel().select(currentValue.ordinal());
|
||||
comboBox.getProperties().put("FXUtils.bindEnum.listener", listener);
|
||||
comboBox.getSelectionModel().selectedIndexProperty().addListener(listener);
|
||||
}
|
||||
@@ -645,15 +646,13 @@ public final class FXUtils {
|
||||
*
|
||||
* @param comboBox the combo box being bound with the property which can be inferred by {@code bindEnum}.
|
||||
* @see #bindEnum(JFXComboBox, Property)
|
||||
* @deprecated Use {@link ExtendedProperties#selectedItemPropertyFor(ComboBox)}
|
||||
* @see ExtendedProperties#selectedItemPropertyFor(ComboBox)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
public static void unbindEnum(JFXComboBox<?> comboBox) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ChangeListener listener = tryCast(comboBox.getProperties().get("FXUtils.bindEnum.listener"), ChangeListener.class).orElse(null);
|
||||
if (listener == null) return;
|
||||
comboBox.getSelectionModel().selectedIndexProperty().removeListener(listener);
|
||||
public static void unbindEnum(JFXComboBox<? extends Enum<?>> comboBox) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ChangeListener<Number> listener = (ChangeListener<Number>) comboBox.getProperties().remove("FXUtils.bindEnum.listener");
|
||||
if (listener != null)
|
||||
comboBox.getSelectionModel().selectedIndexProperty().removeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,7 @@ import javafx.scene.Node;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
@@ -72,6 +73,7 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
public class GameCrashWindow extends Stage {
|
||||
private final Version version;
|
||||
private final String memory;
|
||||
private final String total_memory;
|
||||
private final String java;
|
||||
private final LibraryAnalyzer analyzer;
|
||||
private final StringProperty os = new SimpleStringProperty(OperatingSystem.SYSTEM_NAME);
|
||||
@@ -99,6 +101,8 @@ public class GameCrashWindow extends Stage {
|
||||
|
||||
memory = Optional.ofNullable(launchOptions.getMaxMemory()).map(i -> i + " MB").orElse("-");
|
||||
|
||||
total_memory = Optional.ofNullable(OperatingSystem.TOTAL_MEMORY).map(i -> i + " MB").orElse("-");
|
||||
|
||||
this.java = launchOptions.getJava().getArchitecture() == Architecture.SYSTEM_ARCH
|
||||
? launchOptions.getJava().getVersion()
|
||||
: launchOptions.getJava().getVersion() + " (" + launchOptions.getJava().getArchitecture().getDisplayName() + ")";
|
||||
@@ -291,6 +295,11 @@ public class GameCrashWindow extends Stage {
|
||||
version.setTitle(i18n("archive.game_version"));
|
||||
version.setSubtitle(GameCrashWindow.this.version.getId());
|
||||
|
||||
TwoLineListItem total_memory = new TwoLineListItem();
|
||||
total_memory.getStyleClass().setAll("two-line-item-second-large");
|
||||
total_memory.setTitle(i18n("settings.physical_memory"));
|
||||
total_memory.setSubtitle(GameCrashWindow.this.total_memory);
|
||||
|
||||
TwoLineListItem memory = new TwoLineListItem();
|
||||
memory.getStyleClass().setAll("two-line-item-second-large");
|
||||
memory.setTitle(i18n("settings.memory"));
|
||||
@@ -311,7 +320,7 @@ public class GameCrashWindow extends Stage {
|
||||
arch.setTitle(i18n("system.architecture"));
|
||||
arch.subtitleProperty().bind(GameCrashWindow.this.arch);
|
||||
|
||||
infoPane.getChildren().setAll(launcher, version, memory, java, os, arch);
|
||||
infoPane.getChildren().setAll(launcher, version, total_memory, memory, java, os, arch);
|
||||
}
|
||||
|
||||
HBox moddedPane = new HBox(8);
|
||||
@@ -347,9 +356,20 @@ public class GameCrashWindow extends Stage {
|
||||
Label reasonTitle = new Label(i18n("game.crash.reason"));
|
||||
reasonTitle.getStyleClass().add("two-line-item-second-large-title");
|
||||
|
||||
ScrollPane reasonPane = new ScrollPane(reasonTextFlow);
|
||||
reasonPane.setFitToWidth(true);
|
||||
reasonPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
||||
reasonPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
||||
|
||||
gameDirPane.setPadding(new Insets(8));
|
||||
VBox.setVgrow(gameDirPane, Priority.ALWAYS);
|
||||
gameDirPane.getChildren().setAll(gameDir, javaDir, new VBox(reasonTitle, reasonTextFlow, feedbackTextFlow));
|
||||
FXUtils.onChangeAndOperate(feedbackTextFlow.visibleProperty(), visible -> {
|
||||
if (visible) {
|
||||
gameDirPane.getChildren().setAll(gameDir, javaDir, new VBox(reasonTitle, reasonPane, feedbackTextFlow));
|
||||
} else {
|
||||
gameDirPane.getChildren().setAll(gameDir, javaDir, new VBox(reasonTitle, reasonPane));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
HBox toolBar = new HBox();
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.jackhuang.hmcl.ui.construct.SpinnerPane;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.io.NetworkUtils;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@@ -162,7 +163,9 @@ public final class AddAuthlibInjectorServerPane extends TransitionPane implement
|
||||
}
|
||||
|
||||
private String resolveFetchExceptionMessage(Throwable exception) {
|
||||
if (exception instanceof IOException) {
|
||||
if (exception instanceof SSLException) {
|
||||
return i18n("account.failed.ssl");
|
||||
} else if (exception instanceof IOException) {
|
||||
return i18n("account.failed.connect_injector_server");
|
||||
} else {
|
||||
return exception.getClass().getName() + ": " + exception.getLocalizedMessage();
|
||||
|
||||
@@ -36,7 +36,6 @@ import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilService;
|
||||
import org.jackhuang.hmcl.setting.Accounts;
|
||||
import org.jackhuang.hmcl.task.Schedulers;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.ui.FXUtils;
|
||||
import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
|
||||
import org.jackhuang.hmcl.ui.construct.JFXHyperlink;
|
||||
import org.jackhuang.hmcl.ui.construct.RequiredValidator;
|
||||
@@ -91,10 +90,10 @@ public class ClassicAccountLoginDialog extends StackPane {
|
||||
body.getChildren().add(linkPane);
|
||||
|
||||
JFXHyperlink migrationLink = new JFXHyperlink(i18n("account.methods.yggdrasil.migration"));
|
||||
migrationLink.setOnAction(e -> FXUtils.openLink(YggdrasilService.PROFILE_URL));
|
||||
migrationLink.setExternalLink(YggdrasilService.PROFILE_URL);
|
||||
|
||||
JFXHyperlink migrationHowLink = new JFXHyperlink(i18n("account.methods.yggdrasil.migration.how"));
|
||||
migrationHowLink.setOnAction(e -> FXUtils.openLink(YggdrasilService.MIGRATION_FAQ_URL));
|
||||
migrationHowLink.setExternalLink(YggdrasilService.MIGRATION_FAQ_URL);
|
||||
|
||||
linkPane.getChildren().setAll(migrationLink, migrationHowLink);
|
||||
}
|
||||
|
||||
@@ -512,13 +512,13 @@ public class CreateAccountPane extends JFXDialogLayout implements DialogAware {
|
||||
GridPane.setColumnSpan(box, 2);
|
||||
|
||||
JFXHyperlink migrationLink = new JFXHyperlink(i18n("account.methods.yggdrasil.migration"));
|
||||
migrationLink.setOnAction(e -> FXUtils.openLink("https://aka.ms/MinecraftMigration"));
|
||||
migrationLink.setExternalLink("https://aka.ms/MinecraftMigration");
|
||||
|
||||
JFXHyperlink migrationHowLink = new JFXHyperlink(i18n("account.methods.yggdrasil.migration.how"));
|
||||
migrationHowLink.setOnAction(e -> FXUtils.openLink("https://help.minecraft.net/hc/articles/4411173197709"));
|
||||
migrationHowLink.setExternalLink("https://help.minecraft.net/hc/articles/4411173197709");
|
||||
|
||||
JFXHyperlink purchaseLink = new JFXHyperlink(i18n("account.methods.yggdrasil.purchase"));
|
||||
purchaseLink.setOnAction(e -> FXUtils.openLink(YggdrasilService.PURCHASE_URL));
|
||||
purchaseLink.setExternalLink(YggdrasilService.PURCHASE_URL);
|
||||
|
||||
box.getChildren().setAll(migrationLink, migrationHowLink, purchaseLink);
|
||||
add(box, 0, rowIndex);
|
||||
@@ -530,7 +530,7 @@ public class CreateAccountPane extends JFXDialogLayout implements DialogAware {
|
||||
txtUsername.setPromptText(i18n("account.methods.offline.name.special_characters"));
|
||||
|
||||
JFXHyperlink purchaseLink = new JFXHyperlink(i18n("account.methods.yggdrasil.purchase"));
|
||||
purchaseLink.setOnAction(e -> FXUtils.openLink(YggdrasilService.PURCHASE_URL));
|
||||
purchaseLink.setExternalLink(YggdrasilService.PURCHASE_URL);
|
||||
HBox linkPane = new HBox(purchaseLink);
|
||||
GridPane.setColumnSpan(linkPane, 2);
|
||||
add(linkPane, 0, rowIndex);
|
||||
|
||||
@@ -38,7 +38,8 @@ import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
import org.jackhuang.hmcl.util.javafx.MappedObservableList;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@DefaultProperty("content")
|
||||
public class ComponentList extends Control {
|
||||
@@ -47,13 +48,17 @@ public class ComponentList extends Control {
|
||||
private final IntegerProperty depth = new SimpleIntegerProperty(this, "depth", 0);
|
||||
private boolean hasSubtitle = false;
|
||||
public final ObservableList<Node> content = FXCollections.observableArrayList();
|
||||
private boolean expanded = false;
|
||||
private Consumer<ComponentList> lazyInitializer;
|
||||
private Supplier<List<? extends Node>> lazyInitializer;
|
||||
|
||||
public ComponentList() {
|
||||
getStyleClass().add("options-list");
|
||||
}
|
||||
|
||||
public ComponentList(Supplier<List<? extends Node>> lazyInitializer) {
|
||||
this();
|
||||
this.lazyInitializer = lazyInitializer;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title.get();
|
||||
}
|
||||
@@ -102,17 +107,12 @@ public class ComponentList extends Control {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setLazyInitializer(Consumer<ComponentList> lazyInitializer) {
|
||||
this.lazyInitializer = lazyInitializer;
|
||||
}
|
||||
|
||||
public void onExpand() {
|
||||
if (!expanded && lazyInitializer != null) {
|
||||
lazyInitializer.accept(this);
|
||||
void doLazyInit() {
|
||||
if (lazyInitializer != null) {
|
||||
this.getContent().setAll(lazyInitializer.get());
|
||||
setNeedsLayout(true);
|
||||
lazyInitializer = null;
|
||||
}
|
||||
|
||||
expanded = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -125,7 +125,7 @@ public class ComponentList extends Control {
|
||||
return new Skin(this);
|
||||
}
|
||||
|
||||
protected static class Skin extends ControlSkinBase<ComponentList> {
|
||||
private static final class Skin extends ControlSkinBase<ComponentList> {
|
||||
private static final PseudoClass PSEUDO_CLASS_FIRST = PseudoClass.getPseudoClass("first");
|
||||
private static final PseudoClass PSEUDO_CLASS_LAST = PseudoClass.getPseudoClass("last");
|
||||
|
||||
@@ -133,7 +133,7 @@ public class ComponentList extends Control {
|
||||
private final ObjectBinding<Node> firstItem;
|
||||
private final ObjectBinding<Node> lastItem;
|
||||
|
||||
protected Skin(ComponentList control) {
|
||||
Skin(ComponentList control) {
|
||||
super(control);
|
||||
|
||||
list = MappedObservableList.create(control.getContent(), node -> {
|
||||
|
||||
@@ -43,7 +43,7 @@ import org.jackhuang.hmcl.ui.animation.AnimationUtils;
|
||||
/**
|
||||
* @author huangyuhui
|
||||
*/
|
||||
class ComponentListCell extends StackPane {
|
||||
final class ComponentListCell extends StackPane {
|
||||
private final Node content;
|
||||
private Animation expandAnimation;
|
||||
private Rectangle clipRect;
|
||||
@@ -139,69 +139,53 @@ class ComponentListCell extends StackPane {
|
||||
container.getChildren().setAll(content);
|
||||
groupNode.getChildren().add(container);
|
||||
|
||||
EventHandler<Event> onExpand;
|
||||
if (AnimationUtils.isAnimationEnabled()) {
|
||||
onExpand = e -> {
|
||||
if (expandAnimation != null && expandAnimation.getStatus() == Animation.Status.RUNNING) {
|
||||
expandAnimation.stop();
|
||||
EventHandler<Event> onExpand = e -> {
|
||||
if (expandAnimation != null && expandAnimation.getStatus() == Animation.Status.RUNNING) {
|
||||
expandAnimation.stop();
|
||||
}
|
||||
|
||||
boolean expanded = !isExpanded();
|
||||
setExpanded(expanded);
|
||||
if (expanded) {
|
||||
list.doLazyInit();
|
||||
list.layout();
|
||||
}
|
||||
|
||||
Platform.runLater(() -> {
|
||||
double newAnimatedHeight = (list.prefHeight(-1) + 8 + 10) * (expanded ? 1 : -1);
|
||||
double newHeight = expanded ? getHeight() + newAnimatedHeight : prefHeight(-1);
|
||||
double contentHeight = expanded ? newAnimatedHeight : 0;
|
||||
|
||||
if (expanded) {
|
||||
updateClip(newHeight);
|
||||
}
|
||||
|
||||
setExpanded(!isExpanded());
|
||||
|
||||
if (isExpanded()) {
|
||||
list.onExpand();
|
||||
list.layout();
|
||||
}
|
||||
|
||||
Platform.runLater(() -> {
|
||||
double newAnimatedHeight = (content.prefHeight(-1) + 8 + 10) * (isExpanded() ? 1 : -1);
|
||||
double newHeight = isExpanded() ? getHeight() + newAnimatedHeight : prefHeight(-1);
|
||||
double contentHeight = isExpanded() ? newAnimatedHeight : 0;
|
||||
|
||||
if (isExpanded()) {
|
||||
updateClip(newHeight);
|
||||
}
|
||||
|
||||
if (AnimationUtils.isAnimationEnabled()) {
|
||||
expandAnimation = new Timeline(new KeyFrame(new Duration(320.0),
|
||||
new KeyValue(container.minHeightProperty(), contentHeight, FXUtils.SINE),
|
||||
new KeyValue(container.maxHeightProperty(), contentHeight, FXUtils.SINE)
|
||||
));
|
||||
|
||||
if (!isExpanded()) {
|
||||
if (!expanded) {
|
||||
expandAnimation.setOnFinished(e2 -> updateClip(newHeight));
|
||||
}
|
||||
|
||||
expandAnimation.play();
|
||||
});
|
||||
};
|
||||
} else {
|
||||
onExpand = e -> {
|
||||
setExpanded(!isExpanded());
|
||||
} else {
|
||||
container.setMinHeight(contentHeight);
|
||||
container.setMaxHeight(contentHeight);
|
||||
|
||||
double newAnimatedHeight = (content.prefHeight(-1) + 8 + 10) * (isExpanded() ? 1 : -1);
|
||||
double newHeight = isExpanded() ? getHeight() + newAnimatedHeight : prefHeight(-1);
|
||||
double contentHeight = isExpanded() ? newAnimatedHeight : 0;
|
||||
|
||||
if (isExpanded()) {
|
||||
list.onExpand();
|
||||
list.layout();
|
||||
updateClip(newHeight);
|
||||
if (!expanded) {
|
||||
updateClip(newHeight);
|
||||
}
|
||||
}
|
||||
|
||||
container.setMinHeight(contentHeight);
|
||||
container.setMaxHeight(contentHeight);
|
||||
|
||||
if (!isExpanded()) {
|
||||
updateClip(newHeight);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
headerRippler.setOnMouseClicked(onExpand);
|
||||
expandButton.setOnAction((EventHandler<ActionEvent>) (Object) onExpand);
|
||||
|
||||
expandedProperty().addListener((a, b, newValue) ->
|
||||
expandIcon.setRotate(newValue ? 180 : 0));
|
||||
expandedProperty().addListener((a, b, newValue) -> expandIcon.setRotate(newValue ? 180 : 0));
|
||||
|
||||
getChildren().setAll(groupNode);
|
||||
} else {
|
||||
|
||||
@@ -39,6 +39,7 @@ import javafx.util.Duration;
|
||||
import org.jackhuang.hmcl.ui.FXUtils;
|
||||
import org.jackhuang.hmcl.util.javafx.MappedObservableList;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class TabHeader extends Control implements TabControl, PageAware {
|
||||
|
||||
public TabHeader(Tab<?>... tabs) {
|
||||
|
||||
@@ -88,7 +88,9 @@ public class TaskExecutorDialogPane extends BorderPane {
|
||||
|
||||
btnCancel.setOnAction(e -> {
|
||||
Optional.ofNullable(executor).ifPresent(TaskExecutor::cancel);
|
||||
onCancel.getCancellationAction().accept(this);
|
||||
if (onCancel.getCancellationAction() != null) {
|
||||
onCancel.getCancellationAction().accept(this);
|
||||
}
|
||||
});
|
||||
|
||||
speedEventHandler = speedEvent -> {
|
||||
|
||||
@@ -33,6 +33,7 @@ import javafx.scene.control.Label;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
@@ -71,6 +72,8 @@ import static org.jackhuang.hmcl.ui.FXUtils.SINE;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
public final class MainPage extends StackPane implements DecoratorPage {
|
||||
private static final String ANNOUNCEMENT = "announcement";
|
||||
|
||||
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>();
|
||||
|
||||
private final PopupMenu menu = new PopupMenu();
|
||||
@@ -83,7 +86,7 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
private final ObservableList<Node> versionNodes;
|
||||
private Profile profile;
|
||||
|
||||
private final VBox announcementPane;
|
||||
private VBox announcementPane;
|
||||
private final StackPane updatePane;
|
||||
private final JFXButton menuButton;
|
||||
|
||||
@@ -112,7 +115,15 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
|
||||
setPadding(new Insets(20));
|
||||
|
||||
announcementPane = new VBox(16);
|
||||
if (Metadata.isNightly() || (Metadata.isDev() && !Objects.equals(Metadata.VERSION, config().getShownTips().get(ANNOUNCEMENT)))) {
|
||||
announcementPane = new VBox(16);
|
||||
if (Metadata.isNightly()) {
|
||||
announcementPane.getChildren().add(new AnnouncementCard(i18n("update.channel.nightly.title"), i18n("update.channel.nightly.hint")));
|
||||
} else if (Metadata.isDev()) {
|
||||
announcementPane.getChildren().add(new AnnouncementCard(i18n("update.channel.dev.title"), i18n("update.channel.dev.hint")));
|
||||
}
|
||||
getChildren().add(announcementPane);
|
||||
}
|
||||
|
||||
updatePane = new StackPane();
|
||||
updatePane.setVisible(false);
|
||||
@@ -221,7 +232,7 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
launchPane.getChildren().setAll(launchButton, separator, menuButton);
|
||||
}
|
||||
|
||||
getChildren().setAll(announcementPane, updatePane, launchPane);
|
||||
getChildren().addAll(updatePane, launchPane);
|
||||
|
||||
menu.setMaxHeight(365);
|
||||
menu.setMaxWidth(545);
|
||||
@@ -235,14 +246,6 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
Bindings.bindContent(menu.getContent(), versionNodes);
|
||||
}
|
||||
|
||||
public MainPage() {
|
||||
if (Metadata.isNightly()) {
|
||||
announcementPane.getChildren().add(new AnnouncementCard(i18n("update.channel.nightly.title"), i18n("update.channel.nightly.hint")));
|
||||
} else if (Metadata.isDev()) {
|
||||
announcementPane.getChildren().add(new AnnouncementCard(i18n("update.channel.dev.title"), i18n("update.channel.dev.hint")));
|
||||
}
|
||||
}
|
||||
|
||||
private void showUpdate(boolean show) {
|
||||
doAnimation(show);
|
||||
|
||||
@@ -294,6 +297,16 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
showUpdate.set(false);
|
||||
}
|
||||
|
||||
public void hideAnnouncementPane() {
|
||||
if (announcementPane != null) {
|
||||
config().getShownTips().put(ANNOUNCEMENT, Metadata.VERSION);
|
||||
Pane parent = (Pane) announcementPane.getParent();
|
||||
if (parent != null)
|
||||
parent.getChildren().remove(announcementPane);
|
||||
announcementPane = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadOnlyObjectWrapper<State> stateProperty() {
|
||||
return state;
|
||||
|
||||
@@ -82,7 +82,7 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
|
||||
return new Skin(this);
|
||||
}
|
||||
|
||||
private MainPage getMainPage() {
|
||||
public MainPage getMainPage() {
|
||||
if (mainPage == null) {
|
||||
MainPage mainPage = new MainPage();
|
||||
FXUtils.applyDragListener(mainPage, ModpackHelper::isFileModpackByExtension, modpacks -> {
|
||||
@@ -157,7 +157,7 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
|
||||
multiplayerItem.setActionButtonVisible(false);
|
||||
multiplayerItem.setTitle(i18n("multiplayer"));
|
||||
JFXHyperlink link = new JFXHyperlink(i18n("multiplayer.hint.details"));
|
||||
link.setOnAction(e -> FXUtils.openLink("https://hmcl.huangyuhui.net/api/redirect/multiplayer-migrate"));
|
||||
link.setExternalLink("https://hmcl.huangyuhui.net/api/redirect/multiplayer-migrate");
|
||||
multiplayerItem.setOnAction(e -> Controllers.dialog(
|
||||
new MessageDialogPane.Builder(i18n("multiplayer.hint"), null, MessageDialogPane.MessageType.INFO)
|
||||
.addAction(link)
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
package org.jackhuang.hmcl.ui.versions;
|
||||
|
||||
import com.jfoenix.controls.JFXComboBox;
|
||||
import com.jfoenix.controls.JFXTextField;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.layout.*;
|
||||
import org.jackhuang.hmcl.game.NativesDirectoryType;
|
||||
import org.jackhuang.hmcl.setting.Profile;
|
||||
import org.jackhuang.hmcl.game.Renderer;
|
||||
import org.jackhuang.hmcl.setting.VersionSetting;
|
||||
import org.jackhuang.hmcl.ui.FXUtils;
|
||||
import org.jackhuang.hmcl.ui.construct.*;
|
||||
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.stringConverter;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
public final class AdvancedVersionSettingPage extends StackPane implements DecoratorPage {
|
||||
|
||||
private final ObjectProperty<State> stateProperty;
|
||||
|
||||
private final Profile profile;
|
||||
private final String versionId;
|
||||
private final VersionSetting versionSetting;
|
||||
|
||||
private final JFXTextField txtJVMArgs;
|
||||
private final JFXTextField txtGameArgs;
|
||||
private final JFXTextField txtEnvironmentVariables;
|
||||
private final JFXTextField txtMetaspace;
|
||||
private final JFXTextField txtWrapper;
|
||||
private final JFXTextField txtPreLaunchCommand;
|
||||
private final JFXTextField txtPostExitCommand;
|
||||
private final OptionToggleButton noJVMArgsPane;
|
||||
private final OptionToggleButton noGameCheckPane;
|
||||
private final OptionToggleButton noJVMCheckPane;
|
||||
private final OptionToggleButton noNativesPatchPane;
|
||||
private final OptionToggleButton useNativeGLFWPane;
|
||||
private final OptionToggleButton useNativeOpenALPane;
|
||||
private final ComponentSublist nativesDirSublist;
|
||||
private final MultiFileItem<NativesDirectoryType> nativesDirItem;
|
||||
private final MultiFileItem.FileOption<NativesDirectoryType> nativesDirCustomOption;
|
||||
private final JFXComboBox<Renderer> cboRenderer;
|
||||
|
||||
public AdvancedVersionSettingPage(Profile profile, String versionId, VersionSetting versionSetting) {
|
||||
this.profile = profile;
|
||||
this.versionId = versionId;
|
||||
this.versionSetting = versionSetting;
|
||||
this.stateProperty = new SimpleObjectProperty<>(State.fromTitle(
|
||||
versionId == null ? i18n("settings.advanced") : i18n("settings.advanced.title", versionId)
|
||||
));
|
||||
|
||||
ScrollPane scrollPane = new ScrollPane();
|
||||
scrollPane.setFitToHeight(true);
|
||||
scrollPane.setFitToWidth(true);
|
||||
scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
|
||||
getChildren().setAll(scrollPane);
|
||||
|
||||
VBox rootPane = new VBox();
|
||||
rootPane.setFillWidth(true);
|
||||
scrollPane.setContent(rootPane);
|
||||
FXUtils.smoothScrolling(scrollPane);
|
||||
rootPane.getStyleClass().add("card-list");
|
||||
|
||||
ComponentList customCommandsPane = new ComponentList();
|
||||
{
|
||||
GridPane pane = new GridPane();
|
||||
pane.setHgap(16);
|
||||
pane.setVgap(8);
|
||||
pane.getColumnConstraints().setAll(new ColumnConstraints(), FXUtils.getColumnHgrowing());
|
||||
|
||||
txtGameArgs = new JFXTextField();
|
||||
txtGameArgs.setPromptText(i18n("settings.advanced.minecraft_arguments.prompt"));
|
||||
txtGameArgs.getStyleClass().add("fit-width");
|
||||
pane.addRow(0, new Label(i18n("settings.advanced.minecraft_arguments")), txtGameArgs);
|
||||
|
||||
txtPreLaunchCommand = new JFXTextField();
|
||||
txtPreLaunchCommand.setPromptText(i18n("settings.advanced.precall_command.prompt"));
|
||||
txtPreLaunchCommand.getStyleClass().add("fit-width");
|
||||
pane.addRow(1, new Label(i18n("settings.advanced.precall_command")), txtPreLaunchCommand);
|
||||
|
||||
txtWrapper = new JFXTextField();
|
||||
txtWrapper.setPromptText(i18n("settings.advanced.wrapper_launcher.prompt"));
|
||||
txtWrapper.getStyleClass().add("fit-width");
|
||||
pane.addRow(2, new Label(i18n("settings.advanced.wrapper_launcher")), txtWrapper);
|
||||
|
||||
txtPostExitCommand = new JFXTextField();
|
||||
txtPostExitCommand.setPromptText(i18n("settings.advanced.post_exit_command.prompt"));
|
||||
txtPostExitCommand.getStyleClass().add("fit-width");
|
||||
pane.addRow(3, new Label(i18n("settings.advanced.post_exit_command")), txtPostExitCommand);
|
||||
|
||||
HintPane hintPane = new HintPane();
|
||||
hintPane.setText(i18n("settings.advanced.custom_commands.hint"));
|
||||
GridPane.setColumnSpan(hintPane, 2);
|
||||
pane.addRow(4, hintPane);
|
||||
|
||||
customCommandsPane.getContent().setAll(pane);
|
||||
}
|
||||
|
||||
ComponentList jvmPane = new ComponentList();
|
||||
{
|
||||
GridPane pane = new GridPane();
|
||||
ColumnConstraints title = new ColumnConstraints();
|
||||
ColumnConstraints value = new ColumnConstraints();
|
||||
value.setFillWidth(true);
|
||||
value.setHgrow(Priority.ALWAYS);
|
||||
pane.setHgap(16);
|
||||
pane.setVgap(8);
|
||||
pane.getColumnConstraints().setAll(title, value);
|
||||
|
||||
txtJVMArgs = new JFXTextField();
|
||||
txtJVMArgs.getStyleClass().add("fit-width");
|
||||
pane.addRow(0, new Label(i18n("settings.advanced.jvm_args")), txtJVMArgs);
|
||||
|
||||
HintPane hintPane = new HintPane();
|
||||
hintPane.setText(i18n("settings.advanced.jvm_args.prompt"));
|
||||
GridPane.setColumnSpan(hintPane, 2);
|
||||
pane.addRow(4, hintPane);
|
||||
|
||||
txtMetaspace = new JFXTextField();
|
||||
txtMetaspace.setPromptText(i18n("settings.advanced.java_permanent_generation_space.prompt"));
|
||||
txtMetaspace.getStyleClass().add("fit-width");
|
||||
FXUtils.setValidateWhileTextChanged(txtMetaspace, true);
|
||||
txtMetaspace.setValidators(new NumberValidator(i18n("input.number"), true));
|
||||
pane.addRow(1, new Label(i18n("settings.advanced.java_permanent_generation_space")), txtMetaspace);
|
||||
|
||||
txtEnvironmentVariables = new JFXTextField();
|
||||
txtEnvironmentVariables.getStyleClass().add("fit-width");
|
||||
pane.addRow(2, new Label(i18n("settings.advanced.environment_variables")), txtEnvironmentVariables);
|
||||
|
||||
jvmPane.getContent().setAll(pane);
|
||||
}
|
||||
|
||||
ComponentList workaroundPane = new ComponentList();
|
||||
|
||||
HintPane workaroundWarning = new HintPane(MessageDialogPane.MessageType.WARNING);
|
||||
workaroundWarning.setText(i18n("settings.advanced.workaround.warning"));
|
||||
|
||||
{
|
||||
nativesDirItem = new MultiFileItem<>();
|
||||
nativesDirSublist = new ComponentSublist();
|
||||
nativesDirSublist.getContent().add(nativesDirItem);
|
||||
nativesDirSublist.setTitle(i18n("settings.advanced.natives_directory"));
|
||||
nativesDirSublist.setHasSubtitle(true);
|
||||
nativesDirCustomOption = new MultiFileItem.FileOption<>(i18n("settings.advanced.natives_directory.custom"), NativesDirectoryType.CUSTOM)
|
||||
.setChooserTitle(i18n("settings.advanced.natives_directory.choose"))
|
||||
.setDirectory(true);
|
||||
nativesDirItem.loadChildren(Arrays.asList(
|
||||
new MultiFileItem.Option<>(i18n("settings.advanced.natives_directory.default"), NativesDirectoryType.VERSION_FOLDER),
|
||||
nativesDirCustomOption
|
||||
));
|
||||
HintPane nativesDirHint = new HintPane(MessageDialogPane.MessageType.WARNING);
|
||||
nativesDirHint.setText(i18n("settings.advanced.natives_directory.hint"));
|
||||
nativesDirItem.getChildren().add(nativesDirHint);
|
||||
|
||||
BorderPane rendererPane = new BorderPane();
|
||||
{
|
||||
Label label = new Label(i18n("settings.advanced.renderer"));
|
||||
rendererPane.setLeft(label);
|
||||
BorderPane.setAlignment(label, Pos.CENTER_LEFT);
|
||||
|
||||
cboRenderer = new JFXComboBox<>();
|
||||
cboRenderer.getItems().setAll(Renderer.values());
|
||||
cboRenderer.setConverter(stringConverter(e -> i18n("settings.advanced.renderer." + e.name().toLowerCase(Locale.ROOT))));
|
||||
rendererPane.setRight(cboRenderer);
|
||||
BorderPane.setAlignment(cboRenderer, Pos.CENTER_RIGHT);
|
||||
FXUtils.setLimitWidth(cboRenderer, 300);
|
||||
}
|
||||
|
||||
noJVMArgsPane = new OptionToggleButton();
|
||||
noJVMArgsPane.setTitle(i18n("settings.advanced.no_jvm_args"));
|
||||
|
||||
noGameCheckPane = new OptionToggleButton();
|
||||
noGameCheckPane.setTitle(i18n("settings.advanced.dont_check_game_completeness"));
|
||||
|
||||
noJVMCheckPane = new OptionToggleButton();
|
||||
noJVMCheckPane.setTitle(i18n("settings.advanced.dont_check_jvm_validity"));
|
||||
|
||||
noNativesPatchPane = new OptionToggleButton();
|
||||
noNativesPatchPane.setTitle(i18n("settings.advanced.dont_patch_natives"));
|
||||
|
||||
useNativeGLFWPane = new OptionToggleButton();
|
||||
useNativeGLFWPane.setTitle(i18n("settings.advanced.use_native_glfw"));
|
||||
|
||||
useNativeOpenALPane = new OptionToggleButton();
|
||||
useNativeOpenALPane.setTitle(i18n("settings.advanced.use_native_openal"));
|
||||
|
||||
workaroundPane.getContent().setAll(
|
||||
nativesDirSublist, rendererPane,
|
||||
noJVMArgsPane, noGameCheckPane, noJVMCheckPane, noNativesPatchPane,
|
||||
useNativeGLFWPane, useNativeOpenALPane);
|
||||
}
|
||||
|
||||
rootPane.getChildren().addAll(
|
||||
ComponentList.createComponentListTitle(i18n("settings.advanced.custom_commands")), customCommandsPane,
|
||||
ComponentList.createComponentListTitle(i18n("settings.advanced.jvm")), jvmPane,
|
||||
ComponentList.createComponentListTitle(i18n("settings.advanced.workaround")), workaroundWarning, workaroundPane
|
||||
);
|
||||
|
||||
bindProperties();
|
||||
}
|
||||
|
||||
void bindProperties() {
|
||||
nativesDirCustomOption.bindBidirectional(versionSetting.nativesDirProperty());
|
||||
FXUtils.bindString(txtJVMArgs, versionSetting.javaArgsProperty());
|
||||
FXUtils.bindString(txtGameArgs, versionSetting.minecraftArgsProperty());
|
||||
FXUtils.bindString(txtMetaspace, versionSetting.permSizeProperty());
|
||||
FXUtils.bindString(txtEnvironmentVariables, versionSetting.environmentVariablesProperty());
|
||||
FXUtils.bindString(txtWrapper, versionSetting.wrapperProperty());
|
||||
FXUtils.bindString(txtPreLaunchCommand, versionSetting.preLaunchCommandProperty());
|
||||
FXUtils.bindEnum(cboRenderer, versionSetting.rendererProperty());
|
||||
noGameCheckPane.selectedProperty().bindBidirectional(versionSetting.notCheckGameProperty());
|
||||
noJVMCheckPane.selectedProperty().bindBidirectional(versionSetting.notCheckJVMProperty());
|
||||
noJVMArgsPane.selectedProperty().bindBidirectional(versionSetting.noJVMArgsProperty());
|
||||
noNativesPatchPane.selectedProperty().bindBidirectional(versionSetting.notPatchNativesProperty());
|
||||
useNativeGLFWPane.selectedProperty().bindBidirectional(versionSetting.useNativeGLFWProperty());
|
||||
useNativeOpenALPane.selectedProperty().bindBidirectional(versionSetting.useNativeOpenALProperty());
|
||||
|
||||
nativesDirItem.selectedDataProperty().bindBidirectional(versionSetting.nativesDirTypeProperty());
|
||||
nativesDirSublist.subtitleProperty().bind(Bindings.createStringBinding(() -> Paths.get(profile.getRepository().getRunDirectory(versionId).getAbsolutePath() + "/natives").normalize().toString(),
|
||||
versionSetting.nativesDirProperty(), versionSetting.nativesDirTypeProperty()));
|
||||
}
|
||||
|
||||
void unbindProperties() {
|
||||
nativesDirCustomOption.valueProperty().unbindBidirectional(versionSetting.nativesDirProperty());
|
||||
FXUtils.unbind(txtJVMArgs, versionSetting.javaArgsProperty());
|
||||
FXUtils.unbind(txtGameArgs, versionSetting.minecraftArgsProperty());
|
||||
FXUtils.unbind(txtMetaspace, versionSetting.permSizeProperty());
|
||||
FXUtils.unbind(txtEnvironmentVariables, versionSetting.environmentVariablesProperty());
|
||||
FXUtils.unbind(txtWrapper, versionSetting.wrapperProperty());
|
||||
FXUtils.unbind(txtPreLaunchCommand, versionSetting.preLaunchCommandProperty());
|
||||
FXUtils.unbind(txtPostExitCommand, versionSetting.postExitCommandProperty());
|
||||
FXUtils.unbindEnum(cboRenderer);
|
||||
noGameCheckPane.selectedProperty().unbindBidirectional(versionSetting.notCheckGameProperty());
|
||||
noJVMCheckPane.selectedProperty().unbindBidirectional(versionSetting.notCheckJVMProperty());
|
||||
noJVMArgsPane.selectedProperty().unbindBidirectional(versionSetting.noJVMArgsProperty());
|
||||
noNativesPatchPane.selectedProperty().unbindBidirectional(versionSetting.notPatchNativesProperty());
|
||||
useNativeGLFWPane.selectedProperty().unbindBidirectional(versionSetting.useNativeGLFWProperty());
|
||||
useNativeOpenALPane.selectedProperty().unbindBidirectional(versionSetting.useNativeOpenALProperty());
|
||||
|
||||
nativesDirItem.selectedDataProperty().unbindBidirectional(versionSetting.nativesDirTypeProperty());
|
||||
nativesDirSublist.subtitleProperty().unbind();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadOnlyObjectProperty<State> stateProperty() {
|
||||
return stateProperty;
|
||||
}
|
||||
}
|
||||
@@ -260,18 +260,18 @@ public class DownloadPage extends Control implements DecoratorPage {
|
||||
|
||||
if (getSkinnable().mod != null) {
|
||||
JFXHyperlink openMcmodButton = new JFXHyperlink(i18n("mods.mcmod"));
|
||||
openMcmodButton.setOnAction(e -> FXUtils.openLink(getSkinnable().translations.getMcmodUrl(getSkinnable().mod)));
|
||||
openMcmodButton.setExternalLink(getSkinnable().translations.getMcmodUrl(getSkinnable().mod));
|
||||
descriptionPane.getChildren().add(openMcmodButton);
|
||||
|
||||
if (StringUtils.isNotBlank(getSkinnable().mod.getMcbbs())) {
|
||||
JFXHyperlink openMcbbsButton = new JFXHyperlink(i18n("mods.mcbbs"));
|
||||
openMcbbsButton.setOnAction(e -> FXUtils.openLink(ModManager.getMcbbsUrl(getSkinnable().mod.getMcbbs())));
|
||||
openMcbbsButton.setExternalLink(ModManager.getMcbbsUrl(getSkinnable().mod.getMcbbs()));
|
||||
descriptionPane.getChildren().add(openMcbbsButton);
|
||||
}
|
||||
}
|
||||
|
||||
JFXHyperlink openUrlButton = new JFXHyperlink(control.page.getLocalizedOfficialPage());
|
||||
openUrlButton.setOnAction(e -> FXUtils.openLink(getSkinnable().addon.getPageUrl()));
|
||||
openUrlButton.setExternalLink(getSkinnable().addon.getPageUrl());
|
||||
descriptionPane.getChildren().add(openUrlButton);
|
||||
}
|
||||
|
||||
@@ -322,12 +322,10 @@ public class DownloadPage extends Control implements DecoratorPage {
|
||||
for (String gameVersion : control.versions.keys().stream()
|
||||
.sorted(VersionNumber.VERSION_COMPARATOR.reversed())
|
||||
.collect(Collectors.toList())) {
|
||||
ComponentList sublist = new ComponentList();
|
||||
sublist.setLazyInitializer(self -> {
|
||||
self.getContent().setAll(control.versions.get(gameVersion).stream()
|
||||
.map(version -> new ModItem(version, control))
|
||||
.collect(Collectors.toList()));
|
||||
});
|
||||
ComponentList sublist = new ComponentList(() ->
|
||||
control.versions.get(gameVersion).stream()
|
||||
.map(version -> new ModItem(version, control))
|
||||
.collect(Collectors.toList()));
|
||||
sublist.getStyleClass().add("no-padding");
|
||||
sublist.setTitle(gameVersion);
|
||||
|
||||
@@ -369,6 +367,7 @@ public class DownloadPage extends Control implements DecoratorPage {
|
||||
}
|
||||
|
||||
private static final class ModItem extends StackPane {
|
||||
|
||||
ModItem(RemoteMod.Version dataItem, DownloadPage selfPage) {
|
||||
HBox pane = new HBox(8);
|
||||
pane.setPadding(new Insets(8));
|
||||
@@ -378,9 +377,7 @@ public class DownloadPage extends Control implements DecoratorPage {
|
||||
JFXButton saveAsButton = new JFXButton();
|
||||
|
||||
RipplerContainer container = new RipplerContainer(pane);
|
||||
container.setOnMouseClicked(e -> {
|
||||
selfPage.download(dataItem);
|
||||
});
|
||||
container.setOnMouseClicked(e -> selfPage.download(dataItem));
|
||||
getChildren().setAll(container);
|
||||
|
||||
saveAsButton.getStyleClass().add("toggle-icon4");
|
||||
@@ -391,7 +388,7 @@ public class DownloadPage extends Control implements DecoratorPage {
|
||||
|
||||
content.setTitle(dataItem.getName());
|
||||
content.setSubtitle(FORMATTER.format(dataItem.getDatePublished().toInstant()));
|
||||
saveAsButton.setOnMouseClicked(e -> selfPage.saveAs(dataItem));
|
||||
saveAsButton.setOnAction(e -> selfPage.saveAs(dataItem));
|
||||
|
||||
switch (dataItem.getVersionType()) {
|
||||
case Release:
|
||||
@@ -407,6 +404,9 @@ public class DownloadPage extends Control implements DecoratorPage {
|
||||
content.getTags().add(i18n("version.game.snapshot"));
|
||||
break;
|
||||
}
|
||||
|
||||
// Workaround for https://github.com/huanghongxun/HMCL/issues/2129
|
||||
this.setMinHeight(50);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -308,8 +308,7 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
||||
setBody(description);
|
||||
|
||||
if (StringUtils.isNotBlank(modInfo.getModInfo().getUrl())) {
|
||||
JFXHyperlink officialPageButton = new JFXHyperlink();
|
||||
officialPageButton.setText(i18n("mods.url"));
|
||||
JFXHyperlink officialPageButton = new JFXHyperlink(i18n("mods.url"));
|
||||
officialPageButton.setOnAction(e -> {
|
||||
fireEvent(new DialogCloseEvent());
|
||||
FXUtils.openLink(modInfo.getModInfo().getUrl());
|
||||
@@ -319,8 +318,7 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
||||
}
|
||||
|
||||
if (modInfo.getMod() != null && StringUtils.isNotBlank(modInfo.getMod().getMcbbs())) {
|
||||
JFXHyperlink mcbbsButton = new JFXHyperlink();
|
||||
mcbbsButton.setText(i18n("mods.mcbbs"));
|
||||
JFXHyperlink mcbbsButton = new JFXHyperlink(i18n("mods.mcbbs"));
|
||||
mcbbsButton.setOnAction(e -> {
|
||||
fireEvent(new DialogCloseEvent());
|
||||
FXUtils.openLink(ModManager.getMcbbsUrl(modInfo.getMod().getMcbbs()));
|
||||
@@ -329,8 +327,7 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
||||
}
|
||||
|
||||
if (modInfo.getMod() == null || StringUtils.isBlank(modInfo.getMod().getMcmod())) {
|
||||
JFXHyperlink searchButton = new JFXHyperlink();
|
||||
searchButton.setText(i18n("mods.mcmod.search"));
|
||||
JFXHyperlink searchButton = new JFXHyperlink(i18n("mods.mcmod.search"));
|
||||
searchButton.setOnAction(e -> {
|
||||
fireEvent(new DialogCloseEvent());
|
||||
FXUtils.openLink(NetworkUtils.withQuery("https://search.mcmod.cn/s", mapOf(
|
||||
@@ -341,8 +338,7 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
||||
});
|
||||
getActions().add(searchButton);
|
||||
} else {
|
||||
JFXHyperlink mcmodButton = new JFXHyperlink();
|
||||
mcmodButton.setText(i18n("mods.mcmod.page"));
|
||||
JFXHyperlink mcmodButton = new JFXHyperlink(i18n("mods.mcmod.page"));
|
||||
mcmodButton.setOnAction(e -> {
|
||||
fireEvent(new DialogCloseEvent());
|
||||
FXUtils.openLink(ModTranslations.MOD.getMcmodUrl(modInfo.getMod()));
|
||||
|
||||
@@ -163,6 +163,10 @@ public class VersionPage extends DecoratorAnimatedPage implements DecoratorPage
|
||||
FileUtils.deleteDirectoryQuietly(new File(getProfile().getRepository().getBaseDirectory(), "libraries"));
|
||||
}
|
||||
|
||||
private void clearAssets() {
|
||||
FileUtils.deleteDirectoryQuietly(new File(getProfile().getRepository().getBaseDirectory(), "assets"));
|
||||
}
|
||||
|
||||
private void clearJunkFiles() {
|
||||
Versions.cleanVersion(getProfile(), getVersion());
|
||||
}
|
||||
@@ -291,6 +295,7 @@ public class VersionPage extends DecoratorAnimatedPage implements DecoratorPage
|
||||
new IconedMenuItem(FXUtils.limitingSize(SVG.export(Theme.blackFillBinding(), 14, 14), 14, 14), i18n("modpack.export"), FXUtils.withJFXPopupClosing(control::export, managementPopup)),
|
||||
new MenuSeparator(),
|
||||
new IconedMenuItem(null, i18n("version.manage.redownload_assets_index"), FXUtils.withJFXPopupClosing(control::redownloadAssetIndex, managementPopup)),
|
||||
new IconedMenuItem(null, i18n("version.manage.remove_assets"), FXUtils.withJFXPopupClosing(control::clearAssets, managementPopup)),
|
||||
new IconedMenuItem(null, i18n("version.manage.remove_libraries"), FXUtils.withJFXPopupClosing(control::clearLibraries, managementPopup)),
|
||||
new IconedMenuItem(null, i18n("version.manage.clean"), FXUtils.withJFXPopupClosing(control::clearJunkFiles, managementPopup)).addTooltip(i18n("version.manage.clean.tooltip"))
|
||||
);
|
||||
|
||||
@@ -66,7 +66,7 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
public final class VersionSettingsPage extends StackPane implements DecoratorPage, VersionPage.VersionLoadable, PageAware {
|
||||
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>(new State("", null, false, false, false));
|
||||
|
||||
private final boolean globalSetting;
|
||||
private AdvancedVersionSettingPage advancedVersionSettingPage;
|
||||
|
||||
private VersionSetting lastVersionSetting = null;
|
||||
private Profile profile;
|
||||
@@ -77,24 +77,11 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
private final VBox rootPane;
|
||||
private final JFXTextField txtWidth;
|
||||
private final JFXTextField txtHeight;
|
||||
private final JFXTextField txtJVMArgs;
|
||||
private final JFXTextField txtGameArgs;
|
||||
private final JFXTextField txtMetaspace;
|
||||
private final JFXTextField txtWrapper;
|
||||
private final JFXTextField txtPreLaunchCommand;
|
||||
private final JFXTextField txtPostExitCommand;
|
||||
private final JFXTextField txtServerIP;
|
||||
private final ComponentList componentList;
|
||||
private final JFXComboBox<LauncherVisibility> cboLauncherVisibility;
|
||||
private final JFXCheckBox chkAutoAllocate;
|
||||
private final JFXCheckBox chkFullscreen;
|
||||
private final OptionToggleButton noJVMArgsPane;
|
||||
private final OptionToggleButton noGameCheckPane;
|
||||
private final OptionToggleButton noJVMCheckPane;
|
||||
private final OptionToggleButton noNativesPatchPane;
|
||||
private final OptionToggleButton useSoftwareRenderer;
|
||||
private final OptionToggleButton useNativeGLFWPane;
|
||||
private final OptionToggleButton useNativeOpenALPane;
|
||||
private final ComponentSublist javaSublist;
|
||||
private final MultiFileItem<Pair<JavaVersionType, JavaVersion>> javaItem;
|
||||
private final MultiFileItem.Option<Pair<JavaVersionType, JavaVersion>> javaAutoDeterminedOption;
|
||||
@@ -102,12 +89,9 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
private final ComponentSublist gameDirSublist;
|
||||
private final MultiFileItem<GameDirectoryType> gameDirItem;
|
||||
private final MultiFileItem.FileOption<GameDirectoryType> gameDirCustomOption;
|
||||
private final ComponentSublist nativesDirSublist;
|
||||
private final MultiFileItem<NativesDirectoryType> nativesDirItem;
|
||||
private final MultiFileItem.FileOption<NativesDirectoryType> nativesDirCustomOption;
|
||||
private final JFXComboBox<ProcessPriority> cboProcessPriority;
|
||||
private final OptionToggleButton showLogsPane;
|
||||
private ImagePickerItem iconPickerItem;
|
||||
private final ImagePickerItem iconPickerItem;
|
||||
|
||||
private final InvalidationListener specificSettingsListener;
|
||||
|
||||
@@ -121,8 +105,6 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
private final BooleanProperty modpack = new SimpleBooleanProperty();
|
||||
|
||||
public VersionSettingsPage(boolean globalSetting) {
|
||||
this.globalSetting = globalSetting;
|
||||
|
||||
ScrollPane scrollPane = new ScrollPane();
|
||||
scrollPane.setFitToHeight(true);
|
||||
scrollPane.setFitToWidth(true);
|
||||
@@ -145,18 +127,17 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
text.textProperty().bind(BindingMapping.of(selectedVersion)
|
||||
.map(selectedVersion -> i18n("settings.type.special.edit.hint", selectedVersion)));
|
||||
|
||||
JFXHyperlink specificSettingsLink = new JFXHyperlink();
|
||||
specificSettingsLink.setText(i18n("settings.type.special.edit"));
|
||||
specificSettingsLink.setOnMouseClicked(e -> editSpecificSettings());
|
||||
JFXHyperlink specificSettingsLink = new JFXHyperlink(i18n("settings.type.special.edit"));
|
||||
specificSettingsLink.setOnAction(e -> editSpecificSettings());
|
||||
|
||||
specificSettingsHint.setChildren(text, specificSettingsLink);
|
||||
specificSettingsHint.managedProperty().bind(navigateToSpecificSettings);
|
||||
specificSettingsHint.visibleProperty().bind(navigateToSpecificSettings);
|
||||
|
||||
rootPane.getChildren().addAll(specificSettingsHint);
|
||||
}
|
||||
iconPickerItem = null;
|
||||
|
||||
if (!globalSetting) {
|
||||
rootPane.getChildren().addAll(specificSettingsHint);
|
||||
} else {
|
||||
HintPane gameDirHint = new HintPane(MessageDialogPane.MessageType.INFO);
|
||||
gameDirHint.setText(i18n("settings.game.working_directory.hint"));
|
||||
rootPane.getChildren().add(gameDirHint);
|
||||
@@ -171,7 +152,6 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
iconPickerItem.setOnDeleteButtonClicked(e -> onDeleteIcon());
|
||||
iconPickerItemWrapper.getContent().setAll(iconPickerItem);
|
||||
|
||||
|
||||
BorderPane settingsTypePane = new BorderPane();
|
||||
settingsTypePane.disableProperty().bind(modpack);
|
||||
rootPane.getChildren().add(settingsTypePane);
|
||||
@@ -186,7 +166,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
settingsTypePane.setRight(editGlobalSettingsButton);
|
||||
editGlobalSettingsButton.disableProperty().bind(enableSpecificCheckBox.selectedProperty());
|
||||
BorderPane.setAlignment(editGlobalSettingsButton, Pos.CENTER_RIGHT);
|
||||
editGlobalSettingsButton.setOnMouseClicked(e -> editGlobalSettings());
|
||||
editGlobalSettingsButton.setOnAction(e -> editGlobalSettings());
|
||||
}
|
||||
|
||||
{
|
||||
@@ -401,146 +381,43 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
serverPane.addRow(0, new Label(i18n("settings.advanced.server_ip")), txtServerIP);
|
||||
}
|
||||
|
||||
componentList.getContent().setAll(javaSublist, gameDirSublist, maxMemoryPane, launcherVisibilityPane, dimensionPane, showLogsPane, processPriorityPane, serverPane);
|
||||
BorderPane showAdvancedSettingPane = new BorderPane();
|
||||
{
|
||||
Label label = new Label(i18n("settings.advanced"));
|
||||
showAdvancedSettingPane.setLeft(label);
|
||||
BorderPane.setAlignment(label, Pos.CENTER_LEFT);
|
||||
|
||||
JFXButton button = new JFXButton(i18n("settings.advanced.modify"));
|
||||
button.setOnAction(e -> {
|
||||
if (lastVersionSetting != null) {
|
||||
if (advancedVersionSettingPage == null)
|
||||
advancedVersionSettingPage = new AdvancedVersionSettingPage(profile, versionId, lastVersionSetting);
|
||||
|
||||
Controllers.navigate(advancedVersionSettingPage);
|
||||
}
|
||||
});
|
||||
button.getStyleClass().add("jfx-button-border");
|
||||
showAdvancedSettingPane.setRight(button);
|
||||
}
|
||||
|
||||
componentList.getContent().setAll(
|
||||
javaSublist,
|
||||
gameDirSublist,
|
||||
maxMemoryPane,
|
||||
launcherVisibilityPane,
|
||||
dimensionPane,
|
||||
showLogsPane,
|
||||
processPriorityPane,
|
||||
serverPane,
|
||||
showAdvancedSettingPane
|
||||
);
|
||||
}
|
||||
|
||||
HBox advancedHintPane = new HBox();
|
||||
advancedHintPane.setAlignment(Pos.CENTER);
|
||||
advancedHintPane.setPadding(new Insets(16, 0, 8, 0));
|
||||
{
|
||||
Label advanced = new Label(i18n("settings.advanced"));
|
||||
advanced.setStyle("-fx-font-size: 12px;");
|
||||
advancedHintPane.getChildren().setAll(advanced);
|
||||
}
|
||||
|
||||
ComponentList customCommandsPane = new ComponentList();
|
||||
customCommandsPane.disableProperty().bind(enableSpecificSettings.not());
|
||||
{
|
||||
GridPane pane = new GridPane();
|
||||
pane.setHgap(16);
|
||||
pane.setVgap(8);
|
||||
pane.getColumnConstraints().setAll(new ColumnConstraints(), FXUtils.getColumnHgrowing());
|
||||
|
||||
txtGameArgs = new JFXTextField();
|
||||
txtGameArgs.setPromptText(i18n("settings.advanced.minecraft_arguments.prompt"));
|
||||
txtGameArgs.getStyleClass().add("fit-width");
|
||||
pane.addRow(0, new Label(i18n("settings.advanced.minecraft_arguments")), txtGameArgs);
|
||||
|
||||
txtPreLaunchCommand = new JFXTextField();
|
||||
txtPreLaunchCommand.setPromptText(i18n("settings.advanced.precall_command.prompt"));
|
||||
txtPreLaunchCommand.getStyleClass().add("fit-width");
|
||||
pane.addRow(1, new Label(i18n("settings.advanced.precall_command")), txtPreLaunchCommand);
|
||||
|
||||
txtWrapper = new JFXTextField();
|
||||
txtWrapper.setPromptText(i18n("settings.advanced.wrapper_launcher.prompt"));
|
||||
txtWrapper.getStyleClass().add("fit-width");
|
||||
pane.addRow(2, new Label(i18n("settings.advanced.wrapper_launcher")), txtWrapper);
|
||||
|
||||
txtPostExitCommand = new JFXTextField();
|
||||
txtPostExitCommand.setPromptText(i18n("settings.advanced.post_exit_command.prompt"));
|
||||
txtPostExitCommand.getStyleClass().add("fit-width");
|
||||
pane.addRow(3, new Label(i18n("settings.advanced.post_exit_command")), txtPostExitCommand);
|
||||
|
||||
HintPane hintPane = new HintPane();
|
||||
hintPane.setText(i18n("settings.advanced.custom_commands.hint"));
|
||||
GridPane.setColumnSpan(hintPane, 2);
|
||||
pane.addRow(4, hintPane);
|
||||
|
||||
customCommandsPane.getContent().setAll(pane);
|
||||
}
|
||||
|
||||
ComponentList jvmPane = new ComponentList();
|
||||
jvmPane.disableProperty().bind(enableSpecificSettings.not());
|
||||
{
|
||||
GridPane pane = new GridPane();
|
||||
ColumnConstraints title = new ColumnConstraints();
|
||||
ColumnConstraints value = new ColumnConstraints();
|
||||
value.setFillWidth(true);
|
||||
value.setHgrow(Priority.ALWAYS);
|
||||
pane.setHgap(16);
|
||||
pane.setVgap(8);
|
||||
pane.getColumnConstraints().setAll(title, value);
|
||||
|
||||
txtJVMArgs = new JFXTextField();
|
||||
txtJVMArgs.getStyleClass().add("fit-width");
|
||||
pane.addRow(0, new Label(i18n("settings.advanced.jvm_args")), txtJVMArgs);
|
||||
|
||||
HintPane hintPane = new HintPane();
|
||||
hintPane.setText(i18n("settings.advanced.jvm_args.prompt"));
|
||||
GridPane.setColumnSpan(hintPane, 2);
|
||||
pane.addRow(4, hintPane);
|
||||
|
||||
txtMetaspace = new JFXTextField();
|
||||
txtMetaspace.setPromptText(i18n("settings.advanced.java_permanent_generation_space.prompt"));
|
||||
txtMetaspace.getStyleClass().add("fit-width");
|
||||
FXUtils.setValidateWhileTextChanged(txtMetaspace, true);
|
||||
txtMetaspace.setValidators(new NumberValidator(i18n("input.number"), true));
|
||||
pane.addRow(1, new Label(i18n("settings.advanced.java_permanent_generation_space")), txtMetaspace);
|
||||
|
||||
jvmPane.getContent().setAll(pane);
|
||||
}
|
||||
|
||||
ComponentList workaroundPane = new ComponentList();
|
||||
workaroundPane.disableProperty().bind(enableSpecificSettings.not());
|
||||
|
||||
HintPane workaroundWarning = new HintPane(MessageDialogPane.MessageType.WARNING);
|
||||
workaroundWarning.setText(i18n("settings.advanced.workaround.warning"));
|
||||
|
||||
{
|
||||
nativesDirItem = new MultiFileItem<>();
|
||||
nativesDirSublist = new ComponentSublist();
|
||||
nativesDirSublist.getContent().add(nativesDirItem);
|
||||
nativesDirSublist.setTitle(i18n("settings.advanced.natives_directory"));
|
||||
nativesDirSublist.setHasSubtitle(true);
|
||||
nativesDirCustomOption = new MultiFileItem.FileOption<>(i18n("settings.advanced.natives_directory.custom"), NativesDirectoryType.CUSTOM)
|
||||
.setChooserTitle(i18n("settings.advanced.natives_directory.choose"))
|
||||
.setDirectory(true);
|
||||
nativesDirItem.loadChildren(Arrays.asList(
|
||||
new MultiFileItem.Option<>(i18n("settings.advanced.natives_directory.default"), NativesDirectoryType.VERSION_FOLDER),
|
||||
nativesDirCustomOption
|
||||
));
|
||||
HintPane nativesDirHint = new HintPane(MessageDialogPane.MessageType.WARNING);
|
||||
nativesDirHint.setText(i18n("settings.advanced.natives_directory.hint"));
|
||||
nativesDirItem.getChildren().add(nativesDirHint);
|
||||
|
||||
noJVMArgsPane = new OptionToggleButton();
|
||||
noJVMArgsPane.setTitle(i18n("settings.advanced.no_jvm_args"));
|
||||
|
||||
noGameCheckPane = new OptionToggleButton();
|
||||
noGameCheckPane.setTitle(i18n("settings.advanced.dont_check_game_completeness"));
|
||||
|
||||
noJVMCheckPane = new OptionToggleButton();
|
||||
noJVMCheckPane.setTitle(i18n("settings.advanced.dont_check_jvm_validity"));
|
||||
|
||||
noNativesPatchPane = new OptionToggleButton();
|
||||
noNativesPatchPane.setTitle(i18n("settings.advanced.dont_patch_natives"));
|
||||
|
||||
useSoftwareRenderer = new OptionToggleButton();
|
||||
useSoftwareRenderer.setTitle(i18n("settings.advanced.use_software_renderer"));
|
||||
|
||||
useNativeGLFWPane = new OptionToggleButton();
|
||||
useNativeGLFWPane.setTitle(i18n("settings.advanced.use_native_glfw"));
|
||||
|
||||
useNativeOpenALPane = new OptionToggleButton();
|
||||
useNativeOpenALPane.setTitle(i18n("settings.advanced.use_native_openal"));
|
||||
|
||||
workaroundPane.getContent().setAll(
|
||||
nativesDirSublist,
|
||||
noJVMArgsPane, noGameCheckPane, noJVMCheckPane, noNativesPatchPane,
|
||||
useSoftwareRenderer, useNativeGLFWPane, useNativeOpenALPane);
|
||||
}
|
||||
|
||||
rootPane.getChildren().addAll(componentList,
|
||||
advancedHintPane,
|
||||
ComponentList.createComponentListTitle(i18n("settings.advanced.custom_commands")), customCommandsPane,
|
||||
ComponentList.createComponentListTitle(i18n("settings.advanced.jvm")), jvmPane,
|
||||
ComponentList.createComponentListTitle(i18n("settings.advanced.workaround")), workaroundWarning, workaroundPane);
|
||||
rootPane.getChildren().add(componentList);
|
||||
|
||||
initialize();
|
||||
|
||||
specificSettingsListener = any -> {
|
||||
enableSpecificSettings.set(!lastVersionSetting.isUsesGlobal());
|
||||
};
|
||||
specificSettingsListener = any -> enableSpecificSettings.set(!lastVersionSetting.isUsesGlobal());
|
||||
|
||||
addEventHandler(Navigator.NavigationEvent.NAVIGATED, this::onDecoratorPageNavigating);
|
||||
|
||||
@@ -595,6 +472,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void loadVersion(Profile profile, String versionId) {
|
||||
this.profile = profile;
|
||||
this.versionId = versionId;
|
||||
@@ -631,24 +509,10 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
maxMemory.unbindBidirectional(lastVersionSetting.maxMemoryProperty());
|
||||
javaCustomOption.valueProperty().unbindBidirectional(lastVersionSetting.javaDirProperty());
|
||||
gameDirCustomOption.valueProperty().unbindBidirectional(lastVersionSetting.gameDirProperty());
|
||||
nativesDirCustomOption.valueProperty().unbindBidirectional(lastVersionSetting.nativesDirProperty());
|
||||
FXUtils.unbind(txtJVMArgs, lastVersionSetting.javaArgsProperty());
|
||||
FXUtils.unbind(txtGameArgs, lastVersionSetting.minecraftArgsProperty());
|
||||
FXUtils.unbind(txtMetaspace, lastVersionSetting.permSizeProperty());
|
||||
FXUtils.unbind(txtWrapper, lastVersionSetting.wrapperProperty());
|
||||
FXUtils.unbind(txtPreLaunchCommand, lastVersionSetting.preLaunchCommandProperty());
|
||||
FXUtils.unbind(txtPostExitCommand, lastVersionSetting.postExitCommandProperty());
|
||||
FXUtils.unbind(txtServerIP, lastVersionSetting.serverIpProperty());
|
||||
FXUtils.unbindBoolean(chkAutoAllocate, lastVersionSetting.autoMemoryProperty());
|
||||
FXUtils.unbindBoolean(chkFullscreen, lastVersionSetting.fullscreenProperty());
|
||||
noGameCheckPane.selectedProperty().unbindBidirectional(lastVersionSetting.notCheckGameProperty());
|
||||
noJVMCheckPane.selectedProperty().unbindBidirectional(lastVersionSetting.notCheckJVMProperty());
|
||||
noJVMArgsPane.selectedProperty().unbindBidirectional(lastVersionSetting.noJVMArgsProperty());
|
||||
noNativesPatchPane.selectedProperty().unbindBidirectional(lastVersionSetting.notPatchNativesProperty());
|
||||
showLogsPane.selectedProperty().unbindBidirectional(lastVersionSetting.showLogsProperty());
|
||||
useSoftwareRenderer.selectedProperty().unbindBidirectional(lastVersionSetting.useSoftwareRendererProperty());
|
||||
useNativeGLFWPane.selectedProperty().unbindBidirectional(lastVersionSetting.useNativeGLFWProperty());
|
||||
useNativeOpenALPane.selectedProperty().unbindBidirectional(lastVersionSetting.useNativeOpenALProperty());
|
||||
FXUtils.unbindEnum(cboLauncherVisibility);
|
||||
FXUtils.unbindEnum(cboProcessPriority);
|
||||
|
||||
@@ -659,8 +523,10 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
gameDirItem.selectedDataProperty().unbindBidirectional(lastVersionSetting.gameDirTypeProperty());
|
||||
gameDirSublist.subtitleProperty().unbind();
|
||||
|
||||
nativesDirItem.selectedDataProperty().unbindBidirectional(lastVersionSetting.nativesDirTypeProperty());
|
||||
nativesDirSublist.subtitleProperty().unbind();
|
||||
if (advancedVersionSettingPage != null) {
|
||||
advancedVersionSettingPage.unbindProperties();
|
||||
advancedVersionSettingPage = null;
|
||||
}
|
||||
}
|
||||
|
||||
// unbind data fields
|
||||
@@ -673,23 +539,10 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
|
||||
javaCustomOption.bindBidirectional(versionSetting.javaDirProperty());
|
||||
gameDirCustomOption.bindBidirectional(versionSetting.gameDirProperty());
|
||||
nativesDirCustomOption.bindBidirectional(versionSetting.nativesDirProperty());
|
||||
FXUtils.bindString(txtJVMArgs, versionSetting.javaArgsProperty());
|
||||
FXUtils.bindString(txtGameArgs, versionSetting.minecraftArgsProperty());
|
||||
FXUtils.bindString(txtMetaspace, versionSetting.permSizeProperty());
|
||||
FXUtils.bindString(txtWrapper, versionSetting.wrapperProperty());
|
||||
FXUtils.bindString(txtPreLaunchCommand, versionSetting.preLaunchCommandProperty());
|
||||
FXUtils.bindString(txtServerIP, versionSetting.serverIpProperty());
|
||||
FXUtils.bindBoolean(chkAutoAllocate, versionSetting.autoMemoryProperty());
|
||||
FXUtils.bindBoolean(chkFullscreen, versionSetting.fullscreenProperty());
|
||||
noGameCheckPane.selectedProperty().bindBidirectional(versionSetting.notCheckGameProperty());
|
||||
noJVMCheckPane.selectedProperty().bindBidirectional(versionSetting.notCheckJVMProperty());
|
||||
noJVMArgsPane.selectedProperty().bindBidirectional(versionSetting.noJVMArgsProperty());
|
||||
noNativesPatchPane.selectedProperty().bindBidirectional(versionSetting.notPatchNativesProperty());
|
||||
showLogsPane.selectedProperty().bindBidirectional(versionSetting.showLogsProperty());
|
||||
useSoftwareRenderer.selectedProperty().bindBidirectional(versionSetting.useSoftwareRendererProperty());
|
||||
useNativeGLFWPane.selectedProperty().bindBidirectional(versionSetting.useNativeGLFWProperty());
|
||||
useNativeOpenALPane.selectedProperty().bindBidirectional(versionSetting.useNativeOpenALProperty());
|
||||
FXUtils.bindEnum(cboLauncherVisibility, versionSetting.launcherVisibilityProperty());
|
||||
FXUtils.bindEnum(cboProcessPriority, versionSetting.processPriorityProperty());
|
||||
|
||||
@@ -703,7 +556,6 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
} else if (javaAutoDeterminedOption.isSelected()) {
|
||||
versionSetting.setJavaAutoSelected();
|
||||
} else {
|
||||
//noinspection unchecked
|
||||
versionSetting.setJavaVersion(((Pair<JavaVersionType, JavaVersion>) newValue.getUserData()).getValue());
|
||||
}
|
||||
});
|
||||
@@ -716,10 +568,6 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
gameDirSublist.subtitleProperty().bind(Bindings.createStringBinding(() -> Paths.get(profile.getRepository().getRunDirectory(versionId).getAbsolutePath()).normalize().toString(),
|
||||
versionSetting.gameDirProperty(), versionSetting.gameDirTypeProperty()));
|
||||
|
||||
nativesDirItem.selectedDataProperty().bindBidirectional(versionSetting.nativesDirTypeProperty());
|
||||
nativesDirSublist.subtitleProperty().bind(Bindings.createStringBinding(() -> Paths.get(profile.getRepository().getRunDirectory(versionId).getAbsolutePath() + "/natives").normalize().toString(),
|
||||
versionSetting.nativesDirProperty(), versionSetting.nativesDirTypeProperty()));
|
||||
|
||||
lastVersionSetting = versionSetting;
|
||||
|
||||
initJavaSubtitle();
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.jackhuang.hmcl.util;
|
||||
|
||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @see <a href="https://github.com/fractureiser-investigation/fractureiser">fractureiser-investigation/fractureiser</a>
|
||||
* @see <a href="https://prismlauncher.org/news/cf-compromised-alert/#automated-script">[MALWARE WARNING] "fractureiser" malware in many popular Minecraft mods and modpacks</a>
|
||||
*/
|
||||
public final class FractureiserDetector {
|
||||
private FractureiserDetector() {
|
||||
}
|
||||
|
||||
public static boolean detect() {
|
||||
try {
|
||||
ArrayList<Path> badPaths = new ArrayList<>();
|
||||
|
||||
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
|
||||
Path appdata = Paths.get(System.getProperty("user.home"), "AppData");
|
||||
if (Files.isDirectory(appdata)) {
|
||||
badPaths.add(appdata.resolve("Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\run.bat"));
|
||||
|
||||
Path falseEdgePath = appdata.resolve("Local\\Microsoft Edge");
|
||||
if (Files.exists(falseEdgePath)) {
|
||||
badPaths.add(falseEdgePath.resolve(".ref"));
|
||||
badPaths.add(falseEdgePath.resolve("client.jar"));
|
||||
badPaths.add(falseEdgePath.resolve("lib.dll"));
|
||||
badPaths.add(falseEdgePath.resolve("libWebGL64.jar"));
|
||||
badPaths.add(falseEdgePath.resolve("run.bat"));
|
||||
}
|
||||
}
|
||||
} else if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX) {
|
||||
Path dataDir = Paths.get(System.getProperty("user.home"), ".config", ".data");
|
||||
if (Files.exists(dataDir)) {
|
||||
badPaths.add(dataDir.resolve(".ref"));
|
||||
badPaths.add(dataDir.resolve("client.jar"));
|
||||
badPaths.add(dataDir.resolve("lib.jar"));
|
||||
}
|
||||
}
|
||||
|
||||
for (Path badPath : badPaths) {
|
||||
if (Files.exists(badPath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,22 @@
|
||||
package org.jackhuang.hmcl.util;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.game.NativesDirectoryType;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.game.*;
|
||||
import org.jackhuang.hmcl.setting.VersionSetting;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.platform.Architecture;
|
||||
import org.jackhuang.hmcl.util.platform.JavaVersion;
|
||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||
import org.jackhuang.hmcl.util.platform.Platform;
|
||||
import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||
|
||||
@@ -25,10 +26,24 @@ public final class NativePatcher {
|
||||
|
||||
private static final Library NONEXISTENT_LIBRARY = new Library(null);
|
||||
|
||||
public static Version patchNative(Version version, String gameVersion, JavaVersion javaVersion, VersionSetting settings) {
|
||||
if (settings.isNotPatchNatives())
|
||||
return version;
|
||||
private static final Map<Platform, Map<String, Library>> natives = new HashMap<>();
|
||||
|
||||
private static Map<String, Library> getNatives(Platform platform) {
|
||||
return natives.computeIfAbsent(platform, p -> {
|
||||
//noinspection ConstantConditions
|
||||
try (Reader reader = new InputStreamReader(NativePatcher.class.getResourceAsStream("/assets/natives.json"), StandardCharsets.UTF_8)) {
|
||||
Map<String, Map<String, Library>> natives = JsonUtils.GSON.fromJson(reader, new TypeToken<Map<String, Map<String, Library>>>() {
|
||||
}.getType());
|
||||
|
||||
return natives.getOrDefault(p.toString(), Collections.emptyMap());
|
||||
} catch (IOException e) {
|
||||
LOG.log(Level.WARNING, "Failed to load native library list", e);
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Version patchNative(Version version, String gameVersion, JavaVersion javaVersion, VersionSetting settings) {
|
||||
if (settings.getNativesDirType() == NativesDirectoryType.CUSTOM) {
|
||||
if (gameVersion != null && VersionNumber.VERSION_COMPARATOR.compare(gameVersion, "1.19") < 0)
|
||||
return version;
|
||||
@@ -47,6 +62,34 @@ public final class NativePatcher {
|
||||
return version.setLibraries(newLibraries);
|
||||
}
|
||||
|
||||
final boolean useNativeGLFW = settings.isUseNativeGLFW();
|
||||
final boolean useNativeOpenAL = settings.isUseNativeOpenAL();
|
||||
|
||||
if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX
|
||||
&& (useNativeGLFW || useNativeOpenAL)
|
||||
&& VersionNumber.VERSION_COMPARATOR.compare(gameVersion, "1.19") >= 0) {
|
||||
|
||||
version = version.setLibraries(version.getLibraries().stream()
|
||||
.filter(library -> {
|
||||
if (library.getClassifier() != null && library.getClassifier().startsWith("natives")
|
||||
&& "org.lwjgl".equals(library.getGroupId())) {
|
||||
if ((useNativeGLFW && "lwjgl-glfw".equals(library.getArtifactId()))
|
||||
|| (useNativeOpenAL && "lwjgl-openal".equals(library.getArtifactId()))) {
|
||||
LOG.info("Filter out " + library.getName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
// Try patch natives
|
||||
|
||||
if (settings.isNotPatchNatives())
|
||||
return version;
|
||||
|
||||
if (javaVersion.getArchitecture().isX86())
|
||||
return version;
|
||||
|
||||
@@ -56,8 +99,8 @@ public final class NativePatcher {
|
||||
&& VersionNumber.VERSION_COMPARATOR.compare(gameVersion, "1.19") >= 0)
|
||||
return version;
|
||||
|
||||
Map<String, Library> replacements = Hole.nativeReplacement.get(javaVersion.getPlatform().toString());
|
||||
if (replacements == null) {
|
||||
Map<String, Library> replacements = getNatives(javaVersion.getPlatform());
|
||||
if (replacements.isEmpty()) {
|
||||
LOG.warning("No alternative native library provided for platform " + javaVersion.getPlatform());
|
||||
return version;
|
||||
}
|
||||
@@ -70,11 +113,7 @@ public final class NativePatcher {
|
||||
if (library.isNative()) {
|
||||
Library replacement = replacements.getOrDefault(library.getName() + ":natives", NONEXISTENT_LIBRARY);
|
||||
if (replacement == NONEXISTENT_LIBRARY) {
|
||||
if (!(settings.isUseNativeGLFW() && library.getArtifactId().contains("glfw"))
|
||||
&& !(settings.isUseNativeOpenAL() && library.getArtifactId().contains("openal"))) {
|
||||
LOG.warning("No alternative native library " + library.getName() + " provided for platform " + javaVersion.getPlatform());
|
||||
return version;
|
||||
}
|
||||
LOG.warning("No alternative native library " + library.getName() + " provided for platform " + javaVersion.getPlatform());
|
||||
newLibraries.add(library);
|
||||
} else if (replacement != null) {
|
||||
newLibraries.add(replacement);
|
||||
@@ -92,23 +131,7 @@ public final class NativePatcher {
|
||||
return version.setLibraries(newLibraries);
|
||||
}
|
||||
|
||||
public static Library getSoftwareRendererLoader(JavaVersion javaVersion) {
|
||||
Map<String, Library> map = Hole.nativeReplacement.get(javaVersion.getPlatform().toString());
|
||||
return map != null ? map.get("software-renderer-loader") : null;
|
||||
}
|
||||
|
||||
private static final class Hole {
|
||||
static Map<String, Map<String, Library>> nativeReplacement;
|
||||
|
||||
static {
|
||||
//noinspection ConstantConditions
|
||||
try (Reader reader = new InputStreamReader(NativePatcher.class.getResourceAsStream("/assets/natives.json"))) {
|
||||
nativeReplacement = JsonUtils.GSON.fromJson(reader, new TypeToken<Map<String, Map<String, Library>>>() {
|
||||
}.getType());
|
||||
} catch (IOException e) {
|
||||
nativeReplacement = Collections.emptyMap();
|
||||
LOG.log(Level.WARNING, "Failed to load native library list", e);
|
||||
}
|
||||
}
|
||||
public static Library getMesaLoader(JavaVersion javaVersion, Renderer renderer) {
|
||||
return getNatives(javaVersion.getPlatform()).get(renderer == Renderer.LLVMPIPE ? "software-renderer-loader" : "mesa-loader");
|
||||
}
|
||||
}
|
||||
@@ -65,8 +65,10 @@ account.failed.invalid_password=Invalid password
|
||||
account.failed.invalid_token=Please try to re-login again.
|
||||
account.failed.migration=Your account needs to be migrated to a Microsoft account. If you already did, you should re-login to your migrated Microsoft account instead.
|
||||
account.failed.no_character=There are no characters linked to this account.
|
||||
account.failed.server_disconnected=Cannot access authentication server. You can log in offline or try to re-login.
|
||||
account.failed.server_disconnected=Cannot access authentication server. You can log in offline or try to re-login.\n\
|
||||
If you try multiple times and still fail, please try adding the account again.
|
||||
account.failed.server_response_malformed=Invalid server response, the authentication server may not be working.
|
||||
account.failed.ssl=An SSL error occurred while connecting to the server. Please try updating your Java.
|
||||
account.failed.wrong_account=You have logged in to the wrong account.
|
||||
account.hmcl.hint=You need to click on "Login" and complete the process in the opened tab in your browser.
|
||||
# avoid too long sequence.
|
||||
@@ -108,7 +110,7 @@ If the token used to log in to the Microsoft account is leaked, you can click on
|
||||
account.methods.microsoft.manual=Your device code is <b>%1$s</b>, please click here to copy. After clicking on the "Login" button, you should finish the login process in the opened browser window. If it did not show, you can go to %2$s manually.\n\
|
||||
\n\
|
||||
If the token used to log in to the Microsoft account is leaked, you can click on "Unauthorize the account" to deauthorize it.
|
||||
account.methods.microsoft.makegameidsettings=Create Profile
|
||||
account.methods.microsoft.makegameidsettings=Create Profile / Edit Profile Name
|
||||
account.methods.microsoft.profile=Account Profile
|
||||
account.methods.microsoft.snapshot=You are using an unofficial build of HMCL. Please download the official build for login.
|
||||
account.methods.microsoft.snapshot.website=Official Website
|
||||
@@ -195,7 +197,7 @@ curse.category.4477=Mini Game
|
||||
curse.category.4478=Quests
|
||||
curse.category.4484=Multiplayer
|
||||
curse.category.4476=Exploration
|
||||
curse.category.4736=Skyblock
|
||||
curse.category.6145=Skyblock
|
||||
curse.category.4475=Adventure and RPG
|
||||
curse.category.4487=FTB
|
||||
curse.category.4480=Map Based
|
||||
@@ -342,6 +344,8 @@ extension.png=Image File
|
||||
extension.ps1=Windows PowerShell Cmdlet File
|
||||
extension.sh=Bash Shell Script
|
||||
|
||||
fatal.fractureiser=Hello Minecraft! Launcher has detected that your computer has been infected with the Fraureiser, which poses a serious security issue.\n\
|
||||
Please use antivirus software to perform a full scan immediately, and then change the passwords of all accounts you have logged in on this computer.
|
||||
fatal.javafx.incompatible=Missing JavaFX environment.\n\
|
||||
HMCL cannot automatically install JavaFX under Java versions below 11.\n\
|
||||
Please update your Java to version 11 or higher.
|
||||
@@ -359,6 +363,9 @@ fatal.config_loading_failure=Cannot load configuration files.\n\
|
||||
Please make sure that "Hello Minecraft! Launcher" has read and write access to "%s" and the files in it.
|
||||
fatal.config_loading_failure.unix=Hello Minecraft! Launcher could not load the profile because the profile was created by user %1$s.\n\
|
||||
Please start HMCL with sudo (not recommended), or execute the following command in the terminal to change the ownership of the configuration file to the current user:\n%2$s
|
||||
fatal.mac_app_translocation=Due to the security mechanism of macOS, Hello Minecraft! Launcher is quarantined by the system to the temporary folder.\n\
|
||||
Please move Hello Minecraft! Launcher to a different folder before attempting to start, otherwise your settings and game data may be lost after restarting.\n\
|
||||
Do you still want to continue?
|
||||
fatal.migration_requires_manual_reboot=Hello Minecraft! Launcher has been upgraded. Please reopen the launcher.
|
||||
fatal.apply_update_failure=We are sorry, but Hello Minecraft! Launcher is unable to update.\n\
|
||||
\n\
|
||||
@@ -431,6 +438,8 @@ game.crash.reason.mod_resolution0=The current game cannot continue to run becaus
|
||||
game.crash.reason.mod_profile_causes_game_crash=The current game cannot continue to run because of a problem with the Mod configuration file.\nYou can check the log to find the error module and its configuration file.
|
||||
game.crash.reason.fabric_reports_an_error_and_gives_a_solution=Forge may have provided error information.\nYou can view the log and make corresponding processing according to the log information in the error report.\nIf you do not see the error message, you can view the error report to understand how the error occurred.
|
||||
game.crash.reason.java_version_is_too_high=The current game crashed because the Java version used is too high to continue running.\nPlease use a lower version of Java in the Java path tab of global game settings or game specific settings, and then start the game.\nIf not, you can download it from <a href="https://www.java.com/download/">java.com (Java8)</a> or <a href="https://bell-sw.com/pages/downloads">BellSoft Liberica Full JRE (Java17)</a> and other platforms to download and install one (restart the launcher after installation).
|
||||
game.crash.reason.mod_name=The current game cannot continue to run because of Mod file name problems. \nMod file names should use only upper and lower case letters (Aa~Zz), numbers (0~9), horizontal lines (-), underscores (_), and dots (.) in full half-angle English . \nPlease go to the Mod folder and add all non-compliant Mod file names with one of the above compliant characters.
|
||||
game.crash.reason.incomplete_forge_installation=The current game cannot continue due to an incomplete installation of Forge. \nPlease uninstall and reinstall Forge in Version Settings - Automatic Installation.
|
||||
game.crash.reason.fabric_version_0_12=Fabric 0.12 or above are incompatible with currently installed mods. You need to downgrade it to 0.11.7.
|
||||
game.crash.reason.fabric_warnings=The Fabric modloader warned\:\n\
|
||||
%1$s
|
||||
@@ -952,6 +961,8 @@ selector.custom=Custom
|
||||
settings=Settings
|
||||
|
||||
settings.advanced=Advanced Settings
|
||||
settings.advanced.modify=Modify Advanced Settings
|
||||
settings.advanced.title=Advanced Settings - %s
|
||||
settings.advanced.custom_commands=Custom Commands
|
||||
settings.advanced.custom_commands.hint=The following environment variables are provided\:\n\
|
||||
- $INST_NAME: version name\n\
|
||||
@@ -967,6 +978,7 @@ settings.advanced.custom_commands.hint=The following environment variables are p
|
||||
settings.advanced.dont_check_game_completeness=Do not check game integrity
|
||||
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
|
||||
@@ -1001,11 +1013,15 @@ settings.advanced.process_priority.above_normal=Above Normal
|
||||
settings.advanced.process_priority.high=High
|
||||
settings.advanced.post_exit_command=Post-exit Command
|
||||
settings.advanced.post_exit_command.prompt=Commands to execute after the game exits
|
||||
settings.advanced.renderer=Renderer
|
||||
settings.advanced.renderer.default=OpenGL (Default)
|
||||
settings.advanced.renderer.d3d12=DirectX 12 (Poor performance and compatibility)
|
||||
settings.advanced.renderer.llvmpipe=Software (Poor efficiency and best compatibility)
|
||||
settings.advanced.renderer.zink=Vulkan (Best performance and poor compatibility)
|
||||
settings.advanced.server_ip=Server Address
|
||||
settings.advanced.server_ip.prompt=Join automatically after launching the game.
|
||||
settings.advanced.use_native_glfw=[Linux Only] Use system GLFW
|
||||
settings.advanced.use_native_openal=[Linux Only] Use system OpenAL
|
||||
settings.advanced.use_software_renderer=Use OpenGL software renderer (better compatibility, but less performance)
|
||||
settings.advanced.workaround=Workarounds
|
||||
settings.advanced.workaround.warning=Workaround options are intended only for expert users. Tweaking with these options may crash the game. Unless you know what you are doing, please do not modify these options.
|
||||
settings.advanced.wrapper_launcher=Wrapper Command
|
||||
@@ -1107,14 +1123,12 @@ update.channel.dev.hint=You are currently using a beta build of the launcher, wh
|
||||
\n\
|
||||
If you encounter any bug or issue, you can go to <a href="hmcl://settings/feedback">the feedback page</a> to report it, or tell us in our <a href="https://discord.gg/jVvC7HfM6U">Discord</a> or <a href="https://kook.top/Kx7n3t">KOOK</a> community.\n\
|
||||
\n\
|
||||
To hide this tooltip, you need to make a <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">donation</a> or submit a valuable feedback.
|
||||
<a href="hmcl://hide-announcement">Click here</a> to hide this tooltip for the current version.
|
||||
update.channel.dev.title=Beta Version Notice
|
||||
update.channel.nightly=Nightly
|
||||
update.channel.nightly.hint=You are currently using a nightly build of the launcher, which may include some extra features, but is also always more unstable than the other versions.\n\
|
||||
\n\
|
||||
If you encounter any bug or issue, you can go to <a href="hmcl://settings/feedback">the feedback page</a> to report it, or tell us in our <a href="https://discord.gg/jVvC7HfM6U">Discord</a> or <a href="https://kook.top/Kx7n3t">KOOK</a> community.\n\
|
||||
\n\
|
||||
To hide this tooltip, you need to make a <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">donation</a> or submit a valuable feedback.
|
||||
If you encounter any bug or issue, you can go to <a href="hmcl://settings/feedback">the feedback page</a> to report it, or tell us in our <a href="https://discord.gg/jVvC7HfM6U">Discord</a> or <a href="https://kook.top/Kx7n3t">KOOK</a> community.
|
||||
update.channel.nightly.title=Nightly Version Notice
|
||||
update.channel.stable=Release
|
||||
update.checking=Checking for Updates
|
||||
@@ -1159,6 +1173,7 @@ version.manage.remove=Delete Instance
|
||||
version.manage.remove.confirm=Are you sure you want to permanently remove the version %s? This action cannot be undone\!
|
||||
version.manage.remove.confirm.trash=Are you sure you want to remove the version %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 instance %s?
|
||||
version.manage.remove_assets=Delete All Assets
|
||||
version.manage.remove_libraries=Delete All Libraries
|
||||
version.manage.rename=Rename Instance
|
||||
version.manage.rename.message=Please enter the new name for this instance
|
||||
|
||||
@@ -89,7 +89,7 @@ account.methods.microsoft.birth=Cómo actualizar la fecha de nacimiento de tu cu
|
||||
account.methods.microsoft.close_page=La autorización de la cuenta de Microsoft ha finalizado. \n\
|
||||
\n\
|
||||
Hay algunos trabajos extra para nosotros, pero puedes cerrar esta pestaña con seguridad por ahora.
|
||||
account.methods.microsoft.makegameidsettings=Create Profile
|
||||
account.methods.microsoft.makegameidsettings=Create Profile / Editar el nombre de perfil
|
||||
account.methods.microsoft.deauthorize=Desautorizar
|
||||
account.methods.microsoft.error.add_family=Como todavía no tienes 18 años, un adulto debe añadirte a una familia para que puedas jugar a Minecraft.
|
||||
account.methods.microsoft.error.add_family_probably=Por favor, comprueba si la edad indicada en la configuración de tu cuenta es de al menos 18 años. Si no es así y crees que se trata de un error, puedes hacer clic en el enlace anterior para cambiarlo.
|
||||
@@ -183,7 +183,7 @@ curse.category.4477=Mini Juego
|
||||
curse.category.4478=Quests
|
||||
curse.category.4484=Multijugador
|
||||
curse.category.4476=Exploración
|
||||
curse.category.4736=Skyblock
|
||||
curse.category.6145=Skyblock
|
||||
curse.category.4475=Aventura y RPG
|
||||
curse.category.4487=FTB
|
||||
curse.category.4480=Basado en mapa
|
||||
@@ -468,6 +468,8 @@ game.crash.reason.mod_solution0=El juego actual no puede seguir ejecutándose de
|
||||
game.crash.reason.mod_profile_causes_game_crash=El juego actual no puede seguir ejecutándose debido a un problema con el perfil de mod. \nPuede consultar el registro del mod defectuoso y su archivo de configuración.
|
||||
game.crash.reason.fabric_reports_an_error_and_gives_a_solution=Forge puede haber dado un mensaje de error. \nPuede ver el registro y realizar las acciones correspondientes de acuerdo con la información de registro en el informe de errores. \nSi no ve un mensaje de error, puede consultar el informe de errores para saber cómo ocurrió el error.
|
||||
game.crash.reason.java_version_is_too_high=El juego actual se bloqueó porque la versión de Java es demasiado alta y no puede seguir ejecutándose. \nCambie a una versión anterior de Java en la pestaña Java Path de Configuración global del juego o Configuración específica del juego antes de iniciar el juego. \nSi no es así, puede descargarlo desde <a href="https://www.java.com/download/">java.com (Java8)</a> o <a href="https://bell-sw.com/pages/downloads">BellSoft Liberica Full JRE (Java17)</a> y otras plataformas para descargar e instalar una (reinicie el iniciador después de la instalación).
|
||||
game.crash.reason.mod_name=El juego actual no puede continuar ejecutándose debido a un problema con el nombre del archivo mod. El nombre del archivo de \nMod solo debe usar mayúsculas y minúsculas (Aa ~ Zz), números (0 ~ 9), líneas horizontales (-), subrayado (_) y puntos (.) en toda la mitad del inglés. \n Por favor, vaya a la carpeta mod para agregar un carácter de Cumplimiento anterior a todos los nombres de archivo mod que no cumplan.
|
||||
game.crash.reason.incomplete_forge_installation=O jogo atual não pode continuar devido a uma instalação incompleta do Forge. \nDesinstale e reinstale o Forge em Configurações de versão - Instalação automática.
|
||||
game.crash.reason.modlauncher_8=El juego se ha bloqueado porque tu versión actual de Forge no es compatible con tu instalación de Java. Por favor, intente actualizar Forge, o intente utilizar Java 8u312/11.0.13/17.0.1 o versiones anteriores.\n\
|
||||
\n\
|
||||
8u312 y anteriores\:\n\
|
||||
@@ -869,6 +871,7 @@ selector.custom=Personalizar
|
||||
settings=Configuración
|
||||
|
||||
settings.advanced=Configuración avanzada
|
||||
settings.advanced.title=Configuración avanzada - %s
|
||||
settings.advanced.custom_commands=Comandos personalizados
|
||||
settings.advanced.custom_commands.hint=Se proporcionan las siguientes variables de entorno\:\n\
|
||||
- $INST_NAME: nombre de la versión\n\
|
||||
@@ -1016,14 +1019,12 @@ update.channel.dev.hint=Actualmente está utilizando una versión beta del launc
|
||||
\n\
|
||||
Si encuentra algún error o problema, puede ir a la <a href="hmcl://settings/feedback">página de comentarios</a> para informar de ello, o bien para decírnoslo en nuestro <a href="https://discord.gg/jVvC7HfM6U">Discord</a> o en la comunidad <a href="https://kookapp.co/Kx7n3t">KOOK</a>.\n\
|
||||
\n\
|
||||
Para ocultar esta información, es necesario hacer una <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">donación</a> o enviar un valioso comentario.
|
||||
<a href="hmcl://hide-announcement">Haga clic aquí</a> para ocultar el recordatorio para la versión de prueba actual.
|
||||
update.channel.dev.title=Aviso de versión beta
|
||||
update.channel.nightly=Nocturna
|
||||
update.channel.nightly.hint=Estás utilizando una versión nocturna del launcher, que puede incluir algunas características adicionales, pero también es siempre más inestable que las otras versiones.\n\
|
||||
\n\
|
||||
Si encuentra algún error o problema, puede ir a la <a href="hmcl://settings/feedback">página de comentarios</a> para informar de ello, o bien para decírnoslo en nuestro <a href="https://discord.gg/jVvC7HfM6U">Discord</a> o en la comunidad <a href="https://kookapp.co/Kx7n3t">KOOK</a> community.\n\
|
||||
\n\
|
||||
Para ocultar esta información sobre herramientas, es necesario hacer una <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">donación</a> o enviar un valioso comentario.
|
||||
Si encuentra algún error o problema, puede ir a la <a href="hmcl://settings/feedback">página de comentarios</a> para informar de ello, o bien para decírnoslo en nuestro <a href="https://discord.gg/jVvC7HfM6U">Discord</a> o en la comunidad <a href="https://kookapp.co/Kx7n3t">KOOK</a> community.
|
||||
update.channel.nightly.title=Aviso de versión nocturna
|
||||
update.channel.stable=Estable
|
||||
update.checking=Buscando actualizaciones
|
||||
@@ -1068,6 +1069,7 @@ version.manage.remove=Borrar instancia
|
||||
version.manage.remove.confirm=¿Está seguro de que quiere eliminar permanentemente la versión %s? ¡Esta acción no se puede deshacer\!
|
||||
version.manage.remove.confirm.trash=¿Estás seguro de que quieres eliminar la versión %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
|
||||
version.manage.remove_libraries=Borrar todas las bibliotecas
|
||||
version.manage.rename=Renombrar instancia
|
||||
version.manage.rename.message=Por favor, introduzca el nuevo nombre de esta instancia
|
||||
|
||||
@@ -94,7 +94,7 @@ account.methods.microsoft.error.no_character=アカウントにMinecraftJavaプ
|
||||
account.methods.microsoft.error.unknown=ログインに失敗しました。Microsoftはエラーコード %d で応答します。
|
||||
account.methods.microsoft.logging_in=ログイン...
|
||||
account.methods.forgot_password=パスワードをお忘れの方
|
||||
account.methods.microsoft.makegameidsettings=プロファイルを作成
|
||||
account.methods.microsoft.makegameidsettings=プロファイルを作成/プロフィール名を編集する
|
||||
account.methods.microsoft.hint=「ログイン」ボタンをクリックして、新しく開いたブラウザウィンドウでログインプロセスを続行する必要があります。\nMicrosoftアカウントへのログインに使用されたトークンが誤って漏洩した場合は、下の[アカウントのバインドを解除]をクリックして、ログイン認証をキャンセルできます。
|
||||
account.methods.microsoft.manual=「ログイン」ボタンをクリックした後、新しく開いたブラウザウィンドウで認証を完了する必要があります。ブラウザウィンドウが表示されない場合は、ここをクリックしてURLをコピーし、ブラウザで手動で開くことができます。\nMicrosoftアカウントへのログインに使用されたトークンが誤って漏洩した場合は、下の[アカウントのバインドを解除]をクリックして、ログイン認証をキャンセルできます。
|
||||
account.methods.microsoft.profile=アカウントプロファイル..
|
||||
@@ -170,7 +170,7 @@ curse.category.4477=ミニゲーム
|
||||
curse.category.4478=クエスト
|
||||
curse.category.4484=マルチプレイヤー
|
||||
curse.category.4476=探索
|
||||
curse.category.4736=Skyblock
|
||||
curse.category.6145=Skyblock
|
||||
curse.category.4475=アドベンチャーとRPG
|
||||
curse.category.4487=FTB
|
||||
curse.category.4480=マップベース
|
||||
@@ -349,6 +349,8 @@ game.crash.reason.mod_resolution0==mod の問題により、現在のゲーム
|
||||
game.crash.reason.mod_profile_causes_game_crash==mod プロファイルに問題があるため、現在のゲームを続行できません。 \n障害のある mod とその構成ファイルのログを確認できます。
|
||||
game.crash.reason.fabric_reports_an_error_and_gives_a_solution==Forge がエラー メッセージを表示した可能性があります。 \nログを表示し、エラー レポートのログ情報に従って対応するアクションを実行できます。 \nエラー メッセージが表示されない場合は、エラー レポートをチェックして、エラーがどのように発生したかを知ることができます。
|
||||
game.crash.reason.java_version_is_too_high=Java のバージョンが高すぎて実行を継続できないため、現在のゲームがクラッシュしました。 \nゲームを起動する前に、グローバル ゲーム設定またはゲーム固有の設定の Java パス タブで Java の以前のバージョンに切り替えてください。 \nそうでない場合は、<a href="https://www.java.com/download/">java.com (Java8)</a> または <a href="https://bell-sw.com/pages/downloads">BellSoft Liberica Full JRE (Java17)</a> およびその他のプラットフォームをダウンロードしてインストールします (インストール後にランチャーを再起動します)。
|
||||
game.crash.reason.mod_name=現在のゲームはModファイル名の問題で続行できません。\nModファイル名は、英文の全半角の大文字と小文字(Aa ~ Zz)、数字(0 ~ 9)、横線(-)、アンダースコア(_)、点(.)のみを使用してください。\n上記のコンプライアンス文字をModフォルダに追加してください。
|
||||
game.crash.reason.incomplete_forge_installation=Forge のインストールが不完全なため、現在のゲームを続行できません。 \nバージョン設定 - 自動インストールで Forge をアンインストールしてから再インストールしてください。
|
||||
game.crash.reason.file_already_exists=ファイル %1$s が既に存在するので、現在のゲームは続行できません。 \このファイルを削除してもよいと思われる場合は、このファイルをバックアップして、ゲームを再起動してから削除してみてください。
|
||||
game.crash.reason.file_changed=ファイルのチェックサムに失敗したため、現在のゲームを続行できません。 \nMinecraft.jar ファイルを手動で変更した場合、変更をロールバックするか、ゲームを再度ダウンロードする必要があります。
|
||||
game.crash.reason.gl_operation_failure=一部のモッド、シェーダーパック、テクスチャパックが原因でゲームがクラッシュしました。\n使用しているモッド/シェーダーパック/テクスチャパックを無効にして、再試行してください。
|
||||
@@ -703,6 +705,7 @@ selector.custom=カスタム
|
||||
settings=設定
|
||||
|
||||
settings.advanced=詳細設定
|
||||
settings.advanced.title=詳細設定 - %s
|
||||
settings.advanced.custom_commands=カスタムコマンド
|
||||
settings.advanced.custom_commands.hint=カスタムコマンドは、次の環境変数を使用して実行されます。\n \
|
||||
\-$ INST_NAME:バージョンの名前\n \
|
||||
@@ -843,16 +846,15 @@ update=更新
|
||||
update.accept=更新
|
||||
update.changelog=変更
|
||||
update.channel.dev=ベータ
|
||||
update.channel.dev.hint=ベータ版を使用しています。ベータ版には、リリースバージョンと比較していくつかの追加機能が含まれている可能性があり、テストにのみ使用されます。\n \
|
||||
ベータ版は不安定なはずです!\n \
|
||||
問題が発生した場合は、<a href="hmcl://settings/feedback">フィードバックページ</a>にアクセスして報告するか、チャット <a href="https://discord.gg/jVvC7HfM6U">Discord</a>または<a href="https://kook.top/Kx7n3t">KOOK</a>で問題を報告します。\n \n \
|
||||
このヒントを非表示にするには、<a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">寄付</a>するか、フィードバックに貢献をする必要があります。
|
||||
update.channel.dev.hint=ベータ版を使用しています。ベータ版には、リリースバージョンと比較していくつかの追加機能が含まれている可能性があり、テストにのみ使用されます。\n\
|
||||
ベータ版は不安定なはずです!\n\
|
||||
問題が発生した場合は、<a href="hmcl://settings/feedback">フィードバックページ</a>にアクセスして報告するか、チャット <a href="https://discord.gg/jVvC7HfM6U">Discord</a>または<a href="https://kook.top/Kx7n3t">KOOK</a>で問題を報告します。\n\n\
|
||||
現在のテスト版のヒントを非表示にするには、<a href="hmcl://hide-announcement">ここをクリックしてください</a>。
|
||||
update.channel.dev.title=ベータ版のヒント
|
||||
update.channel.nightly=アルファ
|
||||
update.channel.nightly.hint=アルファ版を使用しています。これには、ベータ版およびリリース版と比較していくつかの追加機能が含まれている可能性があり、テストにのみ使用されます。\n \
|
||||
アルファ版は不安定です!\n \
|
||||
問題が発生した場合は、<a href="hmcl://settings/feedback">フィードバックページ</a>にアクセスして報告するか、チャット <a href="https://discord.gg/jVvC7HfM6U">Discord</a>または<a href="https://kook.top/Kx7n3t">KOOK</a>で問題を報告します。\n \n \
|
||||
このヒントを非表示にするには、<a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">寄付</a>するか、フィードバックに印象的な貢献をする必要があります。
|
||||
update.channel.nightly.hint=アルファ版を使用しています。これには、ベータ版およびリリース版と比較していくつかの追加機能が含まれている可能性があり、テストにのみ使用されます。\n\
|
||||
アルファ版は不安定です!\n\
|
||||
問題が発生した場合は、<a href="hmcl://settings/feedback">フィードバックページ</a>にアクセスして報告するか、チャット <a href="https://discord.gg/jVvC7HfM6U">Discord</a>または<a href="https://kook.top/Kx7n3t">KOOK</a>で問題を報告します。
|
||||
update.channel.nightly.title=アルファ版のヒント
|
||||
update.channel.stable=リリース
|
||||
update.checking=更新の確認
|
||||
@@ -897,6 +899,7 @@ 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=すべてのゲームリソースファイルの削除
|
||||
version.manage.remove_libraries=ライブラリファイルを削除します
|
||||
version.manage.rename=このバージョンの名前を変更します
|
||||
version.manage.rename.message=このバージョンの新しい名前を入力してください
|
||||
|
||||
@@ -93,7 +93,7 @@ account.methods.microsoft.error.missing_xbox_account=Ваш аккаунт Micro
|
||||
account.methods.microsoft.error.no_character=На аккаунте отсутствует профиль Minecraft Java. \nФайл игры не может быть создан, пожалуйста,\nнажмите на ссылку выше, чтобы создать его
|
||||
account.methods.microsoft.error.unknown=Не удалось войти. Microsoft отвечает с кодом ошибки %d.
|
||||
account.methods.microsoft.logging_in=Авторизация...
|
||||
account.methods.microsoft.makegameidsettings=Создать архив
|
||||
account.methods.microsoft.makegameidsettings=Создать архив / изменение имени профиля
|
||||
account.methods.microsoft.hint=Вам необходимо нажать кнопку «Войти» и продолжить процесс авторизации во вновь открывшемся окне браузера.\nЕсли токен, используемый для входа в аккаунт Microsoft случайно утёк, вы можете нажать «Отменить авторизацию аккаунта» ниже, чтобы отменить авторизацию.
|
||||
account.methods.microsoft.manual=После нажатия кнопки «Войти», вы должны завершить авторизацию во вновь открывшемся окне браузера. Если окно браузера не открылось, вы можете щёлкнуть здесь, чтобы скопировать ссылку и вручную открыть её в браузере.\nЕсли токен, используемый для входа в аккаунт Microsoft случайно утёк, вы можете нажать «Отменить авторизацию аккаунта» ниже, чтобы отменить авторизацию.
|
||||
account.methods.microsoft.profile=Профиль аккаунта...
|
||||
@@ -171,7 +171,7 @@ curse.category.4477=Mini Game
|
||||
curse.category.4478=Quests
|
||||
curse.category.4484=Multiplayer
|
||||
curse.category.4476=Exploration
|
||||
curse.category.4736=Skyblock
|
||||
curse.category.6145=Skyblock
|
||||
curse.category.4475=Adventure and RPG
|
||||
curse.category.4487=FTB
|
||||
curse.category.4480=Map Based
|
||||
@@ -351,6 +351,8 @@ game.crash.reason.mod_resolution0=Текущая игра не может про
|
||||
game.crash.reason.mod_profile_causes_game_crash=Текущая игра не может продолжать работать из-за проблемы с профилем мода. \nВы можете проверить журнал на наличие неисправного мода и его конфигурационного файла.
|
||||
game.crash.reason.fabric_reports_an_error_and_gives_a_solution=Forge мог выдать сообщение об ошибке. \nВы можете просмотреть журнал и выполнить соответствующие действия в соответствии с информацией журнала в отчете об ошибках. \nЕсли вы не видите сообщения об ошибке, вы можете просмотреть отчет об ошибке, чтобы узнать, как она возникла.
|
||||
game.crash.reason.java_version_is_too_high=Текущая игра аварийно завершилась из-за того, что версия Java слишком высока и не может продолжать работать. \nПеред запуском игры переключитесь на более раннюю версию Java на вкладке "Путь к Java" в глобальных настройках игры или в настройках игры. \nЕсли нет, вы можете загрузить его с <a href="https://www.java.com/download/">java.com (Java8)</a> или <a href="https://bell- sw.com/pages/downloads">BellSoft Liberica Full JRE (Java17)</a> и другие платформы, чтобы загрузить и установить ее (перезапустите программу запуска после установки).
|
||||
game.crash.reason.mod_name=Текущая игра не может продолжать работать из - за проблем с именем файла Mod. Имя файла \nMod должно быть использовано только в английском языке в полном углу с большими буквами (Aa ~ Zz), цифрами (0 ~ 9), горизонтальными линиями (-), подчеркнутыми (_) и точками (.) . \nПожалуйста, добавьте символ соответствия в папку Mod для всех несовместимых имен файлов Mod.
|
||||
game.crash.reason.incomplete_forge_installation=Текущая игра не может быть продолжена из-за незавершенной установки Forge. \nУдалите и переустановите Forge в настройках версии - Автоматическая установка.
|
||||
game.crash.reason.file_already_exists=Невозможно запустить игру из-за того, что файл %1$s уже существует.\nЕсли его можно удалить, создайте резервную копию и удалите его, затем попробуйте снова.
|
||||
game.crash.reason.file_changed=Невозможно запустить игру из-за сбоя проверки файла.\nЕсли вы изменили первичный jar Minecraft, вам нужно откатить изменения или скачать игру заново.
|
||||
game.crash.reason.gl_operation_failure=Игра вылетела из-за некоторых модов, шейдер-паков, текстур-паков.\nОтключите используемые моды или наборы шейдеров/текстур и попробуйте снова.
|
||||
@@ -708,6 +710,7 @@ selector.custom=Пользовательский
|
||||
settings=Настройки
|
||||
|
||||
settings.advanced=Расширенные настройки
|
||||
settings.advanced.title=Расширенные настройки - %s
|
||||
settings.advanced.custom_commands=Пользовательские команды
|
||||
settings.advanced.custom_commands.hint=Пользовательские команды выполняются со следующими переменными окружения:\n\
|
||||
\ - $INST_NAME: название версии\n\
|
||||
@@ -852,13 +855,12 @@ update.channel.dev=Бета
|
||||
update.channel.dev.hint=Вы используете бета-версию, которая может включать некоторые дополнительные функции по сравнению с релизной версией, используемой только для тестирования.\n\
|
||||
Бета-версия может быть нестабильной!\n\
|
||||
Если вы встретили какие-то проблемы, вы можете зайти на <a href="hmcl://settings/feedback">страницу обратной связи</a>, чтобы сообщить о них, или присоединиться к чату <a href="https://discord.gg/jVvC7HfM6U">Discord</a> или <a href="https://kook.top/Kx7n3t">KOOK</a>, чтобы сообщить о проблемах.\n\n\
|
||||
Чтобы скрыть эту подсказку, нужно <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">пожертвовать</a> или сделать внушительный вклад через обратную связь.
|
||||
<a href="hmcl://hide-announcement">Нажмите здесь</a>, чтобы скрыть подсказку для текущей тестовой версии.
|
||||
update.channel.dev.title=Подсказки для бета-версии
|
||||
update.channel.nightly=Альфа
|
||||
update.channel.nightly.hint=Вы используете альфа-версию, которая может включать некоторые дополнительные функциональные возможности по сравнению с бета-версией и версией релиза, используемой только для тестирования.\n\
|
||||
Альфа-версия может быть нестабильной!\n\
|
||||
Если вы встретили какие-то проблемы, вы можете зайти на <a href="hmcl://settings/feedback">страницу обратной связи</a>, чтобы сообщить о них, или присоединиться к чату <a href="https://discord.gg/jVvC7HfM6U">Discord</a> или <a href="https://kook.top/Kx7n3t">KOOK</a>, чтобы сообщить о проблемах.\n\n\
|
||||
Чтобы скрыть эту подсказку, нужно <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">пожертвовать</a> или сделать внушительный вклад через обратную связь.
|
||||
Если вы встретили какие-то проблемы, вы можете зайти на <a href="hmcl://settings/feedback">страницу обратной связи</a>, чтобы сообщить о них, или присоединиться к чату <a href="https://discord.gg/jVvC7HfM6U">Discord</a> или <a href="https://kook.top/Kx7n3t">KOOK</a>, чтобы сообщить о проблемах.
|
||||
update.channel.nightly.title=Подсказки для альфа-версии
|
||||
update.channel.stable=Релиз
|
||||
update.checking=Проверка наличия обновлений
|
||||
@@ -903,6 +905,7 @@ 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=Удалить файлы игровых активов
|
||||
version.manage.remove_libraries=Удалить файлы библиотек
|
||||
version.manage.rename=Переименовать
|
||||
version.manage.rename.message=Введите новое название для этой версии
|
||||
|
||||
@@ -67,8 +67,10 @@ account.failed.server_disconnected=無法訪問登錄伺服器,賬戶信息刷
|
||||
您可以選擇“再次刷新賬戶”重新嘗試。 \n\
|
||||
您也可以選擇“跳過賬戶刷新”繼續啟動遊戲,但可能會使賬戶信息不是最新的。\n\
|
||||
若最近沒有刷新賬戶信息,則可能導致賬戶信息過期失效,\n\
|
||||
若為 微軟賬戶 啟動遊戲,賬戶信息過期失效可能將無法進入需賬戶驗證的伺服器。
|
||||
若為 微軟賬戶 啟動遊戲,賬戶信息過期失效可能將無法進入需賬戶驗證的伺服器。\n\
|
||||
若嘗試多次無法成功刷新,可嘗試重新添加該賬戶嘗試解決該問題。
|
||||
account.failed.server_response_malformed=無法解析認證伺服器回應,可能是伺服器故障
|
||||
account.failed.ssl=連接服務器時發生了 SSL 錯誤,可能網站證書已過期或你使用的 Java 版本過低,請嘗試更新 Java
|
||||
account.failed.wrong_account=登錄了錯誤的帳號
|
||||
account.hmcl.hint=你需要點擊“登入”按鈕,並在打開的網頁中完成登入
|
||||
account.injector.add=新增認證伺服器
|
||||
@@ -81,7 +83,7 @@ account.injector.server_url=伺服器位址
|
||||
account.injector.server_name=伺服器名稱
|
||||
account.login=登入
|
||||
account.login.hint=我們不會保存你的密碼
|
||||
account.login.skip=重新刷新帳戶
|
||||
account.login.skip=跳過刷新帳戶
|
||||
account.login.retry=再次刷新帳戶
|
||||
account.login.refresh=重新登錄
|
||||
account.login.refresh.microsoft.hint=因為賬戶授權失效,你需要重新添加微軟賬戶
|
||||
@@ -101,7 +103,7 @@ account.methods.microsoft.error.missing_xbox_account=你的微軟帳號尚未關
|
||||
account.methods.microsoft.error.no_character=該帳戶未包含 Minecraft Java 版購買記錄\n可能未創建遊戲檔案,請點擊上方鏈接創建
|
||||
account.methods.microsoft.error.unknown=登入失敗,錯誤碼:%d
|
||||
account.methods.microsoft.logging_in=登入中...
|
||||
account.methods.microsoft.makegameidsettings=創建檔案
|
||||
account.methods.microsoft.makegameidsettings=創建檔案/編輯檔案名稱
|
||||
account.methods.microsoft.hint=你需要按照以下步驟添加賬戶:\n\
|
||||
1.點擊“登入”按鈕\n\
|
||||
2.在網頁瀏覽器顯示的網站中輸入 HMCL 顯示的代碼(自動拷貝,直接粘貼即可),並點擊“下一步”\n\
|
||||
@@ -205,7 +207,7 @@ curse.category.4477=小遊戲
|
||||
curse.category.4478=任務
|
||||
curse.category.4484=多人
|
||||
curse.category.4476=探索
|
||||
curse.category.4736=空島
|
||||
curse.category.6145=空島
|
||||
curse.category.4475=冒險 RPG
|
||||
curse.category.4487=FTB 模組包
|
||||
curse.category.4480=有特定地圖
|
||||
@@ -347,6 +349,7 @@ extension.png=圖片檔案
|
||||
extension.ps1=PowerShell 指令碼
|
||||
extension.sh=Bash 指令碼
|
||||
|
||||
fatal.fractureiser=Hello Minecraft! Launcher 檢測到你的電腦被 Fractureiser 病毒感染,存在嚴重安全問題。\n請立即使用殺毒軟體進行全盤查殺,隨後修改你在此電腦上登入過的所有帳號的密碼。
|
||||
fatal.javafx.incompatible=缺少 JavaFX 運行環境。\nHMCL 無法在低於 Java 11 的 Java 環境上自行補全 JavaFX 運行環境,請更新到 Java 11 或更高版本。
|
||||
fatal.javafx.incompatible.loongson=缺少 JavaFX 運行環境。\n請使龍芯 JDK 8 (http://www.loongnix.cn/zh/api/java/downloads-jdk8/index.html) 啟動 HMCL。
|
||||
fatal.javafx.missing=找不到 JavaFX,
|
||||
@@ -354,6 +357,7 @@ fatal.config_change_owner_root=你正在使用 root 帳戶啟動 Hello Minecraft
|
||||
fatal.config_in_temp_dir=你正在臨時資料夾中啟動 Hello Minecraft! Launcher,你的設定和遊戲數據可能會遺失,建議將 HMCL 移動至其他位置再啟動。\n是否繼續啟動?
|
||||
fatal.config_loading_failure=Hello Minecraft! Launcher 無法載入設定檔案。\n請確保 Hello Minecraft! Launcher 對 "%s" 目錄及該目錄下的檔案擁有讀寫權限。
|
||||
fatal.config_loading_failure.unix=Hello Minecraft! Launcher 無法載入設定檔案,因為設定檔案是由用戶 %1$s 創建的。\n請使用 root 帳戶啟動 HMCL (不推薦),或在終端中執行以下命令將設定檔案的所有權變更為當前用戶: \n%2$s
|
||||
fatal.mac_app_translocation=由於 macOS 的安全機制,Hello Minecraft! Launcher 被系統隔離至臨時資料夾中。\n請將Hello Minecraft! Launcher 移動到其他資料夾後再嘗試啟動,否則你的設定和遊戲數據可能會在重啟後遺失。\n是否繼續啟動?
|
||||
fatal.migration_requires_manual_reboot=Hello Minecraft! Launcher 即將升級完成,請重新開啟 Hello Minecraft! Launcher。
|
||||
fatal.apply_update_failure=我們很抱歉 Hello Minecraft! Launcher 無法自動完成升級程式,因為出現了一些問題。\n但你依然可以從 %s 處手動下載 Hello Minecraft! Launcher 來完成升級。\n你可以訪問 https://docs.hmcl.net/help.html 網頁進行迴響。
|
||||
fatal.samba=如果您正在通過 Samba 共亯的資料夾中運行 Hello Minecraft! Launcher,啟動器可能無法正常工作,請嘗試更新您的 Java 或在本地資料夾內運行 HMCL。
|
||||
@@ -403,6 +407,8 @@ game.crash.reason.mod_resolution0=當前遊戲因為一些 Mod 出現問題,
|
||||
game.crash.reason.mod_profile_causes_game_crash=當前遊戲因為 Mod 配置文件出現問題,無法繼續運行。\n你可以查看日誌尋找出錯模組及其配置文件。
|
||||
game.crash.reason.fabric_reports_an_error_and_gives_a_solution=Forge 可能已經提供了錯誤信息。\n你可以查看日誌,並根據錯誤報告中的日誌信息進行對應處。\n如果沒有看到報錯信息,可以查看錯誤報告了解錯誤具體是如何發生的。
|
||||
game.crash.reason.java_version_is_too_high=當前遊戲因為使用的 Java 版本過高而崩潰了,無法繼續運行。\n請在 全局遊戲設置 或 遊戲特定設置 的 Java 路徑選項卡中改用較低版本的 Java,然後再啟動遊戲。\n如果沒有,可以從 <a href="https://www.java.com/download/">java.com(Java8)</a> 或 <a href="https://bell-sw.com/pages/downloads">BellSoft Liberica Full JRE(Java17)</a> 等平台下載、安裝一個(安裝完後需重啟啟動器)。
|
||||
game.crash.reason.mod_name=當前遊戲因為 Mod 檔案名稱問題,無法繼續運行。 \nMod 檔案名稱應只使用英文全半型的大小寫字母(Aa~Zz)、數位(0~9)、橫線(-)、底線(_)和點(.)。\n請到Mod資料夾中將所有不合規的Mod檔案名稱添加一個上述的合規的字元。
|
||||
game.crash.reason.incomplete_forge_installation=當前遊戲因為 Forge 安裝不完整,無法繼續運行。 \n請在 版本設置 - 自動安裝 中卸載 Forge 並重新安裝。
|
||||
game.crash.reason.file_already_exists=當前遊戲因為文件 %1$s 已經存在,無法繼續運行。\n如果你認為這個文件可以刪除,你可以在備份這個文件後嘗試刪除它,並重新啟動遊戲。
|
||||
game.crash.reason.file_changed=當前遊戲因為檔案校驗失敗,無法繼續運行。\n如果你手動修改了 Minecraft.jar 檔案,你需要回退修改,或者重新下載遊戲。
|
||||
game.crash.reason.gl_operation_failure=當前遊戲因為你使用的某些 Mod、光影包、材質包,無法繼續運行。\n請先嘗試禁用你所使用的Mod/光影包/材質包再試。
|
||||
@@ -827,6 +833,8 @@ selector.custom=自訂
|
||||
settings=遊戲設定
|
||||
|
||||
settings.advanced=進階設定
|
||||
settings.advanced.modify=修改進階設定
|
||||
settings.advanced.title=進階設定 - %s
|
||||
settings.advanced.custom_commands=自訂命令
|
||||
settings.advanced.custom_commands.hint=自訂命令被調用時將包含如下的環境變數:\n\
|
||||
\ - $INST_NAME: 版本名稱\n\
|
||||
@@ -842,6 +850,7 @@ settings.advanced.custom_commands.hint=自訂命令被調用時將包含如下
|
||||
settings.advanced.dont_check_game_completeness=不檢查遊戲完整性
|
||||
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、libraries)
|
||||
settings.advanced.java_permanent_generation_space=記憶體永久儲存區域
|
||||
@@ -874,13 +883,17 @@ settings.advanced.process_priority.above_normal=較高(優先保證遊戲運
|
||||
settings.advanced.process_priority.high=高(優先保證遊戲運行,但可能會導致其他程式卡頓)
|
||||
settings.advanced.post_exit_command=遊戲結束後執行命令
|
||||
settings.advanced.post_exit_command.prompt=將在遊戲結束後呼叫使用
|
||||
settings.advanced.renderer=渲染器
|
||||
settings.advanced.renderer.default=OpenGL(默認)
|
||||
settings.advanced.renderer.d3d12=DirectX 12(效能與相容性較差,用於調試)
|
||||
settings.advanced.renderer.llvmpipe=軟渲染器(效能較差,相容性最好)
|
||||
settings.advanced.renderer.zink=Vulkan(效能最好,相容性較差)
|
||||
settings.advanced.server_ip=伺服器位址
|
||||
settings.advanced.server_ip.prompt=預設,啟動遊戲後直接進入對應伺服器
|
||||
settings.advanced.use_native_glfw=[Linux] 使用系統 GLFW
|
||||
settings.advanced.use_native_openal=[Linux] 使用系統 OpenAL
|
||||
settings.advanced.use_software_renderer=使用 OpenGL 軟渲染器(相容性更好,但效能較差)
|
||||
settings.advanced.workaround=除錯選項
|
||||
settings.advanced.workaround.warning=除錯選項僅提供給專業玩家使用。修改除錯選項可能會導致遊戲無法啟動。除非你知道你在做什麼,否則請你不要修改這些選項。
|
||||
settings.advanced.workaround.warning=除錯選項僅提供給專業玩家使用。修改除錯選項可能會導致遊戲無法啟動。除非你知道你在做什麼,否則請不要修改這些選項。
|
||||
settings.advanced.wrapper_launcher=前置指令
|
||||
settings.advanced.wrapper_launcher.prompt=如填寫 optirun 後,啟動命令將從 "java ..." 變為 "optirun java ..."
|
||||
|
||||
@@ -976,13 +989,12 @@ update.channel.dev=測試版
|
||||
update.channel.dev.hint=你正在使用測試版。測試版包含一些未在正式版中包含的測試性功能,僅用於體驗新功能。\n\
|
||||
測試版功能未受充分驗證,使用起來可能不穩定!\n\
|
||||
如果你遇到了使用問題,可以在設置的 <a href="hmcl://settings/feedback">回饋頁面</a> 中進行回饋,或加入回饋頁面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kook.top/Kx7n3t">KOOK 群</a>以回饋問題。\n\n\
|
||||
你需要 <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">贊助</a> 或在回饋過程中作出貢獻以隱藏本提示。
|
||||
<a href="hmcl://hide-announcement">點擊此處</a>為當前版本隱藏該提示。
|
||||
update.channel.dev.title=測試版提示
|
||||
update.channel.nightly=預覽版
|
||||
update.channel.nightly.hint=你正在使用預覽版。預覽版可能會每天更新一次,包含一些未在正式版和測試版中包含的測試性功能,僅用於體驗新功能\n\
|
||||
測試版功能未受充分驗證,使用起來可能不穩定!\n\
|
||||
如果你遇到了使用問題,可以在設置的 <a href="hmcl://settings/feedback">回饋頁面</a> 中進行回饋,或加入回饋頁面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kook.top/Kx7n3t">KOOK 群</a>以回饋問題。\n\n\
|
||||
你需要 <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">贊助</a> 或在回饋過程中作出貢獻以隱藏本提示。
|
||||
如果你遇到了使用問題,可以在設置的 <a href="hmcl://settings/feedback">回饋頁面</a> 中進行回饋,或加入回饋頁面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kook.top/Kx7n3t">KOOK 群</a>以回饋問題。
|
||||
update.channel.nightly.title=預覽版提示
|
||||
update.channel.stable=建議版本
|
||||
update.checking=正在檢查更新
|
||||
@@ -1027,6 +1039,7 @@ 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=刪除所有遊戲資源檔案
|
||||
version.manage.remove_libraries=刪除所有函式庫檔案
|
||||
version.manage.rename=重新命名該版本
|
||||
version.manage.rename.message=請輸入新名稱
|
||||
|
||||
@@ -67,8 +67,10 @@ account.failed.server_disconnected=无法访问登录服务器,账户信息刷
|
||||
你可以选择“再次刷新账户”重新尝试。\n\
|
||||
你也可以选择“跳过账户刷新”继续启动游戏,但可能会使账户信息不是最新的。\n\
|
||||
若最近没有刷新账户信息,则可能导致账户信息过期失效,\n\
|
||||
若为 微软账户 启动游戏,账户信息过期失效可能将无法进入需账户验证的服务器。
|
||||
若为 微软账户 启动游戏,账户信息过期失效可能将无法进入需账户验证的服务器。\n\
|
||||
若尝试多次无法成功刷新,可尝试重新添加该账户尝试解决该问题。
|
||||
account.failed.server_response_malformed=无法解析认证服务器响应,可能是服务器故障
|
||||
account.failed.ssl=连接服务器时发生了 SSL 错误,可能网站证书已过期或你使用的 Java 版本过低,请尝试更新 Java
|
||||
account.failed.wrong_account=登录了错误的帐号
|
||||
account.hmcl.hint=你需要点击“登录”按钮,并在打开的网页中完成登录
|
||||
account.injector.add=添加认证服务器
|
||||
@@ -101,7 +103,7 @@ account.methods.microsoft.error.missing_xbox_account=你的微软帐户尚未关
|
||||
account.methods.microsoft.error.no_character=该帐户未包含 Minecraft Java 版购买记录\n若已购买,则可能未创建游戏档案,请点击上方链接创建。\n若确定该账号完成了上述步骤,请先在 Minecraft 官网(minecraft.net)登录一次账户,然后再在启动器登录。
|
||||
account.methods.microsoft.error.unknown=登录失败,错误码:%d
|
||||
account.methods.microsoft.logging_in=登录中……
|
||||
account.methods.microsoft.makegameidsettings=创建档案
|
||||
account.methods.microsoft.makegameidsettings=创建档案/编辑档案名称
|
||||
account.methods.microsoft.hint=你需要按照以下步骤添加账户:\n\
|
||||
1.点击“登录”按钮\n\
|
||||
2.在网页浏览器显示的网站中输入 HMCL 显示的代码(自动拷贝,直接粘贴即可),并点击“下一步”\n\
|
||||
@@ -204,7 +206,7 @@ curse.category.4477=小游戏
|
||||
curse.category.4478=任务
|
||||
curse.category.4484=多人
|
||||
curse.category.4476=探索
|
||||
curse.category.4736=空岛
|
||||
curse.category.6145=空岛
|
||||
curse.category.4475=冒险 RPG
|
||||
curse.category.4487=FTB 整合包
|
||||
curse.category.4480=有特定地图
|
||||
@@ -347,6 +349,7 @@ extension.png=图片文件
|
||||
extension.ps1=PowerShell 脚本
|
||||
extension.sh=Bash 脚本
|
||||
|
||||
fatal.fractureiser=Hello Minecraft! Launcher 检测到你的电脑被 Fractureiser 病毒感染,存在严重安全问题。\n请立即使用杀毒软件进行全盘查杀,随后修改你在此电脑上登陆过的所有账号的密码。
|
||||
fatal.javafx.incompatible=缺少 JavaFX 运行环境。\nHello Minecraft! Launcher 无法在低于 Java 11 的 Java 环境上自行补全 JavaFX 运行环境,请更新到 Java 11 或更高版本。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。
|
||||
fatal.javafx.incompatible.loongson=缺少 JavaFX 运行环境。\n请使用龙芯 JDK 8 (http://www.loongnix.cn/zh/api/java/downloads-jdk8/index.html) 启动 HMCL。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。
|
||||
fatal.javafx.missing=缺少 JavaFX 运行环境,请使用包含 OpenJFX 的 Java 运行环境启动 Hello Minecraft! Launcher。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。
|
||||
@@ -354,6 +357,7 @@ fatal.config_change_owner_root=你正在使用 root 账户启动 Hello Minecraft
|
||||
fatal.config_in_temp_dir=你正在临时文件夹中启动 Hello Minecraft! Launcher, 你的设置和游戏数据可能会丢失,建议将 HMCL 移动至其他位置再启动。\n是否继续启动?
|
||||
fatal.config_loading_failure=Hello Minecraft! Launcher 无法加载配置文件\n请确保 Hello Minecraft! Launcher 对 "%s" 目录及该目录下的文件拥有读写权限。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。
|
||||
fatal.config_loading_failure.unix=Hello Minecraft! Launcher 无法加载配置文件,因为配置文件是由用户 %1$s 创建的。\n请使用 root 账户启动 HMCL (不推荐),或在终端中执行以下命令将配置文件的所有权变更为当前用户:\n%2$s\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。
|
||||
fatal.mac_app_translocation=由于 macOS 的安全机制,Hello Minecraft! Launcher 被系统隔离至临时文件夹中。\n请将 Hello Minecraft! Launcher 移动到其他文件夹后再尝试启动,否则你的设置和游戏数据可能会在重启后丢失。\n是否继续启动?
|
||||
fatal.migration_requires_manual_reboot=Hello Minecraft! Launcher 即将完成升级,请重新打开 Hello Minecraft! Launcher。
|
||||
fatal.apply_update_failure=我们很抱歉 Hello Minecraft! Launcher 无法自动完成升级,因为出现了一些问题。\n但你依可以从 %s 处手动下载 Hello Minecraft! Launcher 来完成升级\n你可以访问 https://docs.hmcl.net/help.html 网页进行反馈。
|
||||
fatal.samba=如果你正在通过 Samba 共享的文件夹中运行 Hello Minecraft! Launcher,启动器可能无法正常工作。请尝试更新你的 Java 或在本地文件夹内运行 Hello Minecraft! Launcher。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。
|
||||
@@ -398,12 +402,12 @@ game.crash.reason.fabric_warnings=Fabric 提供了一些警告信息:\n%1$s \n
|
||||
game.crash.reason.file_already_exists=当前游戏因为文件 %1$s 已经存在,无法继续运行。\n如果你认为这个文件可以删除,你可以在备份这个文件后尝试删除它,并重新启动游戏。 \n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.file_changed=当前游戏因为文件校验失败,无法继续运行。\n如果你手动修改了 Minecraft.jar 文件,你需要回退修改,或者重新下载游戏。 \n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.gl_operation_failure=当前游戏因为你使用的某些 Mod、光影包、材质包,无法继续运行。\n请先尝试禁用你所使用的Mod/光影包/材质包再试。 \n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.graphics_driver=当前游戏因为你的显卡驱动存在问题崩溃了,请尝试:\n\
|
||||
game.crash.reason.graphics_driver=当前游戏因为显卡驱动问题而崩溃,请尝试以下操作:\n\
|
||||
- 如果你的电脑存在独立显卡,请尝试使用 独立显卡 而非 Intel 核显启动 HMCL 与游戏 <a href="https://www.bing.com/search?q=用独立显卡运行程序">详情</a>;\n\
|
||||
- <a href="https://minecrafthopper.net/help/pixel-format-not-accelerated/">尝试升级你的 显卡驱动 到最新版本</a>,或回退到出厂版本;\n\
|
||||
- 如果你确实需要使用核芯显卡,请检查你的电脑的 CPU 是否是 Intel(R) Core(TM) 3000 系列或更旧的处理器,如果是,对于 Minecraft 1.16.5 及更旧版本,请你将游戏所使用的 Java 版本降级至 1.8.0_51 及以下版本 <a href="https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html">Java 1.8.0 历史版本</a> ,否则请跳过;\n\
|
||||
- 在全局(特定)游戏设置,菜单底部中打开“使用 OpenGL 软渲染器”选项可以尝试解决此问题,但打开此选项后在 CPU 性能不足的情况下帧数会显著降低,请慎重选择(仅推荐以调试为目的或应急时开启)\n\
|
||||
如果仍有问题,你可能需要考虑换一个新显卡或新电脑。\n\
|
||||
- 在游戏设置中打开“使用 OpenGL 软渲染器”(开启此选项后帧数会显著降低,仅推荐在以调试为目的或应急时开启)。\n\
|
||||
如果仍有问题,你可能需要考虑换一张新显卡或一台新电脑。\n\
|
||||
你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.illegal_access_error=当前游戏因为某些 Mod 的问题,无法继续运行。\n如果你认识:%1$s,你可以更新或删除对应 Mod 再试。\n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.jdk_9=当前游戏因为 Java 版本过高,无法继续运行。\n你需要下载安装 <a href="https://bell-sw.com/pages/downloads/#downloads">Java 8</a>,并在全局(特定)游戏设置中将 Java 设置为 1.8 的版本。\n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
@@ -427,6 +431,8 @@ game.crash.reason.forge_error=Forge 可能已经提供了错误信息。\n你可
|
||||
game.crash.reason.mod_resolution0=当前游戏因为一些 Mod 出现问题,无法继续运行。\n你可以查看日志寻找出错模组。\n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.fabric_reports_an_error_and_gives_a_solution=Fabric 可能已经提供了错误信息。\n你可以查看日志,并根据错误报告中的日志信息进行对应处。\n如果没有看到报错信息,可以查看错误报告了解错误具体是如何发生的。\n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.java_version_is_too_high=当前游戏因为 Java 虚拟机版本过高,无法继续运行。\n请在全局(特定)游戏设置的 Java 路径选项卡中改用较低版本的 Java,然后再启动游戏。\n如果没有,可以从 <a href="https://www.java.com/download/">java.com(Java8)</a> 或 <a href="https://bell-sw.com/pages/downloads">BellSoft Liberica Full JRE(Java17)</a> 等平台下载、安装一个(安装完后需重启启动器)。
|
||||
game.crash.reason.mod_name=当前游戏因为 Mod 文件名称问题,无法继续运行。\nMod 文件名称应只使用英文全半角的大小写字母(Aa~Zz)、数字(0~9)、横线(-)、下划线(_)和点(.)。\n请到 Mod 文件夹中将所有不合规的 Mod 文件名称添加一个上述的合规的字符。\n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.incomplete_forge_installation=当前游戏因为 Forge 安装不完整,无法继续运行。\n请在 版本设置 - 自动安装 中卸载 Forge 并重新安装。\n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.optifine_is_not_compatible_with_forge=当前游戏因为 OptiFine 与当前版本的 Forge 不兼容,导致了游戏崩溃。\n请前往 <a href="https://optifine.net/downloads">OptiFine 官网</a> 查看 OptiFine 所兼容的 Forge 版本,并严格按照对应版本重新安装游戏或在 版本设置 - 自动安装 中更换版本。\n经测试,Forge 版本过高或过低都可能导致崩溃。 \n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.mod_files_are_decompressed=当前游戏因为 Mod 文件被解压了,无法继续运行。\n请直接把整个 Mod 文件放进 Mod 文件夹中即可。\n解压 Mod 会导致游戏出错,请删除 Mod 文件夹中已被解压的 Mod,然后再启动游戏。 \n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.too_many_mods_lead_to_exceeding_the_id_limit=当前游戏因为您所安装的 Mod 过多,超出了游戏的 ID 限制,无法继续运行。\n请尝试安装 <a href="https://www.curseforge.com/minecraft/mc-mods/jeid">JEID</a> 等修复 Mod,或删除部分大型 Mod。 \n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
@@ -436,7 +442,7 @@ game.crash.reason.no_class_def_found_error=当前游戏因为代码不完整,
|
||||
game.crash.reason.no_such_method_error=当前游戏因为代码不完整,无法继续运行。\n你的游戏可能缺失了某个 Mod,或者某些 Mod 文件不完整,或者 Mod 与游戏的版本不匹配。\n你可能需要重新安装游戏和 Mod,或请求他人帮助。 \n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.opengl_not_supported=当前游戏因为你的显卡驱动存在问题,无法继续运行。\n原因是 OpenGL 不受支持,你现在是否在远程桌面或者串流模式下?如果是,请直接使用原电脑启动游戏。\n或者尝试升级你的显卡驱动到最新版本后再尝试启动游戏。如果你的电脑存在独立显卡,你需要检查游戏是否使用集成/核心显卡启动,如果是,请尝试使用独立显卡启动 HMCL 与游戏。如果仍有问题,你可能需要考虑换一个新显卡或新电脑。 \n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.openj9=当前游戏无法运行在 OpenJ9 虚拟机上,请你在全局(特定)游戏设置中更换 Hotspot Java 虚拟机,并重新启动游戏。如果没有下载安装,你可以在网上自行下载。 \n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.out_of_memory=当前游戏因为内存不足,无法继续运行。\n这可能是内存分配太小,或者 Mod 数量过多导致的。\n你可以在全局(特定)游戏设置中调大游戏内存分配值以允许游戏在更大的内存下运行。\n如果仍然出现该错误,你可能需要换一台更好的电脑。 \n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.out_of_memory=当前游戏因为内存不足,无法继续运行。\n这可能是内存分配太小,或者 Mod 数量过多导致的。\n你可以在全局(特定)游戏设置中调大游戏内存分配值以允许游戏在更大的内存下运行。\n如果仍然出现该错误,你可能需要换一台更好的电脑。 \n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.resolution_too_high=当前游戏因为材质包分辨率过高,无法继续运行\n你可以更换一个分辨率更低的材质,或者更换一个显存更大的显卡。 \n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
game.crash.reason.stacktrace=原因未知,请点击日志按钮查看详细信息。\n下面是一些关键词,其中可能包含 Mod 名称,你可以通过搜索的方式查找有关信息。\n%s
|
||||
game.crash.reason.too_old_java=当前游戏因为 Java 虚拟机版本过低,无法继续运行。\n你需要在全局(特定)游戏设置中更换 Java %1$s 或更新版本的 Java 虚拟机,并重新启动游戏。如果没有下载安装,你可以点击 <a href="https://bell-sw.com/pages/downloads/#downloads">此处</a> 下载 Liberica JDK。\n你可以在 <a href="https://docs.hmcl.net/help.html ">此处</a> 寻求帮助。
|
||||
@@ -825,6 +831,8 @@ selector.custom=自定义
|
||||
settings=设置
|
||||
|
||||
settings.advanced=高级设置
|
||||
settings.advanced.modify=修改高级设置
|
||||
settings.advanced.title=高级设置 - %s
|
||||
settings.advanced.custom_commands=自定义命令
|
||||
settings.advanced.custom_commands.hint=自定义命令被调用时将包含如下的环境变量:\n\
|
||||
\ - $INST_NAME: 版本名称\n\
|
||||
@@ -840,6 +848,7 @@ settings.advanced.custom_commands.hint=自定义命令被调用时将包含如
|
||||
settings.advanced.dont_check_game_completeness=不检查游戏完整性
|
||||
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、libraries 外)
|
||||
settings.advanced.java_permanent_generation_space=内存永久保存区域
|
||||
@@ -872,13 +881,17 @@ settings.advanced.process_priority.above_normal=较高(优先保证游戏运
|
||||
settings.advanced.process_priority.high=高(优先保证游戏运行,但可能会导致其他程序卡顿)
|
||||
settings.advanced.post_exit_command=游戏结束后执行命令
|
||||
settings.advanced.post_exit_command.prompt=将在游戏结束后调用
|
||||
settings.advanced.renderer=渲染器
|
||||
settings.advanced.renderer.default=OpenGL(默认)
|
||||
settings.advanced.renderer.d3d12=DirectX 12(性能与兼容性较差,用于调试)
|
||||
settings.advanced.renderer.llvmpipe=软渲染器(性能较差,兼容性最好)
|
||||
settings.advanced.renderer.zink=Vulkan(性能最好,兼容性较差)
|
||||
settings.advanced.server_ip=服务器地址
|
||||
settings.advanced.server_ip.prompt=默认,启动游戏后可以直接进入对应服务器
|
||||
settings.advanced.use_native_glfw=[Linux] 使用系统 GLFW
|
||||
settings.advanced.use_native_openal=[Linux] 使用系统 OpenAL
|
||||
settings.advanced.use_software_renderer=使用 OpenGL 软渲染器(兼容性更好,但性能较差)
|
||||
settings.advanced.workaround=调试选项
|
||||
settings.advanced.workaround.warning=调试选项仅提供给专业玩家使用。调试选项可能会导致游戏无法启动。除非你知道你在做什么,否则请你不要修改这些选项!
|
||||
settings.advanced.workaround.warning=调试选项仅提供给专业玩家使用。调试选项可能会导致游戏无法启动。除非你知道你在做什么,否则请不要修改这些选项!
|
||||
settings.advanced.wrapper_launcher=包装命令
|
||||
settings.advanced.wrapper_launcher.prompt=如填写 optirun 后,启动命令将从 "java ..." 变为 "optirun java ..."
|
||||
|
||||
@@ -974,13 +987,12 @@ update.channel.dev=测试版
|
||||
update.channel.dev.hint=你正在使用测试版。测试版包含一些未在正式版中包含的测试性功能,仅用于体验新功能。\n\
|
||||
测试版功能未受充分验证,使用起来可能不稳定!<a href="https://hmcl.huangyuhui.net/download">下载稳定版</a>\n\
|
||||
如果你遇到了使用问题,可以在设置的 <a href="hmcl://settings/feedback">反馈页面</a> 中进行反馈,或加入反馈页面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kook.top/Kx7n3t">KOOK</a>群以反馈问题。欢迎关注 B 站账号 <a href="https://space.bilibili.com/1445341">huanghongxun</a> 以关注 HMCL 的开发进展。\n\n\
|
||||
你需要 <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">赞助</a> 或在反馈过程中作出贡献以隐藏本提示。
|
||||
<a href="hmcl://hide-announcement">点击此处</a>为当前版本隐藏该提示。
|
||||
update.channel.dev.title=测试版提示
|
||||
update.channel.nightly=预览版
|
||||
update.channel.nightly.hint=你正在使用预览版。预览版可能会每天更新一次,包含一些未在正式版和测试版中包含的测试性功能,仅用于体验新功能。\n\
|
||||
测试版功能未受充分验证,使用起来可能不稳定!<a href="https://hmcl.huangyuhui.net/download">下载稳定版</a>\n\
|
||||
如果你遇到了使用问题,可以在设置的 <a href="hmcl://settings/feedback">反馈页面</a> 中进行反馈,或加入反馈页面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kook.top/Kx7n3t">KOOK</a>群以反馈问题。欢迎关注 B 站账号 <a href="https://space.bilibili.com/1445341">huanghongxun</a> 以关注 HMCL 的开发进展。\n\n\
|
||||
你需要 <a href="https://hmcl.huangyuhui.net/api/redirect/sponsor">赞助</a> 或在反馈过程中作出贡献以隐藏本提示。
|
||||
如果你遇到了使用问题,可以在设置的 <a href="hmcl://settings/feedback">反馈页面</a> 中进行反馈,或加入反馈页面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kook.top/Kx7n3t">KOOK</a>群以反馈问题。欢迎关注 B 站账号 <a href="https://space.bilibili.com/1445341">huanghongxun</a> 以关注 HMCL 的开发进展。
|
||||
update.channel.nightly.title=预览版提示
|
||||
update.channel.stable=推荐版本
|
||||
update.checking=正在检查更新
|
||||
@@ -1025,6 +1037,7 @@ 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=删除所有游戏资源文件
|
||||
version.manage.remove_libraries=删除所有库文件
|
||||
version.manage.rename=重命名该版本
|
||||
version.manage.rename.message=请输入要修改的名称
|
||||
|
||||
@@ -1519,6 +1519,248 @@
|
||||
"com.mojang:text2speech:1.12.4:natives": null,
|
||||
"com.mojang:text2speech:1.13.9:natives-linux": null
|
||||
},
|
||||
"linux-riscv64": {
|
||||
"org.lwjgl:lwjgl:3.1.6": {
|
||||
"name": "org.lwjgl:lwjgl:3.3.1",
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1.jar",
|
||||
"sha1": "ae58664f88e18a9bb2c77b063833ca7aaec484cb",
|
||||
"size": 724243
|
||||
}
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl:3.1.6:natives": {
|
||||
"name": "org.glavo.hmcl:lwjgl3-natives:3.3.1-rc1",
|
||||
"downloads": {
|
||||
"classifiers": {
|
||||
"linux-riscv64": {
|
||||
"path": "org/glavo/hmcl/lwjgl3-natives/3.3.1-rc1/lwjgl3-natives-3.3.1-rc1-linux-riscv64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/glavo/hmcl/lwjgl3-natives/3.3.1-rc1-linux-riscv64/lwjgl3-natives-3.3.1-rc1-linux-riscv64.jar",
|
||||
"sha1": "8544853aa77b10692548b2a728cd890afd740ba5",
|
||||
"size": 11905844
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract": {
|
||||
"exclude": [
|
||||
"META-INF/"
|
||||
]
|
||||
},
|
||||
"natives": {
|
||||
"linux": "linux-riscv64"
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl-jemalloc:3.1.6": {
|
||||
"name": "org.lwjgl:lwjgl-jemalloc:3.3.1",
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1.jar",
|
||||
"sha1": "a817bcf213db49f710603677457567c37d53e103",
|
||||
"size": 36601
|
||||
}
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl-jemalloc:3.1.6:natives": null,
|
||||
"org.lwjgl:lwjgl-openal:3.1.6": {
|
||||
"name": "org.lwjgl:lwjgl-openal:3.3.1",
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1.jar",
|
||||
"sha1": "2623a6b8ae1dfcd880738656a9f0243d2e6840bd",
|
||||
"size": 88237
|
||||
}
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl-openal:3.1.6:natives": null,
|
||||
"org.lwjgl:lwjgl-opengl:3.1.6": {
|
||||
"name": "org.lwjgl:lwjgl-opengl:3.3.1",
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1.jar",
|
||||
"sha1": "831a5533a21a5f4f81bbc51bb13e9899319b5411",
|
||||
"size": 921563
|
||||
}
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl-opengl:3.1.6:natives": null,
|
||||
"org.lwjgl:lwjgl-glfw:3.1.6": {
|
||||
"name": "org.lwjgl:lwjgl-glfw:3.3.1",
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1.jar",
|
||||
"sha1": "cbac1b8d30cb4795149c1ef540f912671a8616d0",
|
||||
"size": 128801
|
||||
}
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl-glfw:3.1.6:natives": null,
|
||||
"org.lwjgl:lwjgl-stb:3.1.6": {
|
||||
"name": "org.lwjgl:lwjgl-stb:3.3.1",
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1.jar",
|
||||
"sha1": "b119297cf8ed01f247abe8685857f8e7fcf5980f",
|
||||
"size": 112380
|
||||
}
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl-stb:3.1.6:natives": null,
|
||||
"org.lwjgl:lwjgl-tinyfd:3.1.6": {
|
||||
"name": "org.lwjgl:lwjgl-tinyfd:3.3.1",
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1.jar",
|
||||
"sha1": "0ff1914111ef2e3e0110ef2dabc8d8cdaad82347",
|
||||
"size": 6767
|
||||
}
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl-tinyfd:3.1.6:natives": null,
|
||||
"org.lwjgl:lwjgl:3.2.2": {
|
||||
"name": "org.lwjgl:lwjgl:3.3.1",
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1.jar",
|
||||
"sha1": "ae58664f88e18a9bb2c77b063833ca7aaec484cb",
|
||||
"size": 724243
|
||||
}
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl:3.2.2:natives": {
|
||||
"name": "org.glavo.hmcl:lwjgl3-natives:3.3.1-rc1",
|
||||
"downloads": {
|
||||
"classifiers": {
|
||||
"linux-riscv64": {
|
||||
"path": "org/glavo/hmcl/lwjgl3-natives/3.3.1-rc1/lwjgl3-natives-3.3.1-rc1-linux-riscv64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/glavo/hmcl/lwjgl3-natives/3.3.1-rc1-linux-riscv64/lwjgl3-natives-3.3.1-rc1-linux-riscv64.jar",
|
||||
"sha1": "8544853aa77b10692548b2a728cd890afd740ba5",
|
||||
"size": 11905844
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract": {
|
||||
"exclude": [
|
||||
"META-INF/"
|
||||
]
|
||||
},
|
||||
"natives": {
|
||||
"linux": "linux-riscv64"
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl-jemalloc:3.2.2": {
|
||||
"name": "org.lwjgl:lwjgl-jemalloc:3.3.1",
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1.jar",
|
||||
"sha1": "a817bcf213db49f710603677457567c37d53e103",
|
||||
"size": 36601
|
||||
}
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl-jemalloc:3.2.2:natives": null,
|
||||
"org.lwjgl:lwjgl-openal:3.2.2": {
|
||||
"name": "org.lwjgl:lwjgl-openal:3.3.1",
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1.jar",
|
||||
"sha1": "2623a6b8ae1dfcd880738656a9f0243d2e6840bd",
|
||||
"size": 88237
|
||||
}
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl-openal:3.2.2:natives": null,
|
||||
"org.lwjgl:lwjgl-opengl:3.2.2": {
|
||||
"name": "org.lwjgl:lwjgl-opengl:3.3.1",
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1.jar",
|
||||
"sha1": "831a5533a21a5f4f81bbc51bb13e9899319b5411",
|
||||
"size": 921563
|
||||
}
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl-opengl:3.2.2:natives": null,
|
||||
"org.lwjgl:lwjgl-glfw:3.2.2": {
|
||||
"name": "org.lwjgl:lwjgl-glfw:3.3.1",
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1.jar",
|
||||
"sha1": "cbac1b8d30cb4795149c1ef540f912671a8616d0",
|
||||
"size": 128801
|
||||
}
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl-glfw:3.2.2:natives": null,
|
||||
"org.lwjgl:lwjgl-stb:3.2.2": {
|
||||
"name": "org.lwjgl:lwjgl-stb:3.3.1",
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1.jar",
|
||||
"sha1": "b119297cf8ed01f247abe8685857f8e7fcf5980f",
|
||||
"size": 112380
|
||||
}
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl-stb:3.2.2:natives": null,
|
||||
"org.lwjgl:lwjgl-tinyfd:3.2.2": {
|
||||
"name": "org.lwjgl:lwjgl-tinyfd:3.3.1",
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1.jar",
|
||||
"sha1": "0ff1914111ef2e3e0110ef2dabc8d8cdaad82347",
|
||||
"size": 6767
|
||||
}
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl-tinyfd:3.2.2:natives": null,
|
||||
"org.lwjgl:lwjgl:3.3.1:natives-linux": {
|
||||
"name": "org.glavo.hmcl:lwjgl3-natives:3.3.1-rc1",
|
||||
"downloads": {
|
||||
"classifiers": {
|
||||
"linux-riscv64": {
|
||||
"path": "org/glavo/hmcl/lwjgl3-natives/3.3.1-rc1/lwjgl3-natives-3.3.1-rc1-linux-riscv64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/glavo/hmcl/lwjgl3-natives/3.3.1-rc1-linux-riscv64/lwjgl3-natives-3.3.1-rc1-linux-riscv64.jar",
|
||||
"sha1": "8544853aa77b10692548b2a728cd890afd740ba5",
|
||||
"size": 11905844
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract": {
|
||||
"exclude": [
|
||||
"META-INF/"
|
||||
]
|
||||
},
|
||||
"natives": {
|
||||
"linux": "linux-riscv64"
|
||||
}
|
||||
},
|
||||
"org.lwjgl:lwjgl-jemalloc:3.3.1:natives-linux": null,
|
||||
"org.lwjgl:lwjgl-openal:3.3.1:natives-linux": null,
|
||||
"org.lwjgl:lwjgl-opengl:3.3.1:natives-linux": null,
|
||||
"org.lwjgl:lwjgl-glfw:3.3.1:natives-linux": null,
|
||||
"org.lwjgl:lwjgl-stb:3.3.1:natives-linux": null,
|
||||
"org.lwjgl:lwjgl-tinyfd:3.3.1:natives-linux": null,
|
||||
"net.java.jinput:jinput-platform:2.0.5:natives": null,
|
||||
"com.mojang:text2speech:1.10.3:natives": null,
|
||||
"com.mojang:text2speech:1.11.3:natives": null,
|
||||
"com.mojang:text2speech:1.12.4:natives": null,
|
||||
"com.mojang:text2speech:1.13.9:natives-linux": null
|
||||
},
|
||||
"windows-x86_64": {
|
||||
"software-renderer-loader": {
|
||||
"name": "org.glavo:llvmpipe-loader:1.0",
|
||||
@@ -1530,6 +1772,30 @@
|
||||
"size": 12964773
|
||||
}
|
||||
}
|
||||
},
|
||||
"mesa-loader": {
|
||||
"name": "org.glavo:mesa-loader-windows:0.2.0:x64",
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/glavo/mesa-loader-windows/0.2.0/mesa-loader-windows-0.2.0-x64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/glavo/mesa-loader-windows/0.2.0/mesa-loader-windows-0.2.0-x64.jar",
|
||||
"sha1": "adb4a16ecb95c8944a016829b05d70f934ea1a29",
|
||||
"size": 22823052
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"windows-x86": {
|
||||
"mesa-loader": {
|
||||
"name": "org.glavo:mesa-loader-windows:0.2.0:x86",
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/glavo/mesa-loader-windows/0.2.0/mesa-loader-windows-0.2.0-x86.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/glavo/mesa-loader-windows/0.2.0/mesa-loader-windows-0.2.0-x86.jar",
|
||||
"sha1": "93c0b9b7382d984e713d3aa299ceb337fde2897b",
|
||||
"size": 18273286
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"windows-arm64": {
|
||||
@@ -2074,7 +2340,7 @@
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1-natives-macos-arm64.jar",
|
||||
"sha1": "71d0d5e469c9c95351eb949064497e3391616ac9",
|
||||
"size": 42693
|
||||
}
|
||||
@@ -2096,7 +2362,7 @@
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1-natives-macos-arm64.jar",
|
||||
"sha1": "e577b87d8ad2ade361aaea2fcf226c660b15dee8",
|
||||
"size": 103475
|
||||
}
|
||||
@@ -2118,7 +2384,7 @@
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1-natives-macos-arm64.jar",
|
||||
"sha1": "23d55e7490b57495320f6c9e1936d78fd72c4ef8",
|
||||
"size": 346125
|
||||
}
|
||||
@@ -2140,7 +2406,7 @@
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1-natives-macos-arm64.jar",
|
||||
"sha1": "eafe34b871d966292e8db0f1f3d6b8b110d4e91d",
|
||||
"size": 41665
|
||||
}
|
||||
@@ -2162,7 +2428,7 @@
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1-natives-macos-arm64.jar",
|
||||
"sha1": "cac0d3f712a3da7641fa174735a5f315de7ffe0a",
|
||||
"size": 129077
|
||||
}
|
||||
@@ -2184,7 +2450,7 @@
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1-natives-macos-arm64.jar",
|
||||
"sha1": "fcf073ed911752abdca5f0b00a53cfdf17ff8e8b",
|
||||
"size": 178408
|
||||
}
|
||||
@@ -2206,7 +2472,7 @@
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1-natives-macos-arm64.jar",
|
||||
"sha1": "972ecc17bad3571e81162153077b4d47b7b9eaa9",
|
||||
"size": 41380
|
||||
}
|
||||
@@ -2228,7 +2494,7 @@
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1-natives-macos-arm64.jar",
|
||||
"sha1": "71d0d5e469c9c95351eb949064497e3391616ac9",
|
||||
"size": 42693
|
||||
}
|
||||
@@ -2250,7 +2516,7 @@
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1-natives-macos-arm64.jar",
|
||||
"sha1": "e577b87d8ad2ade361aaea2fcf226c660b15dee8",
|
||||
"size": 103475
|
||||
}
|
||||
@@ -2272,7 +2538,7 @@
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1-natives-macos-arm64.jar",
|
||||
"sha1": "23d55e7490b57495320f6c9e1936d78fd72c4ef8",
|
||||
"size": 346125
|
||||
}
|
||||
@@ -2294,7 +2560,7 @@
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1-natives-macos-arm64.jar",
|
||||
"sha1": "eafe34b871d966292e8db0f1f3d6b8b110d4e91d",
|
||||
"size": 41665
|
||||
}
|
||||
@@ -2316,7 +2582,7 @@
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1-natives-macos-arm64.jar",
|
||||
"sha1": "cac0d3f712a3da7641fa174735a5f315de7ffe0a",
|
||||
"size": 129077
|
||||
}
|
||||
@@ -2338,7 +2604,7 @@
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1-natives-macos-arm64.jar",
|
||||
"sha1": "fcf073ed911752abdca5f0b00a53cfdf17ff8e8b",
|
||||
"size": 178408
|
||||
}
|
||||
@@ -2360,7 +2626,7 @@
|
||||
"downloads": {
|
||||
"artifact": {
|
||||
"path": "org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1-natives-macos-arm64.jar",
|
||||
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1-natives-macos-arm64.jar",
|
||||
"sha1": "972ecc17bad3571e81162153077b4d47b7b9eaa9",
|
||||
"size": 41380
|
||||
}
|
||||
|
||||
@@ -4,16 +4,13 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
api("org.glavo:simple-png-javafx:0.3.0")
|
||||
api("com.google.code.gson:gson:2.8.1")
|
||||
api("com.google.code.gson:gson:2.10.1")
|
||||
api("com.moandjiezana.toml:toml4j:0.7.2")
|
||||
api("org.tukaani:xz:1.8")
|
||||
api("org.hildan.fxgson:fx-gson:3.1.0") {
|
||||
exclude(group = "org.jetbrains", module = "annotations")
|
||||
}
|
||||
api("org.tukaani:xz:1.9")
|
||||
api("org.hildan.fxgson:fx-gson:5.0.0")
|
||||
api("org.jenkins-ci:constant-pool-scanner:1.2")
|
||||
api("com.github.steveice10:opennbt:1.1")
|
||||
api("com.nqzero:permit-reflect:0.3")
|
||||
api("com.github.steveice10:opennbt:1.5")
|
||||
api("org.nanohttpd:nanohttpd:2.3.1")
|
||||
api("org.apache.commons:commons-compress:1.21")
|
||||
compileOnlyApi("org.jetbrains:annotations:16.0.3")
|
||||
api("org.apache.commons:commons-compress:1.23.0")
|
||||
compileOnlyApi("org.jetbrains:annotations:24.0.1")
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import java.util.UUID;
|
||||
*/
|
||||
@Immutable
|
||||
public class AuthInfo implements AutoCloseable {
|
||||
public static final String USER_TYPE_MSA = "msa";
|
||||
public static final String USER_TYPE_MOJANG = "mojang";
|
||||
public static final String USER_TYPE_LEGACY = "legacy";
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ public class MicrosoftSession {
|
||||
public AuthInfo toAuthInfo() {
|
||||
requireNonNull(profile);
|
||||
|
||||
return new AuthInfo(profile.getName(), profile.getId(), accessToken, AuthInfo.USER_TYPE_MOJANG, "{}");
|
||||
return new AuthInfo(profile.getName(), profile.getId(), accessToken, AuthInfo.USER_TYPE_MSA, "{}");
|
||||
}
|
||||
|
||||
public static class User {
|
||||
|
||||
@@ -114,7 +114,7 @@ public class OfflineAccount extends Account {
|
||||
@Override
|
||||
public AuthInfo logIn() throws AuthenticationException {
|
||||
// Using "legacy" user type here because "mojang" user type may cause "invalid session token" or "disconnected" when connecting to a game server.
|
||||
AuthInfo authInfo = new AuthInfo(username, uuid, UUIDTypeAdapter.fromUUID(UUID.randomUUID()), AuthInfo.USER_TYPE_LEGACY, "{}");
|
||||
AuthInfo authInfo = new AuthInfo(username, uuid, UUIDTypeAdapter.fromUUID(UUID.randomUUID()), AuthInfo.USER_TYPE_MSA, "{}");
|
||||
|
||||
if (loadAuthlibInjector(skin)) {
|
||||
CompletableFuture<AuthlibInjectorArtifactInfo> artifactTask = CompletableFuture.supplyAsync(() -> {
|
||||
@@ -154,7 +154,7 @@ public class OfflineAccount extends Account {
|
||||
private YggdrasilServer server;
|
||||
|
||||
public OfflineAuthInfo(AuthInfo authInfo, AuthlibInjectorArtifactInfo artifact) {
|
||||
super(authInfo.getUsername(), authInfo.getUUID(), authInfo.getAccessToken(), USER_TYPE_LEGACY, authInfo.getUserProperties());
|
||||
super(authInfo.getUsername(), authInfo.getUUID(), authInfo.getAccessToken(), USER_TYPE_MSA, authInfo.getUserProperties());
|
||||
|
||||
this.artifact = artifact;
|
||||
}
|
||||
|
||||
@@ -273,6 +273,6 @@ public class YggdrasilService {
|
||||
.create();
|
||||
|
||||
public static final String PROFILE_URL = "https://aka.ms/MinecraftMigration";
|
||||
public static final String MIGRATION_FAQ_URL = "https://help.minecraft.net/hc/en-us/articles/360050865492-JAVA-Account-Migration-FAQ";
|
||||
public static final String PURCHASE_URL = "https://www.minecraft.net/store/minecraft-java-bedrock-edition-pc";
|
||||
public static final String MIGRATION_FAQ_URL = "https://help.minecraft.net/articles/360050865492";
|
||||
public static final String PURCHASE_URL = "https://www.microsoft.com/store/productId/9NXP44L49SHJ";
|
||||
}
|
||||
@@ -84,6 +84,7 @@ public class YggdrasilSession {
|
||||
String name = tryCast(storage.get("displayName"), String.class).orElseThrow(() -> new IllegalArgumentException("displayName is missing"));
|
||||
String clientToken = tryCast(storage.get("clientToken"), String.class).orElseThrow(() -> new IllegalArgumentException("clientToken is missing"));
|
||||
String accessToken = tryCast(storage.get("accessToken"), String.class).orElseThrow(() -> new IllegalArgumentException("accessToken is missing"));
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, String> userProperties = tryCast(storage.get("userProperties"), Map.class).orElse(null);
|
||||
return new YggdrasilSession(clientToken, accessToken, new GameProfile(uuid, name), null, userProperties);
|
||||
}
|
||||
@@ -104,7 +105,7 @@ public class YggdrasilSession {
|
||||
if (selectedProfile == null)
|
||||
throw new IllegalStateException("No character is selected");
|
||||
|
||||
return new AuthInfo(selectedProfile.getName(), selectedProfile.getId(), accessToken, AuthInfo.USER_TYPE_MOJANG,
|
||||
return new AuthInfo(selectedProfile.getName(), selectedProfile.getId(), accessToken, AuthInfo.USER_TYPE_MSA,
|
||||
Optional.ofNullable(userProperties)
|
||||
.map(properties -> properties.entrySet().stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey,
|
||||
|
||||
@@ -31,8 +31,7 @@ public final class EventBus {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Event> EventManager<T> channel(Class<T> clazz) {
|
||||
events.putIfAbsent(clazz, new EventManager<>());
|
||||
return (EventManager<T>) events.get(clazz);
|
||||
return (EventManager<T>) events.computeIfAbsent(clazz, ignored -> new EventManager<>());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -88,7 +88,7 @@ public final class CrashReportAnalyzer {
|
||||
MODLAUNCHER_8(Pattern.compile("java\\.lang\\.NoSuchMethodError: ('void sun\\.security\\.util\\.ManifestEntryVerifier\\.<init>\\(java\\.util\\.jar\\.Manifest\\)'|sun\\.security\\.util\\.ManifestEntryVerifier\\.<init>\\(Ljava/util/jar/Manifest;\\)V)")),
|
||||
// Manually triggerd debug crash
|
||||
DEBUG_CRASH(Pattern.compile("Manually triggered debug crash")),
|
||||
CONFIG(Pattern.compile("Failed loading config file (?<file>.*?) of type SERVER for modid (?<id>.*)"), "id", "file"),
|
||||
CONFIG(Pattern.compile("Failed loading config file (?<file>.*?) of type (.*?) for modid (?<id>.*)"), "id", "file"),
|
||||
// Fabric gives some warnings
|
||||
FABRIC_WARNINGS(Pattern.compile("(Warnings were found!|Incompatible mod set!)(.*?)[\\n\\r]+(?<reason>[^\\[]+)\\["), "reason"),
|
||||
// Game crashed when ticking entity
|
||||
@@ -113,6 +113,15 @@ public final class CrashReportAnalyzer {
|
||||
FORGE_REPEAT_INSTALLATION(Pattern.compile("--launchTarget, fmlclient, --fml.forgeVersion,[\\w\\W]*?--launchTarget, fmlclient, --fml.forgeVersion,[\\w\\W\\n\\r]*?MultipleArgumentsForOptionException: Found multiple arguments for option gameDir, but you asked for only one")),//https://github.com/huanghongxun/HMCL/issues/1880
|
||||
OPTIFINE_REPEAT_INSTALLATION(Pattern.compile("ResolutionException: Module optifine reads another module named optifine")),//Optifine 重复安装(及Mod文件夹有,自动安装也有)
|
||||
JAVA_VERSION_IS_TOO_HIGH(Pattern.compile("(Unable to make protected final java\\.lang\\.Class java\\.lang\\.ClassLoader\\.defineClass|java\\.lang\\.NoSuchFieldException: ucp|Unsupported class file major version|because module java\\.base does not export|java\\.lang\\.ClassNotFoundException: jdk\\.nashorn\\.api\\.scripting\\.NashornScriptEngineFactory|java\\.lang\\.ClassNotFoundException: java\\.lang\\.invoke\\.LambdaMetafactory)")),//Java版本过高
|
||||
|
||||
//Forge 默认会把每一个 mod jar 都当做一个 JPMS 的模块(Module)加载。在这个 jar 没有给出 module-info 声明的情况下,JPMS 会采用这样的顺序决定 module 名字:
|
||||
//1. META-INF/MANIFEST.MF 里的 Automatic-Module-Name
|
||||
//2. 根据文件名生成。文件名里的 .jar 后缀名先去掉,然后检查是否有 -(\\d+(\\.|$)) 的部分,有的话只取 - 前面的部分,- 后面的部分成为 module 的版本号(即尝试判断文件名里是否有版本号,有的话去掉),然后把不是拉丁字母和数字的字符(正则表达式 [^A-Za-z0-9])都换成点,然后把连续的多个点换成一个点,最后去掉开头和结尾的点。那么
|
||||
//按照 2.,如果你的文件名是拔刀剑.jar,那么这么一通流程下来,你得到的 module 名就是空字符串,而这是不允许的。(来自 @Föhn 说明)
|
||||
MOD_NAME(Pattern.compile("Invalid module name: '' is not a Java identifier")),
|
||||
|
||||
//Forge 安装不完整
|
||||
INCOMPLETE_FORGE_INSTALLATION(Pattern.compile("(java\\.io\\.UncheckedIOException: java\\.io\\.IOException: Invalid paths argument, contained no existing paths: \\[(.*?)\\\\libraries\\\\net\\\\minecraftforge\\\\forge\\\\(.*?)\\\\forge-(.*?)-client\\.jar\\]|Failed to find Minecraft resource version (.*?) at (.*?)\\\\libraries\\\\net\\\\minecraftforge\\\\forge\\\\(.*?)\\\\forge-(.*?)-client\\.jar|Cannot find launch target fmlclient, unable to launch)")),
|
||||
|
||||
// TwilightForest is not compatible with OptiFine on Minecraft 1.16
|
||||
TWILIGHT_FOREST_OPTIFINE(Pattern.compile("java.lang.IllegalArgumentException: (.*) outside of image bounds (.*)"));
|
||||
|
||||
@@ -186,7 +186,7 @@ public class DefaultGameRepository implements GameRepository {
|
||||
} catch (JsonParseException ignored) {
|
||||
}
|
||||
|
||||
LOG.warning("Cannot parse version json + " + file.toString() + "\n" + jsonText);
|
||||
LOG.warning("Cannot parse version json: " + file.toString() + "\n" + jsonText);
|
||||
throw new JsonParseException("Version json incorrect");
|
||||
}
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ import org.jackhuang.hmcl.util.platform.Platform;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Supports operations on versioning.
|
||||
@@ -250,8 +250,8 @@ public interface GameRepository extends VersionProvider {
|
||||
*/
|
||||
Path getLoggingObject(String version, String assetId, LoggingInfo loggingInfo);
|
||||
|
||||
default List<String> getClasspath(Version version) {
|
||||
List<String> classpath = new ArrayList<>();
|
||||
default Set<String> getClasspath(Version version) {
|
||||
Set<String> classpath = new LinkedHashSet<>();
|
||||
for (Library library : version.getLibraries())
|
||||
if (library.appliesToCurrentEnvironment() && !library.isNative()) {
|
||||
File f = getLibraryFile(version, library);
|
||||
|
||||
@@ -23,9 +23,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.net.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -42,6 +40,7 @@ public class LaunchOptions implements Serializable {
|
||||
private final List<String> overrideJavaArguments = new ArrayList<>();
|
||||
private final List<String> javaArguments = new ArrayList<>();
|
||||
private final List<String> javaAgents = new ArrayList<>(0);
|
||||
private final Map<String, String> environmentVariables = new LinkedHashMap<>();
|
||||
private Integer minMemory;
|
||||
private Integer maxMemory;
|
||||
private Integer metaspace;
|
||||
@@ -59,7 +58,7 @@ public class LaunchOptions implements Serializable {
|
||||
private NativesDirectoryType nativesDirType;
|
||||
private String nativesDir;
|
||||
private ProcessPriority processPriority = ProcessPriority.NORMAL;
|
||||
private boolean useSoftwareRenderer;
|
||||
private Renderer renderer = Renderer.DEFAULT;
|
||||
private boolean useNativeGLFW;
|
||||
private boolean useNativeOpenAL;
|
||||
private boolean daemon;
|
||||
@@ -130,6 +129,10 @@ public class LaunchOptions implements Serializable {
|
||||
return Collections.unmodifiableList(javaAgents);
|
||||
}
|
||||
|
||||
public Map<String, String> getEnvironmentVariables() {
|
||||
return environmentVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum memory that the JVM can allocate.
|
||||
*/
|
||||
@@ -252,8 +255,8 @@ public class LaunchOptions implements Serializable {
|
||||
return processPriority;
|
||||
}
|
||||
|
||||
public boolean isUseSoftwareRenderer() {
|
||||
return useSoftwareRenderer;
|
||||
public Renderer getRenderer() {
|
||||
return renderer;
|
||||
}
|
||||
|
||||
public boolean isUseNativeGLFW() {
|
||||
@@ -279,43 +282,6 @@ public class LaunchOptions implements Serializable {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* The game directory
|
||||
*/
|
||||
public File getGameDir() {
|
||||
return options.gameDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Java Environment that Minecraft runs on.
|
||||
*/
|
||||
public JavaVersion getJava() {
|
||||
return options.java;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will shown in the left bottom corner of the main menu of Minecraft.
|
||||
* null if use the id of launch version.
|
||||
*/
|
||||
public String getVersionName() {
|
||||
return options.versionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will shown in the left bottom corner of the main menu of Minecraft.
|
||||
* null if use Version.versionType.
|
||||
*/
|
||||
public String getVersionType() {
|
||||
return options.versionType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't know what the hell this is.
|
||||
*/
|
||||
public String getProfileName() {
|
||||
return options.profileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* User custom additional minecraft command line arguments.
|
||||
*/
|
||||
@@ -341,123 +307,6 @@ public class LaunchOptions implements Serializable {
|
||||
return options.javaAgents;
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum memory that the JVM can allocate.
|
||||
*/
|
||||
public Integer getMinMemory() {
|
||||
return options.minMemory;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum memory that the JVM can allocate.
|
||||
*/
|
||||
public Integer getMaxMemory() {
|
||||
return options.maxMemory;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum metaspace memory that the JVM can allocate.
|
||||
* For Java 7 -XX:PermSize and Java 8 -XX:MetaspaceSize
|
||||
* Containing class instances.
|
||||
*/
|
||||
public Integer getMetaspace() {
|
||||
return options.metaspace;
|
||||
}
|
||||
|
||||
/**
|
||||
* The initial game window width
|
||||
*/
|
||||
public Integer getWidth() {
|
||||
return options.width;
|
||||
}
|
||||
|
||||
/**
|
||||
* The initial game window height
|
||||
*/
|
||||
public Integer getHeight() {
|
||||
return options.height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is inital game window fullscreen.
|
||||
*/
|
||||
public boolean isFullscreen() {
|
||||
return options.fullscreen;
|
||||
}
|
||||
|
||||
/**
|
||||
* The server ip that will connect to when enter game main menu.
|
||||
*/
|
||||
public String getServerIp() {
|
||||
return options.serverIp;
|
||||
}
|
||||
|
||||
/**
|
||||
* i.e. optirun
|
||||
*/
|
||||
public String getWrapper() {
|
||||
return options.wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy settings
|
||||
*/
|
||||
public Proxy getProxy() {
|
||||
return options.proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* The user name of the proxy, optional.
|
||||
*/
|
||||
public String getProxyUser() {
|
||||
return options.proxyUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* The password of the proxy, optional
|
||||
*/
|
||||
public String getProxyPass() {
|
||||
return options.proxyPass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent game launcher from generating default JVM arguments like max memory.
|
||||
*/
|
||||
public boolean isNoGeneratedJVMArgs() {
|
||||
return options.noGeneratedJVMArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called command line before launching the game.
|
||||
*/
|
||||
public String getPreLaunchCommand() {
|
||||
return options.preLaunchCommand;
|
||||
}
|
||||
|
||||
public NativesDirectoryType getNativesDirType() {
|
||||
return options.nativesDirType;
|
||||
}
|
||||
|
||||
public String getNativesDir() {
|
||||
return options.nativesDir;
|
||||
}
|
||||
|
||||
public boolean isUseSoftwareRenderer() {
|
||||
return options.useSoftwareRenderer;
|
||||
}
|
||||
|
||||
public boolean isUseNativeGLFW() {
|
||||
return options.useNativeGLFW;
|
||||
}
|
||||
|
||||
public boolean isUseNativeOpenAL() {
|
||||
return options.useNativeOpenAL;
|
||||
}
|
||||
|
||||
public boolean isDaemon() {
|
||||
return options.daemon;
|
||||
}
|
||||
|
||||
public Builder setGameDir(File gameDir) {
|
||||
options.gameDir = gameDir;
|
||||
return this;
|
||||
@@ -507,6 +356,12 @@ public class LaunchOptions implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEnvironmentVariables(Map<String, String> env) {
|
||||
options.environmentVariables.clear();
|
||||
options.environmentVariables.putAll(env);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMinMemory(Integer minMemory) {
|
||||
options.minMemory = minMemory;
|
||||
return this;
|
||||
@@ -592,8 +447,8 @@ public class LaunchOptions implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setUseSoftwareRenderer(boolean useSoftwareRenderer) {
|
||||
options.useSoftwareRenderer = useSoftwareRenderer;
|
||||
public Builder setRenderer(@NotNull Renderer renderer) {
|
||||
options.renderer = renderer;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
public enum Renderer {
|
||||
DEFAULT,
|
||||
ZINK,
|
||||
LLVMPIPE,
|
||||
D3D12
|
||||
}
|
||||
@@ -207,7 +207,7 @@ public class DefaultLauncher extends Launcher {
|
||||
res.addDefault("-Dfml.ignorePatchDiscrepancies=", "true");
|
||||
}
|
||||
|
||||
List<String> classpath = repository.getClasspath(version);
|
||||
Set<String> classpath = repository.getClasspath(version);
|
||||
|
||||
File jar = repository.getVersionJar(version);
|
||||
if (!jar.exists() || !jar.isFile())
|
||||
@@ -462,16 +462,29 @@ public class DefaultLauncher extends Launcher {
|
||||
|
||||
private Map<String, String> getEnvVars() {
|
||||
String versionName = Optional.ofNullable(options.getVersionName()).orElse(version.getId());
|
||||
Map<String, String> env = new HashMap<>();
|
||||
Map<String, String> env = new LinkedHashMap<>();
|
||||
env.put("INST_NAME", versionName);
|
||||
env.put("INST_ID", versionName);
|
||||
env.put("INST_DIR", repository.getVersionRoot(version.getId()).getAbsolutePath());
|
||||
env.put("INST_MC_DIR", repository.getRunDirectory(version.getId()).getAbsolutePath());
|
||||
env.put("INST_JAVA", options.getJava().getBinary().toString());
|
||||
|
||||
if (options.isUseSoftwareRenderer() && OperatingSystem.CURRENT_OS == OperatingSystem.LINUX) {
|
||||
env.put("LIBGL_ALWAYS_SOFTWARE", "1");
|
||||
env.put("__GLX_VENDOR_LIBRARY_NAME", "mesa");
|
||||
Renderer renderer = options.getRenderer();
|
||||
if (renderer != Renderer.DEFAULT) {
|
||||
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
|
||||
if (renderer != Renderer.LLVMPIPE)
|
||||
env.put("GALLIUM_DRIVER", renderer.name().toLowerCase(Locale.ROOT));
|
||||
} else if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX) {
|
||||
env.put("__GLX_VENDOR_LIBRARY_NAME", "mesa");
|
||||
switch (renderer) {
|
||||
case LLVMPIPE:
|
||||
env.put("LIBGL_ALWAYS_SOFTWARE", "1");
|
||||
break;
|
||||
case ZINK:
|
||||
env.put("MESA_LOADER_DRIVER_OVERRIDE", "zink");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version);
|
||||
@@ -490,6 +503,9 @@ public class DefaultLauncher extends Launcher {
|
||||
if (analyzer.has(LibraryAnalyzer.LibraryType.QUILT)) {
|
||||
env.put("INST_QUILT", "1");
|
||||
}
|
||||
|
||||
env.putAll(options.getEnvironmentVariables());
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ public interface RemoteModRepository {
|
||||
}
|
||||
|
||||
String[] DEFAULT_GAME_VERSIONS = new String[]{
|
||||
"1.20", "1.20.1",
|
||||
"1.19.4", "1.19.3", "1.19.2", "1.19.1", "1.19",
|
||||
"1.18.2", "1.18.1", "1.18",
|
||||
"1.17.1", "1.17",
|
||||
|
||||
@@ -25,10 +25,8 @@ import java.io.UnsupportedEncodingException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.logging.*;
|
||||
|
||||
/**
|
||||
@@ -41,20 +39,20 @@ public final class Logging {
|
||||
public static final Logger LOG = Logger.getLogger("HMCL");
|
||||
private static final ByteArrayOutputStream storedLogs = new ByteArrayOutputStream(IOUtils.DEFAULT_BUFFER_SIZE);
|
||||
|
||||
private static final ConcurrentMap<String, String> forbiddenTokens = new ConcurrentHashMap<>();
|
||||
private static volatile String[] accessTokens = new String[0];
|
||||
|
||||
public static void registerForbiddenToken(String token, String replacement) {
|
||||
forbiddenTokens.put(token, replacement);
|
||||
}
|
||||
public static synchronized void registerAccessToken(String token) {
|
||||
final String[] oldAccessTokens = accessTokens;
|
||||
final String[] newAccessTokens = Arrays.copyOf(oldAccessTokens, oldAccessTokens.length + 1);
|
||||
|
||||
public static void registerAccessToken(String accessToken) {
|
||||
registerForbiddenToken(accessToken, "<access token>");
|
||||
newAccessTokens[oldAccessTokens.length] = token;
|
||||
|
||||
accessTokens = newAccessTokens;
|
||||
}
|
||||
|
||||
public static String filterForbiddenToken(String message) {
|
||||
for (Map.Entry<String, String> entry : forbiddenTokens.entrySet()) {
|
||||
message = message.replace(entry.getKey(), entry.getValue());
|
||||
}
|
||||
for (String token : accessTokens)
|
||||
message = message.replace(token, "<access token>");
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.util;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
@@ -30,20 +27,6 @@ public final class ReflectionHelper {
|
||||
private ReflectionHelper() {
|
||||
}
|
||||
|
||||
private static Method accessible0;
|
||||
|
||||
static {
|
||||
try {
|
||||
accessible0 = AccessibleObject.class.getDeclaredMethod("setAccessible0", boolean.class);
|
||||
accessible0.setAccessible(true);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void setAccessible(AccessibleObject obj) throws InvocationTargetException, IllegalAccessException {
|
||||
accessible0.invoke(obj, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get caller, this method is caller sensitive.
|
||||
*
|
||||
|
||||
@@ -1,67 +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.util.Objects;
|
||||
|
||||
public abstract class Result<T> {
|
||||
|
||||
public T get() {
|
||||
throw new IllegalStateException("TriState not ok");
|
||||
}
|
||||
|
||||
public boolean isOK() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isError() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static <T> Result<T> ok(T result) {
|
||||
return new OK<>(Objects.requireNonNull(result));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Result<T> error() {
|
||||
return (Result<T>) Error.INSTANCE;
|
||||
}
|
||||
|
||||
private static class OK<T> extends Result<T> {
|
||||
private final T result;
|
||||
|
||||
public OK(T result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Error<T> extends Result<T> {
|
||||
public static final Error<Void> INSTANCE = new Error<>();
|
||||
|
||||
@Override
|
||||
public boolean isError() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +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.gson;
|
||||
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
public abstract class GsonSerializerHelper<T> implements JsonSerializer<T>, JsonDeserializer<T> {
|
||||
|
||||
protected static void add(JsonObject object, String property, JsonElement value) {
|
||||
if (value == null) return;
|
||||
object.add(property, value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -51,8 +52,10 @@ public final class UUIDTypeAdapter extends TypeAdapter<UUID> {
|
||||
return value.toString().replace("-", "");
|
||||
}
|
||||
|
||||
private static final Pattern regex = Pattern.compile("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})");
|
||||
|
||||
public static UUID fromString(String input) {
|
||||
return UUID.fromString(input.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5"));
|
||||
return UUID.fromString(regex.matcher(input).replaceFirst("$1-$2-$3-$4-$5"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,8 +46,8 @@ public enum Architecture {
|
||||
PPC64LE(BIT_64, "PowerPC-64 (Little-Endian)"),
|
||||
S390(BIT_32),
|
||||
S390X(BIT_64, "S390x"),
|
||||
RISCV32(BIT_32, "RISC-V (32 Bit)"),
|
||||
RISCV64(BIT_64, "RISC-V"),
|
||||
RISCV32(BIT_32, "RISC-V 32"),
|
||||
RISCV64(BIT_64, "RISC-V 64"),
|
||||
LOONGARCH32(BIT_32, "LoongArch32"),
|
||||
LOONGARCH64_OW(BIT_64, "LoongArch64 (old world)"),
|
||||
LOONGARCH64(BIT_64, "LoongArch64"),
|
||||
@@ -69,12 +69,6 @@ public enum Architecture {
|
||||
this.bits = bits;
|
||||
}
|
||||
|
||||
Architecture(Bits bits, String displayName, String identifier) {
|
||||
this.checkedName = identifier;
|
||||
this.displayName = displayName;
|
||||
this.bits = bits;
|
||||
}
|
||||
|
||||
public Bits getBits() {
|
||||
return bits;
|
||||
}
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.versioning;
|
||||
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
|
||||
@@ -29,7 +27,9 @@ import java.util.*;
|
||||
* Maybe we can migrate to org.jenkins-ci:version-number:1.7?
|
||||
* @see <a href="http://maven.apache.org/pom.html#Version_Order_Specification">Specification</a>
|
||||
*/
|
||||
public class VersionNumber implements Comparable<VersionNumber> {
|
||||
public final class VersionNumber implements Comparable<VersionNumber> {
|
||||
|
||||
public static final Comparator<String> VERSION_COMPARATOR = Comparator.comparing(VersionNumber::asVersion);
|
||||
|
||||
public static VersionNumber asVersion(String version) {
|
||||
Objects.requireNonNull(version);
|
||||
@@ -41,68 +41,85 @@ public class VersionNumber implements Comparable<VersionNumber> {
|
||||
}
|
||||
|
||||
public static boolean isIntVersionNumber(String version) {
|
||||
if (version.chars().noneMatch(ch -> ch != '.' && (ch < '0' || ch > '9'))
|
||||
&& !version.contains("..") && StringUtils.isNotBlank(version)) {
|
||||
String[] arr = version.split("\\.");
|
||||
for (String str : arr)
|
||||
if (str.length() > 9)
|
||||
// Numbers which are larger than 1e9 cannot be stored as integer.
|
||||
return false;
|
||||
return true;
|
||||
} else {
|
||||
if (version.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int idx = 0;
|
||||
boolean cont = true;
|
||||
do {
|
||||
int dotIndex = version.indexOf('.', idx);
|
||||
if (dotIndex == idx || dotIndex == version.length() - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int endIndex;
|
||||
if (dotIndex < 0) {
|
||||
cont = false;
|
||||
endIndex = version.length();
|
||||
} else {
|
||||
endIndex = dotIndex;
|
||||
}
|
||||
|
||||
if (endIndex - idx > 9)
|
||||
// Numbers which are larger than 10^10 cannot be stored as integer
|
||||
return false;
|
||||
|
||||
for (int i = idx; i < endIndex; i++) {
|
||||
char ch = version.charAt(i);
|
||||
if (ch < '0' || ch > '9')
|
||||
return false;
|
||||
}
|
||||
|
||||
idx = endIndex + 1;
|
||||
} while (cont);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private String value;
|
||||
private String canonical;
|
||||
private ListItem items;
|
||||
|
||||
private interface Item {
|
||||
int INTEGER_ITEM = 0;
|
||||
int STRING_ITEM = 1;
|
||||
int LIST_ITEM = 2;
|
||||
int LONG_ITEM = 0;
|
||||
int BIGINTEGER_ITEM = 1;
|
||||
int STRING_ITEM = 2;
|
||||
int LIST_ITEM = 3;
|
||||
|
||||
int compareTo(Item item);
|
||||
|
||||
int getType();
|
||||
|
||||
boolean isNull();
|
||||
|
||||
void appendTo(StringBuilder buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a numeric item in the version item list.
|
||||
*/
|
||||
private static class IntegerItem
|
||||
implements Item {
|
||||
private final BigInteger value;
|
||||
private static final class LongItem implements Item {
|
||||
private final long value;
|
||||
|
||||
public static final IntegerItem ZERO = new IntegerItem();
|
||||
public static final LongItem ZERO = new LongItem(0L);
|
||||
|
||||
private IntegerItem() {
|
||||
this.value = BigInteger.ZERO;
|
||||
}
|
||||
|
||||
IntegerItem(String str) {
|
||||
this.value = new BigInteger(str);
|
||||
LongItem(long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return INTEGER_ITEM;
|
||||
return LONG_ITEM;
|
||||
}
|
||||
|
||||
public boolean isNull() {
|
||||
return BigInteger.ZERO.equals(value);
|
||||
return value == 0L;
|
||||
}
|
||||
|
||||
public int compareTo(Item item) {
|
||||
if (item == null) {
|
||||
return BigInteger.ZERO.equals(value) ? 0 : 1; // 1.0 == 1, 1.1 > 1
|
||||
return value == 0L ? 0 : 1; // 1.0 == 1, 1.1 > 1
|
||||
}
|
||||
|
||||
switch (item.getType()) {
|
||||
case INTEGER_ITEM:
|
||||
return value.compareTo(((IntegerItem) item).value);
|
||||
case LONG_ITEM:
|
||||
long itemValue = ((LongItem) item).value;
|
||||
return Long.compare(value, itemValue);
|
||||
case BIGINTEGER_ITEM:
|
||||
return -1;
|
||||
|
||||
case STRING_ITEM:
|
||||
return 1; // 1.1 > 1-sp
|
||||
@@ -111,10 +128,68 @@ public class VersionNumber implements Comparable<VersionNumber> {
|
||||
return 1; // 1.1 > 1-1
|
||||
|
||||
default:
|
||||
throw new RuntimeException("invalid item: " + item.getClass());
|
||||
throw new AssertionError("invalid item: " + item.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(StringBuilder buffer) {
|
||||
buffer.append(value);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return Long.toString(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a numeric item in the version item list.
|
||||
*/
|
||||
private static final class BigIntegerItem implements Item {
|
||||
private final BigInteger value;
|
||||
|
||||
BigIntegerItem(String str) {
|
||||
this.value = new BigInteger(str);
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return BIGINTEGER_ITEM;
|
||||
}
|
||||
|
||||
public boolean isNull() {
|
||||
// Never be 0
|
||||
// return BigInteger.ZERO.equals(value);
|
||||
return false;
|
||||
}
|
||||
|
||||
public int compareTo(Item item) {
|
||||
if (item == null) {
|
||||
// return BigInteger.ZERO.equals(value) ? 0 : 1; // 1.0 == 1, 1.1 > 1
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (item.getType()) {
|
||||
case LONG_ITEM:
|
||||
return 1;
|
||||
case BIGINTEGER_ITEM:
|
||||
return value.compareTo(((BigIntegerItem) item).value);
|
||||
|
||||
case STRING_ITEM:
|
||||
return 1; // 1.1 > 1-sp
|
||||
|
||||
case LIST_ITEM:
|
||||
return 1; // 1.1 > 1-1
|
||||
|
||||
default:
|
||||
throw new AssertionError("invalid item: " + item.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(StringBuilder buffer) {
|
||||
buffer.append(value);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return value.toString();
|
||||
}
|
||||
@@ -123,9 +198,8 @@ public class VersionNumber implements Comparable<VersionNumber> {
|
||||
/**
|
||||
* Represents a string in the version item list, usually a qualifier.
|
||||
*/
|
||||
private static class StringItem
|
||||
implements Item {
|
||||
private String value;
|
||||
private static final class StringItem implements Item {
|
||||
private final String value;
|
||||
|
||||
StringItem(String value) {
|
||||
this.value = value;
|
||||
@@ -145,7 +219,8 @@ public class VersionNumber implements Comparable<VersionNumber> {
|
||||
return 1;
|
||||
}
|
||||
switch (item.getType()) {
|
||||
case INTEGER_ITEM:
|
||||
case LONG_ITEM:
|
||||
case BIGINTEGER_ITEM:
|
||||
return -1; // 1.any < 1.1 ?
|
||||
|
||||
case STRING_ITEM:
|
||||
@@ -155,10 +230,15 @@ public class VersionNumber implements Comparable<VersionNumber> {
|
||||
return -1; // 1.any < 1-1
|
||||
|
||||
default:
|
||||
throw new RuntimeException("invalid item: " + item.getClass());
|
||||
throw new AssertionError("invalid item: " + item.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(StringBuilder buffer) {
|
||||
buffer.append(value);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
@@ -168,14 +248,14 @@ public class VersionNumber implements Comparable<VersionNumber> {
|
||||
* Represents a version list item. This class is used both for the global item list and for sub-lists (which start
|
||||
* with '-(number)' in the version specification).
|
||||
*/
|
||||
private static class ListItem
|
||||
extends ArrayList<Item>
|
||||
implements Item {
|
||||
Character separator;
|
||||
private static final class ListItem extends ArrayList<Item> implements Item {
|
||||
private final Character separator;
|
||||
|
||||
public ListItem() {}
|
||||
ListItem() {
|
||||
this.separator = null;
|
||||
}
|
||||
|
||||
public ListItem(char separator) {
|
||||
ListItem(char separator) {
|
||||
this.separator = separator;
|
||||
}
|
||||
|
||||
@@ -184,7 +264,7 @@ public class VersionNumber implements Comparable<VersionNumber> {
|
||||
}
|
||||
|
||||
public boolean isNull() {
|
||||
return (size() == 0);
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
void normalize() {
|
||||
@@ -209,7 +289,8 @@ public class VersionNumber implements Comparable<VersionNumber> {
|
||||
return first.compareTo(null);
|
||||
}
|
||||
switch (item.getType()) {
|
||||
case INTEGER_ITEM:
|
||||
case LONG_ITEM:
|
||||
case BIGINTEGER_ITEM:
|
||||
return -1; // 1-1 < 1.0.x
|
||||
|
||||
case STRING_ITEM:
|
||||
@@ -234,36 +315,46 @@ public class VersionNumber implements Comparable<VersionNumber> {
|
||||
return 0;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("invalid item: " + item.getClass());
|
||||
throw new AssertionError("invalid item: " + item.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(StringBuilder buffer) {
|
||||
if (separator != null) {
|
||||
buffer.append((char) separator);
|
||||
}
|
||||
|
||||
final int initLength = buffer.length();
|
||||
|
||||
for (Item item : this) {
|
||||
if (buffer.length() > initLength) {
|
||||
if (!(item instanceof ListItem))
|
||||
buffer.append('.');
|
||||
}
|
||||
item.appendTo(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
for (Item item : this) {
|
||||
if (buffer.length() > 0) {
|
||||
if (!(item instanceof ListItem))
|
||||
buffer.append('.');
|
||||
}
|
||||
buffer.append(item);
|
||||
}
|
||||
if (separator != null)
|
||||
return separator + buffer.toString();
|
||||
else
|
||||
return buffer.toString();
|
||||
appendTo(buffer);
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public VersionNumber(String version) {
|
||||
parseVersion(version);
|
||||
}
|
||||
private static final int MAX_LONGITEM_LENGTH = 18;
|
||||
|
||||
private void parseVersion(String version) {
|
||||
private final String value;
|
||||
public final ListItem items;
|
||||
private final String canonical;
|
||||
|
||||
private VersionNumber(String version) {
|
||||
this.value = version;
|
||||
|
||||
ListItem list = items = new ListItem();
|
||||
ListItem list = this.items = new ListItem();
|
||||
|
||||
Stack<Item> stack = new Stack<>();
|
||||
Deque<Item> stack = new ArrayDeque<>();
|
||||
stack.push(list);
|
||||
|
||||
boolean isDigit = false;
|
||||
@@ -275,14 +366,14 @@ public class VersionNumber implements Comparable<VersionNumber> {
|
||||
|
||||
if (c == '.') {
|
||||
if (i == startIndex) {
|
||||
list.add(IntegerItem.ZERO);
|
||||
list.add(LongItem.ZERO);
|
||||
} else {
|
||||
list.add(parseItem(version.substring(startIndex, i)));
|
||||
}
|
||||
startIndex = i + 1;
|
||||
} else if ("!\"#$%&'()*+,-/:;<=>?@[\\]^_`{|}~".indexOf(c) != -1) {
|
||||
if (i == startIndex) {
|
||||
list.add(IntegerItem.ZERO);
|
||||
list.add(LongItem.ZERO);
|
||||
} else {
|
||||
list.add(parseItem(version.substring(startIndex, i)));
|
||||
}
|
||||
@@ -290,7 +381,7 @@ public class VersionNumber implements Comparable<VersionNumber> {
|
||||
|
||||
list.add(list = new ListItem(c));
|
||||
stack.push(list);
|
||||
} else if (Character.isDigit(c)) {
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
if (!isDigit && i > startIndex) {
|
||||
list.add(parseItem(version.substring(startIndex, i)));
|
||||
startIndex = i;
|
||||
@@ -322,11 +413,42 @@ public class VersionNumber implements Comparable<VersionNumber> {
|
||||
list.normalize();
|
||||
}
|
||||
|
||||
canonical = items.toString();
|
||||
this.canonical = items.toString();
|
||||
}
|
||||
|
||||
// For simple version
|
||||
private VersionNumber(String version, ListItem items) {
|
||||
this.value = version;
|
||||
this.items = items;
|
||||
this.canonical = version;
|
||||
}
|
||||
|
||||
private static Item parseItem(String buf) {
|
||||
return buf.chars().allMatch(Character::isDigit) ? new IntegerItem(buf) : new StringItem(buf);
|
||||
int numberLength = 0;
|
||||
boolean leadingZero = true;
|
||||
for (int i = 0; i < buf.length(); i++) {
|
||||
char ch = buf.charAt(i);
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
if (ch != '0') {
|
||||
leadingZero = false;
|
||||
}
|
||||
|
||||
if (!leadingZero) {
|
||||
numberLength++;
|
||||
}
|
||||
} else {
|
||||
return new StringItem(buf);
|
||||
}
|
||||
}
|
||||
|
||||
if (numberLength == 0) {
|
||||
return LongItem.ZERO;
|
||||
} else if (numberLength <= MAX_LONGITEM_LENGTH) {
|
||||
// Numbers which are larger than 10^19 cannot be stored as long
|
||||
return new LongItem(Long.parseLong(buf));
|
||||
} else {
|
||||
return new BigIntegerItem(buf);
|
||||
}
|
||||
}
|
||||
|
||||
public int compareTo(String o) {
|
||||
@@ -364,6 +486,4 @@ public class VersionNumber implements Comparable<VersionNumber> {
|
||||
public int hashCode() {
|
||||
return canonical.hashCode();
|
||||
}
|
||||
|
||||
public static final Comparator<String> VERSION_COMPARATOR = Comparator.comparing(VersionNumber::asVersion);
|
||||
}
|
||||
@@ -209,6 +209,13 @@ public class CrashReportAnalyzerTest {
|
||||
CrashReportAnalyzer.Rule.GRAPHICS_DRIVER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void modName() throws IOException {
|
||||
CrashReportAnalyzer.Result result = findResultByRule(
|
||||
CrashReportAnalyzer.anaylze(loadLog("/logs/mod_name.txt")),
|
||||
CrashReportAnalyzer.Rule.MOD_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void openj9() throws IOException {
|
||||
CrashReportAnalyzer.Result result = findResultByRule(
|
||||
@@ -347,6 +354,27 @@ public class CrashReportAnalyzerTest {
|
||||
CrashReportAnalyzer.Rule.OPTIFINE_REPEAT_INSTALLATION);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incompleteForgeInstallation() throws IOException {
|
||||
CrashReportAnalyzer.Result result = findResultByRule(
|
||||
CrashReportAnalyzer.anaylze(loadLog("/logs/incomplete_forge_installation.txt")),
|
||||
CrashReportAnalyzer.Rule.INCOMPLETE_FORGE_INSTALLATION);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incompleteForgeInstallation2() throws IOException {
|
||||
CrashReportAnalyzer.Result result = findResultByRule(
|
||||
CrashReportAnalyzer.anaylze(loadLog("/logs/incomplete_forge_installation2.txt")),
|
||||
CrashReportAnalyzer.Rule.INCOMPLETE_FORGE_INSTALLATION);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incompleteForgeInstallation3() throws IOException {
|
||||
CrashReportAnalyzer.Result result = findResultByRule(
|
||||
CrashReportAnalyzer.anaylze(loadLog("/logs/incomplete_forge_installation3.txt")),
|
||||
CrashReportAnalyzer.Rule.INCOMPLETE_FORGE_INSTALLATION);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forgeRepeatInstallation() throws IOException {
|
||||
CrashReportAnalyzer.Result result = findResultByRule(
|
||||
|
||||
@@ -19,105 +19,135 @@ package org.jackhuang.hmcl.util.versioning;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.jackhuang.hmcl.util.versioning.VersionNumber.isIntVersionNumber;
|
||||
import static org.jackhuang.hmcl.util.versioning.VersionNumber.normalize;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class VersionNumberTest {
|
||||
|
||||
@Test
|
||||
public void testCanonical() {
|
||||
VersionNumber u, v;
|
||||
assertEquals("3.2", normalize("3.2.0.0"));
|
||||
assertEquals("3.2-5", normalize("3.2.0.0-5"));
|
||||
assertEquals("3.2", normalize("3.2.0.0-0"));
|
||||
assertEquals("3.2", normalize("3.2--------"));
|
||||
assertEquals("3.2", normalize("3.0002"));
|
||||
assertEquals("1.7.2$%%^@&snapshot-3.1.1", normalize("1.7.2$%%^@&snapshot-3.1.1"));
|
||||
assertEquals("1.99999999999999999999", normalize("1.99999999999999999999"));
|
||||
assertEquals("1.99999999999999999999", normalize("1.0099999999999999999999"));
|
||||
assertEquals("1.99999999999999999999", normalize("1.99999999999999999999.0"));
|
||||
assertEquals("1.99999999999999999999", normalize("1.99999999999999999999--------"));
|
||||
}
|
||||
|
||||
v = VersionNumber.asVersion("3.2.0.0");
|
||||
assertEquals("3.2", v.getCanonical());
|
||||
@Test
|
||||
public void testIsIntVersion() {
|
||||
assertFalse(isIntVersionNumber(""));
|
||||
assertFalse(isIntVersionNumber(" "));
|
||||
assertFalse(isIntVersionNumber("."));
|
||||
assertFalse(isIntVersionNumber("1."));
|
||||
assertFalse(isIntVersionNumber(".1"));
|
||||
assertFalse(isIntVersionNumber(".1."));
|
||||
assertFalse(isIntVersionNumber("1..8"));
|
||||
assertFalse(isIntVersionNumber("1.8."));
|
||||
assertFalse(isIntVersionNumber(".1.8"));
|
||||
assertFalse(isIntVersionNumber("1.7.10forge1614_FTBInfinity"));
|
||||
assertFalse(isIntVersionNumber("3.2-5"));
|
||||
assertFalse(isIntVersionNumber("1.9999999999"));
|
||||
|
||||
v = VersionNumber.asVersion("3.2.0.0-5");
|
||||
assertEquals("3.2-5", v.getCanonical());
|
||||
assertTrue(isIntVersionNumber("0"));
|
||||
assertTrue(isIntVersionNumber("1"));
|
||||
assertTrue(isIntVersionNumber("0.1"));
|
||||
assertTrue(isIntVersionNumber("0.1.0"));
|
||||
assertTrue(isIntVersionNumber("1.8"));
|
||||
assertTrue(isIntVersionNumber("1.12.2"));
|
||||
assertTrue(isIntVersionNumber("1.13.1"));
|
||||
assertTrue(isIntVersionNumber("1.999999999"));
|
||||
assertTrue(isIntVersionNumber("999999999.0"));
|
||||
}
|
||||
|
||||
v = VersionNumber.asVersion("3.2.0.0-0");
|
||||
assertEquals("3.2", v.getCanonical());
|
||||
private static void assertLessThan(String s1, String s2) {
|
||||
Supplier<String> messageSupplier = () -> String.format("%s should be less than %s", s1, s2);
|
||||
|
||||
v = VersionNumber.asVersion("3.2--------");
|
||||
assertEquals("3.2", v.getCanonical());
|
||||
VersionNumber v1 = VersionNumber.asVersion(s1);
|
||||
VersionNumber v2 = VersionNumber.asVersion(s2);
|
||||
|
||||
v = VersionNumber.asVersion("1.7.2$%%^@&snapshot-3.1.1");
|
||||
assertEquals("1.7.2$%%^@&snapshot-3.1.1", v.getCanonical());
|
||||
assertTrue(v1.compareTo(v2) < 0, messageSupplier);
|
||||
assertTrue(v2.compareTo(v1) > 0, messageSupplier);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComparator() {
|
||||
VersionNumber u, v;
|
||||
|
||||
u = VersionNumber.asVersion("1.7.10forge1614_FTBInfinity");
|
||||
v = VersionNumber.asVersion("1.12.2");
|
||||
assertTrue(u.compareTo(v) < 0);
|
||||
|
||||
u = VersionNumber.asVersion("1.8.0_51");
|
||||
v = VersionNumber.asVersion("1.8.0.51");
|
||||
assertTrue(u.compareTo(v) < 0);
|
||||
|
||||
u = VersionNumber.asVersion("1.8.0_151");
|
||||
v = VersionNumber.asVersion("1.8.0_77");
|
||||
assertTrue(u.compareTo(v) > 0);
|
||||
|
||||
u = VersionNumber.asVersion("1.6.0_22");
|
||||
v = VersionNumber.asVersion("1.8.0_11");
|
||||
assertTrue(u.compareTo(v) < 0);
|
||||
|
||||
u = VersionNumber.asVersion("1.7.0_22");
|
||||
v = VersionNumber.asVersion("1.7.99");
|
||||
assertTrue(u.compareTo(v) < 0);
|
||||
|
||||
u = VersionNumber.asVersion("1.12.2-14.23.5.2760");
|
||||
v = VersionNumber.asVersion("1.12.2-14.23.4.2739");
|
||||
assertTrue(u.compareTo(v) > 0);
|
||||
assertLessThan("1.7.10forge1614_FTBInfinity", "1.12.2");
|
||||
assertLessThan("1.8.0_51", "1.8.0.51");
|
||||
assertLessThan("1.8.0_77", "1.8.0_151");
|
||||
assertLessThan("1.6.0_22", "1.8.0_11");
|
||||
assertLessThan("1.7.0_22", "1.7.99");
|
||||
assertLessThan("1.12.2-14.23.4.2739", "1.12.2-14.23.5.2760");
|
||||
assertLessThan("1.9", "1.99999999999999999999");
|
||||
assertLessThan("1.99999999999999999999", "1.199999999999999999999");
|
||||
assertLessThan("1.99999999999999999999", "2");
|
||||
assertLessThan("1.99999999999999999999", "2.0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSorting() {
|
||||
List<String> input = Arrays.asList(
|
||||
"1.10",
|
||||
"1.10.2",
|
||||
"1.10.2-All the Mods",
|
||||
"1.10.2-AOE",
|
||||
"1.10.2-AOE-1.1.5",
|
||||
"1.10.2-forge2511-Age_of_Progression",
|
||||
"1.10.2-forge2511-AOE-1.1.2",
|
||||
"1.10.2-forge2511-ATM-E",
|
||||
"1.10.2-forge2511-simple_life_2",
|
||||
"1.10.2-forge2511_bxztest",
|
||||
"1.10.2-forge2511_Farming_Valley",
|
||||
"1.10.2-forge2511中文",
|
||||
"1.10.2-FTB_Beyond",
|
||||
"1.10.2-LiteLoader1.10.2",
|
||||
"1.12.2",
|
||||
"1.12.2_Modern_Skyblock-3.4.2",
|
||||
"1.13.1",
|
||||
final Comparator<String> comparator = VersionNumber.VERSION_COMPARATOR.thenComparing(String::compareTo);
|
||||
final List<String> input = Collections.unmodifiableList(Arrays.asList(
|
||||
"0",
|
||||
"0.10.0",
|
||||
"1.6.4",
|
||||
"1.6.4-Forge9.11.1.1345",
|
||||
"1.7.10",
|
||||
"1.7.10-1614",
|
||||
"1.7.10-1614-test",
|
||||
"1.7.10Agrarian_Skies_2",
|
||||
"1.7.10-F1614-L",
|
||||
"1.7.10-FL1614_04",
|
||||
"1.7.10-Forge10.13.4.1614-1.7.10",
|
||||
"1.7.10-Forge1614",
|
||||
"1.7.10-Forge1614.1",
|
||||
"1.7.10Agrarian_Skies_2",
|
||||
"1.7.10forge1614test",
|
||||
"1.7.10forge1614_ATlauncher",
|
||||
"1.7.10forge1614_FTBInfinity",
|
||||
"1.7.10Forge1614_FTBInfinity-2.6.0",
|
||||
"1.7.10Forge1614_FTBInfinity-3.0.1",
|
||||
"1.7.10-Forge1614.1",
|
||||
"1.7.10forge1614_ATlauncher",
|
||||
"1.7.10forge1614_FTBInfinity",
|
||||
"1.7.10forge1614_FTBInfinity_server",
|
||||
"1.7.10forge1614test",
|
||||
"1.7.10-1614",
|
||||
"1.7.10-1614-test",
|
||||
"1.8",
|
||||
"1.8-forge1577",
|
||||
"1.8.9",
|
||||
"1.8.9-forge1902",
|
||||
"1.9");
|
||||
input.sort(Comparator.comparing(VersionNumber::asVersion));
|
||||
"1.9",
|
||||
"1.10",
|
||||
"1.10.2",
|
||||
"1.10.2-AOE",
|
||||
"1.10.2-AOE-1.1.5",
|
||||
"1.10.2-All the Mods",
|
||||
"1.10.2-FTB_Beyond",
|
||||
"1.10.2-LiteLoader1.10.2",
|
||||
"1.10.2-forge2511-AOE-1.1.2",
|
||||
"1.10.2-forge2511-ATM-E",
|
||||
"1.10.2-forge2511-Age_of_Progression",
|
||||
"1.10.2-forge2511_Farming_Valley",
|
||||
"1.10.2-forge2511_bxztest",
|
||||
"1.10.2-forge2511-simple_life_2",
|
||||
"1.10.2-forge2511中文",
|
||||
"1.12.2",
|
||||
"1.12.2_Modern_Skyblock-3.4.2",
|
||||
"1.13.1",
|
||||
"1.99999999999999999999",
|
||||
"2",
|
||||
"2.0",
|
||||
"2.1"));
|
||||
|
||||
List<String> output = new ArrayList<>(input);
|
||||
output.sort(comparator);
|
||||
assertIterableEquals(input, output);
|
||||
|
||||
Collections.shuffle(output, new Random(0));
|
||||
output.sort(comparator);
|
||||
assertIterableEquals(input, output);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
[authlib-injector] [INFO] Logging file: D:\❄❄❄❄❄❄❄❄\FileRecv\.minecraft\authlib-injector.log
|
||||
[authlib-injector] [INFO] Version: 1.2.2
|
||||
[authlib-injector] [INFO] Authentication server: http://localhost:59486
|
||||
[authlib-injector] [WARNING] You are using HTTP protocol, which is INSECURE! Please switch to HTTPS if possible.
|
||||
[11:25:59] [main/INFO]: ModLauncher running: args [--username, 666, --version, 1.19.2, --gameDir, D:\❄❄❄❄❄❄❄❄\FileRecv\.minecraft, --assetsDir, D:\❄❄❄❄❄❄❄❄\FileRecv\.minecraft\assets, --assetIndex, 1.19, --uuid, 1ee797995aa33433bd3790203ecd5ce7, --accessToken, ❄❄❄❄❄❄❄❄, --clientId, ${clientid}, --xuid, ${auth_xuid}, --userType, legacy, --versionType, HMCL 3.5.3.230, --width, 854, --height, 480, --launchTarget, forgeclient, --fml.forgeVersion, 43.1.47, --fml.mcVersion, 1.19.2, --fml.forgeGroup, net.minecraftforge, --fml.mcpVersion, 20220805.130853]
|
||||
[11:26:00] [main/INFO]: ModLauncher 10.0.8+10.0.8+main.0ef7e830 starting: java version 17.0.1 by Microsoft; OS Windows 10 arch amd64 version 10.0
|
||||
[11:26:00] [main/INFO]: SpongePowered MIXIN Subsystem Version=0.8.5 Source=union:/D:/❄❄❄❄❄❄❄❄/FileRecv/.minecraft/libraries/org/spongepowered/mixin/0.8.5/mixin-0.8.5.jar%2391!/ Service=ModLauncher Env=CLIENT
|
||||
[11:26:00] [main/INFO]: Found mod file CTM-1.19.2-1.1.6+8.jar of type MOD with provider {mods folder locator at D:\❄❄❄❄❄❄❄❄\FileRecv\.minecraft\mods}
|
||||
[11:26:00] [main/INFO]: Found mod file Patchouli-1.19.2-77.jar of type MOD with provider {mods folder locator at D:\❄❄❄❄❄❄❄❄\FileRecv\.minecraft\mods}
|
||||
[11:26:00] [main/INFO]: Found mod file twilightforest-fabric-1.19.2-4.2.301.jar of type MOD with provider {mods folder locator at D:\❄❄❄❄❄❄❄❄\FileRecv\.minecraft\mods}
|
||||
Exception in thread "main" java.io.UncheckedIOException: java.io.IOException: Invalid paths argument, contained no existing paths: [D:\❄❄❄❄❄❄❄❄\FileRecv\.minecraft\libraries\net\minecraft\client\1.19.2-20220805.130853\client-1.19.2-20220805.130853-srg.jar, D:\❄❄❄❄❄❄❄❄\FileRecv\.minecraft\libraries\net\minecraft\client\1.19.2-20220805.130853\client-1.19.2-20220805.130853-extra.jar, D:\❄❄❄❄❄❄❄❄\FileRecv\.minecraft\libraries\net\minecraftforge\forge\1.19.2-43.1.47\forge-1.19.2-43.1.47-client.jar]
|
||||
at cpw.mods.securejarhandler/cpw.mods.jarhandling.impl.Jar.<init>(Jar.java:82)
|
||||
at cpw.mods.securejarhandler/cpw.mods.jarhandling.SecureJar.from(SecureJar.java:70)
|
||||
at MC-BOOTSTRAP/fmlloader@1.19.2-43.1.47/net.minecraftforge.fml.loading.moddiscovery.ModJarMetadata.buildFile(ModJarMetadata.java:41)
|
||||
at MC-BOOTSTRAP/fmlloader@1.19.2-43.1.47/net.minecraftforge.fml.loading.moddiscovery.MinecraftLocator.scanMods(MinecraftLocator.java:37)
|
||||
at MC-BOOTSTRAP/fmlloader@1.19.2-43.1.47/net.minecraftforge.fml.loading.moddiscovery.ModDiscoverer.discoverMods(ModDiscoverer.java:74)
|
||||
at MC-BOOTSTRAP/fmlloader@1.19.2-43.1.47/net.minecraftforge.fml.loading.FMLLoader.beginModScan(FMLLoader.java:166)
|
||||
at MC-BOOTSTRAP/fmlloader@1.19.2-43.1.47/net.minecraftforge.fml.loading.FMLServiceProvider.beginScanning(FMLServiceProvider.java:86)
|
||||
at MC-BOOTSTRAP/cpw.mods.modlauncher@10.0.8/cpw.mods.modlauncher.TransformationServiceDecorator.runScan(TransformationServiceDecorator.java:112)
|
||||
at MC-BOOTSTRAP/cpw.mods.modlauncher@10.0.8/cpw.mods.modlauncher.TransformationServicesHandler.lambda$runScanningTransformationServices$8(TransformationServicesHandler.java:100)
|
||||
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
|
||||
at java.base/java.util.HashMap$ValueSpliterator.forEachRemaining(HashMap.java:1779)
|
||||
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
|
||||
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
|
||||
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:575)
|
||||
at java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
|
||||
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:616)
|
||||
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:622)
|
||||
at java.base/java.util.stream.ReferencePipeline.toList(ReferencePipeline.java:627)
|
||||
at MC-BOOTSTRAP/cpw.mods.modlauncher@10.0.8/cpw.mods.modlauncher.TransformationServicesHandler.runScanningTransformationServices(TransformationServicesHandler.java:102)
|
||||
at MC-BOOTSTRAP/cpw.mods.modlauncher@10.0.8/cpw.mods.modlauncher.TransformationServicesHandler.initializeTransformationServices(TransformationServicesHandler.java:55)
|
||||
at MC-BOOTSTRAP/cpw.mods.modlauncher@10.0.8/cpw.mods.modlauncher.Launcher.run(Launcher.java:87)
|
||||
at MC-BOOTSTRAP/cpw.mods.modlauncher@10.0.8/cpw.mods.modlauncher.Launcher.main(Launcher.java:77)
|
||||
at MC-BOOTSTRAP/cpw.mods.modlauncher@10.0.8/cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(BootstrapLaunchConsumer.java:26)
|
||||
at MC-BOOTSTRAP/cpw.mods.modlauncher@10.0.8/cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(BootstrapLaunchConsumer.java:23)
|
||||
at cpw.mods.bootstraplauncher@1.1.2/cpw.mods.bootstraplauncher.BootstrapLauncher.main(BootstrapLauncher.java:141)
|
||||
Caused by: java.io.IOException: Invalid paths argument, contained no existing paths: [D:\❄❄❄❄❄❄❄❄\FileRecv\.minecraft\libraries\net\minecraft\client\1.19.2-20220805.130853\client-1.19.2-20220805.130853-srg.jar, D:\❄❄❄❄❄❄❄❄\FileRecv\.minecraft\libraries\net\minecraft\client\1.19.2-20220805.130853\client-1.19.2-20220805.130853-extra.jar, D:\❄❄❄❄❄❄❄❄\FileRecv\.minecraft\libraries\net\minecraftforge\forge\1.19.2-43.1.47\forge-1.19.2-43.1.47-client.jar]
|
||||
... 25 more
|
||||
@@ -0,0 +1,21 @@
|
||||
2023-03-18 12:54:04,303 main ERROR Error processing element Queue ([Appenders: null]): CLASS_NOT_FOUND
|
||||
[12:54:05] [main/INFO]: ModLauncher running: args [--username, 2333, --version, Minecraft Pixelmon, --gameDir, C:\Users\Administrator\Downloads\.minecraft, --assetsDir, C:\Users\Administrator\Downloads\.minecraft\assets, --assetIndex, 1.16, --uuid, 19a73ce1f6c13f9bbdbaecaab8291e74, --accessToken, ❄❄❄❄❄❄❄❄, --userType, legacy, --versionType, HMCL 3.5.4, --width, 854, --height, 480, --launchTarget, fmlclient, --fml.forgeVersion, 36.2.34, --fml.mcVersion, 1.16.5, --fml.forgeGroup, net.minecraftforge, --fml.mcpVersion, 20210115.111550]
|
||||
[12:54:05] [main/INFO]: ModLauncher 8.1.3+8.1.3+main-8.1.x.c94d18ec starting: java version 1.8.0_361 by Oracle Corporation
|
||||
[12:54:08] [main/INFO]: Added Lets Encrypt root certificates as additional trust
|
||||
[12:54:08] [main/INFO]: SpongePowered MIXIN Subsystem Version=0.8.4 Source=file:/C:/Users/Administrator/Downloads/.minecraft/libraries/org/spongepowered/mixin/0.8.4/mixin-0.8.4.jar Service=ModLauncher Env=CLIENT
|
||||
[12:54:09] [main/FATAL]: Failed to find Minecraft resource version 1.16.5-20210115.111550 at C:\Users\Administrator\Downloads\.minecraft\libraries\net\minecraftforge\forge\1.16.5-36.2.34\forge-1.16.5-36.2.34-client.jar
|
||||
[12:54:09] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:-1]: java.lang.RuntimeException: Missing minecraft resource!
|
||||
[12:54:09] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:-1]: at net.minecraftforge.fml.loading.FMLCommonLaunchHandler.lambda$validatePaths$4(FMLCommonLaunchHandler.java:124)
|
||||
[12:54:09] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:-1]: at java.util.Spliterators$ArraySpliterator.forEachRemaining(Unknown Source)
|
||||
[12:54:09] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:-1]: at java.util.stream.ReferencePipeline$Head.forEach(Unknown Source)
|
||||
[12:54:09] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:-1]: at net.minecraftforge.fml.loading.FMLCommonLaunchHandler.validatePaths(FMLCommonLaunchHandler.java:121)
|
||||
[12:54:09] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:-1]: at net.minecraftforge.fml.loading.FMLLoader.setupLaunchHandler(FMLLoader.java:202)
|
||||
[12:54:09] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:-1]: at net.minecraftforge.fml.loading.FMLServiceProvider.initialize(FMLServiceProvider.java:94)
|
||||
[12:54:09] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:-1]: at cpw.mods.modlauncher.TransformationServiceDecorator.onInitialize(TransformationServiceDecorator.java:68)
|
||||
[12:54:09] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:-1]: at cpw.mods.modlauncher.TransformationServicesHandler.lambda$initialiseTransformationServices$7(TransformationServicesHandler.java:107)
|
||||
[12:54:09] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:-1]: at java.util.HashMap$Values.forEach(Unknown Source)
|
||||
[12:54:09] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:-1]: at cpw.mods.modlauncher.TransformationServicesHandler.initialiseTransformationServices(TransformationServicesHandler.java:107)
|
||||
[12:54:09] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:-1]: at cpw.mods.modlauncher.TransformationServicesHandler.initializeTransformationServices(TransformationServicesHandler.java:59)
|
||||
[12:54:09] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:-1]: at cpw.mods.modlauncher.Launcher.run(Launcher.java:76)
|
||||
[12:54:09] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:-1]: at cpw.mods.modlauncher.Launcher.main(Launcher.java:66)
|
||||
Exception in thread "main"
|
||||
@@ -0,0 +1,9 @@
|
||||
2023-03-16 22:19:06,155 main ERROR Error processing element Queue ([Appenders: null]): CLASS_NOT_FOUND
|
||||
[22:19:06] [main/INFO]: ModLauncher running: args [--username, 111, --version, RAD2-1.16.5, --gameDir, C:\Users\Administrator\Desktop\HMCL\.minecraft\versions\RAD2-1.16.5, --assetsDir, C:\Users\Administrator\Desktop\HMCL\.minecraft\assets, --assetIndex, 1.16, --uuid, 2a386545f1ff370eab061a766a28340a, --accessToken, ❄❄❄❄❄❄❄❄, --userType, legacy, --versionType, HMCL 3.5.3.228, --width, 854, --height, 480, --launchTarget, fmlclient, --fml.forgeVersion, 36.2.39, --fml.mcVersion, 1.16.5, --fml.forgeGroup, net.minecraftforge, --fml.mcpVersion, 20210115.111550]
|
||||
[22:19:06] [main/INFO]: ModLauncher 8.1.3+8.1.3+main-8.1.x.c94d18ec starting: java version 1.8.0_362 by BellSoft
|
||||
[22:19:06] [main/INFO]: SpongePowered MIXIN Subsystem Version=0.8.4 Source=file:/C:/Users/Administrator/Desktop/HMCL/.minecraft/libraries/org/spongepowered/mixin/0.8.4/mixin-0.8.4.jar Service=ModLauncher Env=CLIENT
|
||||
[22:19:06] [main/ERROR]: Cannot find launch target fmlclient, unable to launch
|
||||
Exception in thread "main" java.lang.RuntimeException: Cannot find launch target
|
||||
at cpw.mods.modlauncher.LaunchServiceHandler.validateLaunchTarget(LaunchServiceHandler.java:87)
|
||||
at cpw.mods.modlauncher.Launcher.run(Launcher.java:78)
|
||||
at cpw.mods.modlauncher.Launcher.main(Launcher.java:66)
|
||||
@@ -0,0 +1,39 @@
|
||||
[23:16:40] [main/INFO]: ModLauncher running: args [--username, ygu, --version, 1.19.3, --gameDir, D:\MC\.minecraft, --assetsDir, D:\MC\.minecraft\assets, --assetIndex, 2, --uuid, 28ae47c586363ebfae84cce7b2d47198, --accessToken, ❄❄❄❄❄❄❄❄, --clientId, ${clientid}, --xuid, ${auth_xuid}, --userType, legacy, --versionType, HMCL 3.5.4, --width, 854, --height, 480, --launchTarget, forgeclient, --fml.forgeVersion, 44.1.23, --fml.mcVersion, 1.19.3, --fml.forgeGroup, net.minecraftforge, --fml.mcpVersion, 20221207.122022]
|
||||
[23:16:40] [main/INFO]: ModLauncher 10.0.8+10.0.8+main.0ef7e830 starting: java version 17.0.6 by Microsoft; OS Windows 11 arch amd64 version 10.0
|
||||
Exception in thread "main" java.lang.IllegalArgumentException: : Invalid module name: '' is not a Java identifier
|
||||
at java.base/jdk.internal.module.Checks.requireModuleName(Checks.java:59)
|
||||
at java.base/java.lang.module.ModuleDescriptor$Builder.<init>(ModuleDescriptor.java:1515)
|
||||
at java.base/java.lang.module.ModuleDescriptor.newAutomaticModule(ModuleDescriptor.java:2395)
|
||||
at cpw.mods.securejarhandler/cpw.mods.jarhandling.impl.SimpleJarMetadata.descriptor(SimpleJarMetadata.java:13)
|
||||
at cpw.mods.securejarhandler/cpw.mods.jarhandling.impl.Jar.computeDescriptor(Jar.java:51)
|
||||
at cpw.mods.securejarhandler/cpw.mods.jarhandling.impl.Jar$JarModuleDataProvider.descriptor(Jar.java:276)
|
||||
at MC-BOOTSTRAP/fmlloader@1.19.3-44.1.23/net.minecraftforge.fml.loading.ModDirTransformerDiscoverer.visitFile(ModDirTransformerDiscoverer.java:62)
|
||||
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
|
||||
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
|
||||
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
|
||||
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1845)
|
||||
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
|
||||
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
|
||||
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
|
||||
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
|
||||
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
|
||||
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
|
||||
at MC-BOOTSTRAP/fmlloader@1.19.3-44.1.23/net.minecraftforge.fml.loading.ModDirTransformerDiscoverer.scan(ModDirTransformerDiscoverer.java:50)
|
||||
at MC-BOOTSTRAP/fmlloader@1.19.3-44.1.23/net.minecraftforge.fml.loading.ModDirTransformerDiscoverer.candidates(ModDirTransformerDiscoverer.java:33)
|
||||
at MC-BOOTSTRAP/cpw.mods.modlauncher@10.0.8/cpw.mods.modlauncher.serviceapi.ITransformerDiscoveryService.candidates(ITransformerDiscoveryService.java:48)
|
||||
at MC-BOOTSTRAP/cpw.mods.modlauncher@10.0.8/cpw.mods.modlauncher.TransformationServicesHandler.lambda$discoverServices$14(TransformationServicesHandler.java:125)
|
||||
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
|
||||
at java.base/java.util.AbstractList$RandomAccessSpliterator.forEachRemaining(AbstractList.java:720)
|
||||
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
|
||||
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
|
||||
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:575)
|
||||
at java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
|
||||
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:616)
|
||||
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:622)
|
||||
at java.base/java.util.stream.ReferencePipeline.toList(ReferencePipeline.java:627)
|
||||
at MC-BOOTSTRAP/cpw.mods.modlauncher@10.0.8/cpw.mods.modlauncher.TransformationServicesHandler.discoverServices(TransformationServicesHandler.java:127)
|
||||
at MC-BOOTSTRAP/cpw.mods.modlauncher@10.0.8/cpw.mods.modlauncher.Launcher.run(Launcher.java:86)
|
||||
at MC-BOOTSTRAP/cpw.mods.modlauncher@10.0.8/cpw.mods.modlauncher.Launcher.main(Launcher.java:77)
|
||||
at MC-BOOTSTRAP/cpw.mods.modlauncher@10.0.8/cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(BootstrapLaunchConsumer.java:26)
|
||||
at MC-BOOTSTRAP/cpw.mods.modlauncher@10.0.8/cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(BootstrapLaunchConsumer.java:23)
|
||||
at cpw.mods.bootstraplauncher@1.1.2/cpw.mods.bootstraplauncher.BootstrapLauncher.main(BootstrapLauncher.java:141)
|
||||
+1
-1
@@ -7,10 +7,10 @@
|
||||
| ARM64 | 👌 (1.8+)<br/>✅ (use x86 emulation) | 👌 | 👌 (1.6~1.18.2)<br/>✅ (1.19+)<br/>✅ (use Rosetta 2) | ❔ |
|
||||
| ARM32 | /️ | 👌 | / | / |
|
||||
| MIPS64el | / | 👌 | / | / |
|
||||
| RISC-V 64 | / | 👌 (1.13+) | / | / |
|
||||
| LoongArch64 | / | 👌 (for Old World)<br/>❔ (for New World) | / | / |
|
||||
| PowerPC-64 (Little-Endian) | / | ❔ | / | / |
|
||||
| S390x | / | ❔ | / | / |
|
||||
| RISC-V | / | ❔ | / | / |
|
||||
|
||||
Legend:
|
||||
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -144,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
@@ -152,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
|
||||
@@ -41,6 +41,7 @@ val jfxPlatforms = listOf(
|
||||
Platform("linux-arm32", "linux-arm32-monocle", unsupportedModules = listOf("media", "web")),
|
||||
Platform("linux-arm64", "linux-aarch64"),
|
||||
Platform("linux-loongarch64_ow", "linux", groupId = "org.glavo.hmcl.openjfx", version = "19-ea+10-loongson64", unsupportedModules = listOf("media", "web")),
|
||||
Platform("linux-riscv64", "linux", groupId = "org.glavo.hmcl.openjfx", version = "19.0.2.1-riscv64", unsupportedModules = listOf("media", "web")),
|
||||
)
|
||||
|
||||
val jfxInClasspath =
|
||||
|
||||
Reference in new issue
Block a user