Compare commits

...
Author SHA1 Message Date
huanghongxun 470c3d6c24 fix(HMCLCore): do not init JavaFX in JTest. 2023-06-16 08:48:59 +08:00
zkitefly 6133e7e730 Update PURCHASE_URL and MIGRATION_FAQ_URL (#2229) 2023-06-16 08:39:16 +08:00
zkitefly c5cbafea60 添加 remove_assets 按钮 (#2257) 2023-06-16 08:38:27 +08:00
zkitefly 167e25e859 添加更多日志分析规则 (#2192)
* 添加“Forge 安装不完整”的检查

* fix

* fix

* add modName

* 更新 CrashReportAnalyzer.java

* 更新 CrashReportAnalyzerTest.java
2023-06-16 08:36:03 +08:00
zkitefly f47bd8a407 更新 CrashReportAnalyzer.java (#2175) 2023-06-16 08:31:44 +08:00
zkitefly 464be411d1 Updata account.failed.server_disconnected (#2247) 2023-06-16 08:23:11 +08:00
zkitefly d3b6eb36d9 Update DefaultGameRepository.java (#2273) 2023-06-16 08:21:27 +08:00
Glavo 71458f5167 启动时检测 Fractureiser 病毒 (#2270) 2023-06-16 08:21:06 +08:00
zkitefly 597730389f Close #1367 (#2232) 2023-06-16 08:18:41 +08:00
zkitefly 56b227f467 添加新显示项目:物理内存大小 (#2279) 2023-06-16 08:17:30 +08:00
Glavo 213b03ea56 Print warning message when signature key is missing (#2283) 2023-06-16 08:13:05 +08:00
Glavo 959c4d0698 检测 macOS 上的 App Translocation (#2252)
* check app translocation on macOS

* update

* update
2023-06-16 08:12:41 +08:00
zkitefly 57b3bd9ff0 修复分类翻译键问题 (#2277)
* 修复分类翻译键问题

* 更新搜索版本号
2023-06-16 08:11:09 +08:00
zkitefly 68f4038879 更新 Issue 模板 (#2278)
* Create feature.yml

* Update config.yml

* Update config.yml

* Update feature.yml
2023-06-16 08:10:44 +08:00
Glavo 6010008409 使用 ObservableMap 记录已显示的提示 (#2271) 2023-06-13 10:21:03 +08:00
Haowei Wen 4b2e857f08 Fix chat is broken on Minecraft 1.20 2023-06-12 00:42:41 +08:00
Glavo 0280a34d00 fix #2267: filter duplicate jars in the class path (#2280) 2023-06-11 15:47:43 +08:00
Glavo 811707b611 代码清理以及微优化 (#2244) 2023-05-26 00:52:46 +08:00
Glavo 9152550bda Suppress compilation warnings (#2243)
* Suppress compilation warnings

* update
2023-05-24 22:05:30 +08:00
Glavo 6cb4d24600 Log XDG_SESSION_TYPE (#2242) 2023-05-24 21:51:22 +08:00
Glavo 49287453eb 优化 VersionNumber (#2240)
* 优化 VersionNumber

* Add more tests

* update

* update tests
2023-05-24 21:28:22 +08:00
Glavo e7c108d843 修复使用系统 GLFW 选项对 1.19+ 不生效的问题 (#2241)
* 修复使用系统 GLFW 选项对 1.19+ 不生效的问题

* Use UTF-8 in NativePatcher

* update
2023-05-24 21:15:09 +08:00
Glavo 6c9bf6cb09 修复翻译 (#2239) 2023-05-23 15:07:53 +08:00
Glavo efc27c8e21 添加 Linux RISC-V 64 平台支持 (#2238) 2023-05-23 05:17:26 +08:00
Glavo 7c5ccc906e 优化 SSL 异常报错信息 (#2234)
* 改进 SSL 异常报错

* update
2023-05-22 16:40:34 +08:00
zkitefly 69a6ff6053 Fix 2226 (#2227) 2023-05-20 02:18:25 +08:00
zkitefly 605d0c6a92 Fix #2204 (#2228)
https://github.com/huanghongxun/HMCL/issues/2204#issuecomment-1519823562
2023-05-20 02:17:18 +08:00
Glavo 9d54ddf456 修复无法使用 macOS aarch64 JRE 启动部分版本的问题 (#2222) 2023-05-10 20:08:53 +08:00
Glavo c6afd53e73 Bump dependencies (#2191) 2023-04-06 02:41:57 +08:00
Glavo fd9bb88033 添加隐藏提示按钮 (#2018)
* 添加隐藏提示按钮

* update

* update

* update

* update
2023-04-06 02:33:22 +08:00
Glavo 316607b333 添加对 Linux RISC-V 64 平台的基本支持 (#2187) 2023-04-01 06:29:51 +08:00
53 changed files with 1023 additions and 406 deletions

No files matched your search

+2 -2
View File
@@ -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 反馈其他问题。
+21
View File
@@ -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
+6 -1
View File
@@ -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();
@@ -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;
}
}
@@ -323,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);
@@ -73,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);
@@ -100,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() + ")";
@@ -292,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"));
@@ -312,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);
@@ -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();
@@ -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 -> {
@@ -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"))
);
@@ -472,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;
@@ -555,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());
}
});
@@ -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;
}
}
@@ -7,13 +7,16 @@ 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;
@@ -23,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;
@@ -45,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;
@@ -54,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;
}
@@ -68,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);
@@ -91,22 +132,6 @@ public final class NativePatcher {
}
public static Library getMesaLoader(JavaVersion javaVersion, Renderer renderer) {
Map<String, Library> map = Hole.nativeReplacement.get(javaVersion.getPlatform().toString());
return map != null ? map.get(renderer == Renderer.LLVMPIPE ? "software-renderer-loader" : "mesa-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);
}
}
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
@@ -1007,7 +1016,7 @@ settings.advanced.post_exit_command.prompt=Commands to execute after the game ex
settings.advanced.renderer=Renderer
settings.advanced.renderer.default=OpenGL (Default)
settings.advanced.renderer.d3d12=DirectX 12 (Poor performance and compatibility)
settings.advanced.renderer.llvmpipe=軟渲染器 (Poor efficiency and best 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.
@@ -1114,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
@@ -1166,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\
@@ -1017,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
@@ -1069,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使用しているモッド/シェーダーパック/テクスチャパックを無効にして、再試行してください。
@@ -844,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=更新の確認
@@ -898,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Отключите используемые моды или наборы шейдеров/текстур и попробуйте снова.
@@ -853,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=Проверка наличия обновлений
@@ -904,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/光影包/材質包再試。
@@ -983,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=正在檢查更新
@@ -1034,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 页面寻求帮助。
@@ -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> 寻求帮助。
@@ -981,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=正在检查更新
@@ -1032,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=请输入要修改的名称
+242
View File
@@ -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",
+3 -3
View File
@@ -9,8 +9,8 @@ dependencies {
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.4")
api("com.github.steveice10:opennbt:1.5")
api("org.nanohttpd:nanohttpd:2.3.1")
api("org.apache.commons:commons-compress:1.22")
compileOnlyApi("org.jetbrains:annotations:24.0.0")
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,
@@ -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);
@@ -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())
@@ -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(
@@ -80,7 +80,7 @@ public class TaskTest {
public void testThenAccept() {
AtomicBoolean flag = new AtomicBoolean();
boolean result = Task.supplyAsync(JavaVersion::fromCurrentEnvironment)
.thenAcceptAsync(Schedulers.javafx(), javaVersion -> {
.thenAcceptAsync(Schedulers.io(), javaVersion -> {
flag.set(true);
assertEquals(javaVersion, JavaVersion.fromCurrentEnvironment());
})
@@ -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
View File
@@ -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:
+1
View File
@@ -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 =