Compare commits
8
Commits
main
...
release/3.12
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
997b75ba19 | ||
|
|
373e5c1ff0 | ||
|
|
d095eab8fc | ||
|
|
447edff1ed | ||
|
|
f7024a4c0f | ||
|
|
31c7e3a60f | ||
|
|
43cfe29eeb | ||
|
|
4921804283 |
No files matched your search
@@ -66,6 +66,7 @@ dependencies {
|
||||
}
|
||||
|
||||
embedResources(libs.authlib.injector)
|
||||
embedResources(libs.lwjgl.unsafe.agent)
|
||||
}
|
||||
|
||||
fun digest(algorithm: String, bytes: ByteArray): ByteArray = MessageDigest.getInstance(algorithm).digest(bytes)
|
||||
@@ -155,6 +156,7 @@ val hmclProperties = buildList {
|
||||
add("hmcl.microsoft.auth.id" to microsoftAuthId)
|
||||
add("hmcl.curseforge.apikey" to curseForgeApiKey)
|
||||
add("hmcl.authlib-injector.version" to libs.authlib.injector.get().version!!)
|
||||
add("hmcl.lwjgl-unsafe-agent.version" to libs.lwjgl.unsafe.agent.get().version!!)
|
||||
}
|
||||
|
||||
val hmclPropertiesFile = layout.buildDirectory.file("hmcl.properties")
|
||||
|
||||
@@ -88,6 +88,14 @@ public class JFXTextField extends TextField {
|
||||
useJFXContextMenu(this);
|
||||
}
|
||||
|
||||
// https://github.com/HMCL-dev/HMCL/issues/5822
|
||||
// TODO: This method may no longer be needed after we update JFXTextFieldSkin
|
||||
@Override
|
||||
protected void layoutChildren() {
|
||||
super.layoutChildren();
|
||||
this.setNeedsLayout(false);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* Properties *
|
||||
|
||||
@@ -21,12 +21,16 @@ import org.jackhuang.hmcl.Metadata;
|
||||
import org.jackhuang.hmcl.auth.AuthInfo;
|
||||
import org.jackhuang.hmcl.launch.DefaultLauncher;
|
||||
import org.jackhuang.hmcl.launch.ProcessListener;
|
||||
import org.jackhuang.hmcl.util.NativePatcher;
|
||||
import org.jackhuang.hmcl.util.i18n.LocaleUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.io.JarUtils;
|
||||
import org.jackhuang.hmcl.util.platform.CommandBuilder;
|
||||
import org.jackhuang.hmcl.util.platform.ManagedProcess;
|
||||
import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.*;
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
@@ -150,4 +154,60 @@ public final class HMCLGameLauncher extends DefaultLauncher {
|
||||
generateOptionsTxt();
|
||||
super.makeLaunchScript(scriptFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendJvmArgs(CommandBuilder result) {
|
||||
super.appendJvmArgs(result);
|
||||
|
||||
if (config().getAllowAutoAgent()
|
||||
&& !options.isNoGeneratedJVMArgs()
|
||||
&& !options.isNoGeneratedOptimizingJVMArgs()
|
||||
&& NativePatcher.needPatchMemoryUtil(version, options.getJava().getParsedVersion())) {
|
||||
LOG.info("Attempting to patch game with lwjgl-unsafe-agent");
|
||||
try {
|
||||
result.add("-javaagent:" + extractLwjglUnsafeAgent());
|
||||
} catch (Exception e) {
|
||||
LOG.warning("Failed to extract lwjgl-unsafe-agent", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Path extractLwjglUnsafeAgent() throws IOException {
|
||||
String agentVersion = JarUtils.getAttribute("hmcl.lwjgl-unsafe-agent.version", null);
|
||||
if (agentVersion == null) {
|
||||
throw new IOException("Missing hmcl.lwjgl-unsafe-agent.version attribute");
|
||||
}
|
||||
|
||||
Library library = new Library(new Artifact("org.glavo", "lwjgl-unsafe-agent", agentVersion));
|
||||
String fileName = library.getArtifact().getFileName();
|
||||
|
||||
Path agentPath = repository.getLibraryFile(version, library).toAbsolutePath().normalize();
|
||||
if (agentPath.toString().contains("=")) {
|
||||
throw new IOException("Invalid library path: " + agentPath);
|
||||
}
|
||||
|
||||
byte[] bytes;
|
||||
try (InputStream input = DefaultLauncher.class.getResourceAsStream("/assets/" + fileName)) {
|
||||
if (input == null) {
|
||||
throw new IOException("/assets/" + fileName + " not found");
|
||||
}
|
||||
|
||||
bytes = input.readAllBytes();
|
||||
}
|
||||
|
||||
if (Files.isRegularFile(agentPath)) {
|
||||
try {
|
||||
if (Files.size(agentPath) == bytes.length) {
|
||||
return agentPath;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Failed to check size of " + agentPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
Files.createDirectories(agentPath.getParent());
|
||||
FileUtils.saveSafely(agentPath, output -> output.write(bytes));
|
||||
return agentPath;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -65,6 +65,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import static javafx.application.Platform.runLater;
|
||||
import static javafx.application.Platform.setImplicitExit;
|
||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
|
||||
import static org.jackhuang.hmcl.util.DataSizeUnit.MEGABYTES;
|
||||
import static org.jackhuang.hmcl.util.Lang.resolveException;
|
||||
@@ -75,6 +76,8 @@ import static org.jackhuang.hmcl.util.platform.Platform.isCompatibleWithX86Java;
|
||||
|
||||
public final class LauncherHelper {
|
||||
|
||||
private static final String LWJGL_3_4_1_TIP = "lwjgl3.4.1-ffm";
|
||||
|
||||
private final Profile profile;
|
||||
private Account account;
|
||||
private final String selectedVersion;
|
||||
@@ -197,6 +200,28 @@ public final class LauncherHelper {
|
||||
);
|
||||
}).withStage("launch.state.dependencies")
|
||||
.thenComposeAsync(() -> gameVersion.map(s -> new GameVerificationFixTask(dependencyManager, s, version.get())).orElse(null))
|
||||
.thenComposeAsync(() -> {
|
||||
if (config().getAllowAutoAgent()
|
||||
|| setting.isNoJVMArgs()
|
||||
|| setting.isNoOptimizingJVMArgs()
|
||||
|| Boolean.TRUE.equals(config().getShownTips().get(LWJGL_3_4_1_TIP))
|
||||
|| !NativePatcher.needPatchMemoryUtil(version.get(), javaVersionRef.get().getParsedVersion())) {
|
||||
return Task.completed(null);
|
||||
} else {
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
runInFX(() -> {
|
||||
Controllers.confirm(i18n("launch.advice.lwjgl_3_4_1"), i18n("launch.advice.lwjgl_3_4_1.title"), MessageType.QUESTION, () -> {
|
||||
config().getShownTips().put(LWJGL_3_4_1_TIP, true);
|
||||
config().setAllowAutoAgent(true);
|
||||
future.complete(null);
|
||||
}, () -> {
|
||||
config().getShownTips().put(LWJGL_3_4_1_TIP, true);
|
||||
future.complete(null);
|
||||
});
|
||||
});
|
||||
return Task.fromCompletableFuture(future);
|
||||
}
|
||||
})
|
||||
.thenComposeAsync(() -> logIn(account).withStage("launch.state.logging_in"))
|
||||
.thenComposeAsync(authInfo -> Task.supplyAsync(() -> {
|
||||
LaunchOptions.Builder launchOptionsBuilder = repository.getLaunchOptions(
|
||||
|
||||
@@ -689,6 +689,21 @@ public final class Config extends ObservableSetting {
|
||||
this.disableAutoGameOptions.set(disableAutoGameOptions);
|
||||
}
|
||||
|
||||
@SerializedName("allowAutoAgent")
|
||||
private final BooleanProperty allowAutoAgent = new SimpleBooleanProperty(false);
|
||||
|
||||
public BooleanProperty allowAutoAgentProperty() {
|
||||
return allowAutoAgent;
|
||||
}
|
||||
|
||||
public boolean getAllowAutoAgent() {
|
||||
return allowAutoAgent.get();
|
||||
}
|
||||
|
||||
public void setAllowAutoAgent(boolean allowAutoAgent) {
|
||||
this.allowAutoAgent.set(allowAutoAgent);
|
||||
}
|
||||
|
||||
// Accounts
|
||||
|
||||
@SerializedName("authlibInjectorServers")
|
||||
|
||||
@@ -288,6 +288,15 @@ public final class SettingsPage extends ScrollPane {
|
||||
settingsPane.getContent().add(disableAutoGameOptionsPane);
|
||||
}
|
||||
|
||||
{
|
||||
LineToggleButton allowAutoAgentPane = new LineToggleButton();
|
||||
allowAutoAgentPane.setTitle(i18n("settings.launcher.allow_auto_agent"));
|
||||
allowAutoAgentPane.setSubtitle(i18n("settings.launcher.allow_auto_agent.subtitle"));
|
||||
allowAutoAgentPane.selectedProperty().bindBidirectional(config().allowAutoAgentProperty());
|
||||
|
||||
settingsPane.getContent().add(allowAutoAgentPane);
|
||||
}
|
||||
|
||||
{
|
||||
BorderPane debugPane = new BorderPane();
|
||||
|
||||
|
||||
@@ -31,21 +31,27 @@ public final class ChunkBaseApp {
|
||||
private static final GameVersionNumber MIN_END_CITY_VERSION = GameVersionNumber.asGameVersion("1.13");
|
||||
|
||||
private static final String[] SEED_MAP_GAME_VERSIONS = {
|
||||
"1.21.9", "1.21.6", "1.21.5", "1.21.4", "1.21.2", "1.21", "1.20",
|
||||
"1.19.3", "1.19", "1.18", "1.17", "1.16", "1.15", "1.14", "1.13",
|
||||
"1.12", "1.11", "1.10", "1.9", "1.8", "1.7"
|
||||
"26.1", "1.21.9", "1.21.6", "1.21.5", "1.21.4", "1.21.2", "1.21",
|
||||
"1.20", "1.19.3", "1.19", "1.18", "1.17", "1.16", "1.15", "1.14",
|
||||
"1.13", "1.12", "1.11", "1.10", "1.9", "1.8", "1.7"
|
||||
};
|
||||
|
||||
public static final String[] STRONGHOLD_FINDER_GAME_VERSIONS = {
|
||||
"1.20", "1.19.3", "1.19", "1.18", "1.16", "1.13", "1.9", "1.7"
|
||||
"26.1", "1.21.9", "1.21.6", "1.21.5", "1.21.4", "1.21.2", "1.21",
|
||||
"1.20", "1.19.3", "1.19", "1.18", "1.17", "1.16", "1.15", "1.14",
|
||||
"1.13", "1.12", "1.11", "1.10", "1.9", "1.8", "1.7"
|
||||
};
|
||||
|
||||
public static final String[] NETHER_FORTRESS_GAME_VERSIONS = {
|
||||
"1.18", "1.16", "1.7"
|
||||
"26.1", "1.21.9", "1.21.6", "1.21.5", "1.21.4", "1.21.2", "1.21",
|
||||
"1.20", "1.19.3", "1.19", "1.18", "1.17", "1.16", "1.15", "1.14",
|
||||
"1.13", "1.12", "1.11", "1.10", "1.9", "1.8", "1.7"
|
||||
};
|
||||
|
||||
public static final String[] END_CITY_GAME_VERSIONS = {
|
||||
"1.19", "1.13"
|
||||
"26.1", "1.21.9", "1.21.6", "1.21.5", "1.21.4", "1.21.2", "1.21",
|
||||
"1.20", "1.19.3", "1.19", "1.18", "1.17", "1.16", "1.15", "1.14",
|
||||
"1.13"
|
||||
};
|
||||
|
||||
public static boolean isSupported(@NotNull World world) {
|
||||
|
||||
@@ -63,6 +63,16 @@ public final class NativePatcher {
|
||||
});
|
||||
}
|
||||
|
||||
// https://github.com/LWJGL/lwjgl3/issues/1111
|
||||
public static boolean needPatchMemoryUtil(Version version, int javaVersion) {
|
||||
return javaVersion >= 25 && javaVersion <= 26 && version.getLibraries().stream().anyMatch(library ->
|
||||
"org.lwjgl".equals(library.getGroupId())
|
||||
&& "lwjgl".equals(library.getArtifactId())
|
||||
&& "3.4.1".equals(library.getVersion())
|
||||
&& library.getClassifier() == null
|
||||
);
|
||||
}
|
||||
|
||||
public static Version patchNative(DefaultGameRepository repository,
|
||||
Version version, String gameVersion,
|
||||
JavaRuntime javaVersion,
|
||||
|
||||
@@ -155,7 +155,32 @@ public class Translator_lzh extends Translator {
|
||||
case "23w13a_or_b" -> "二三週一三暨";
|
||||
case "24w14potato" -> "二四週一四芋";
|
||||
case "25w14craftmine" -> "二五週一四礦";
|
||||
default -> version;
|
||||
default -> {
|
||||
if (version.length() >= 6 && version.charAt(2) == 'w') {
|
||||
Matcher matcher = Pattern.compile("(?<year>[0-9]{2})w(?<week>[0-9]{2})(?<suffix>.+)").matcher(version);
|
||||
if (matcher.matches()) {
|
||||
int year = Integer.parseInt(matcher.group("year"));
|
||||
int week = Integer.parseInt(matcher.group("week"));
|
||||
String suffix = matcher.group("suffix");
|
||||
char suffixFirstChar = suffix.charAt(0);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
appendDigitByDigit(builder, String.valueOf(year));
|
||||
builder.append('週');
|
||||
appendDigitByDigit(builder, String.valueOf(week));
|
||||
|
||||
if (suffix.length() == 1
|
||||
&& suffixFirstChar >= 'a' && (suffixFirstChar - 'a') < TIAN_GAN.length)
|
||||
builder.append(TIAN_GAN[suffixFirstChar - 'a']);
|
||||
else
|
||||
builder.append(suffix);
|
||||
|
||||
yield builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
yield version;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return gameVersion.toString();
|
||||
|
||||
@@ -808,6 +808,8 @@ launch.advice.forge37_0_60=Forge versions prior to 37.0.60 are not compatible wi
|
||||
launch.advice.java8_1_13=Minecraft 1.13 and later can only be run on Java 8 or later. Please use Java 8 or later versions.
|
||||
launch.advice.java8_51_1_13=Minecraft 1.13 may crash on Java 8 versions prior to 1.8.0_51. Please install the latest Java 8 version.
|
||||
launch.advice.java9=You cannot launch Minecraft 1.12 or earlier with Java 9 or later. Please use Java 8 instead.
|
||||
launch.advice.lwjgl_3_4_1=The current game version has a known issue that may cause stuttering in the game.\nHMCL can automatically optimize the game performance (using a Java Agent).\nDo you allow HMCL to automatically optimize the game?\nIf you encounter issues, you can disable the "Allow HMCL to modify the game" option in "Settings → General".
|
||||
launch.advice.lwjgl_3_4_1.title=Allow HMCL to automatically optimize the game?
|
||||
launch.advice.modded_java=Some mods may not be compatible with newer Java versions. It is recommended to use Java %1$s to launch Minecraft %2$s.
|
||||
launch.advice.modlauncher8=The Forge version you are using is not compatible with the current Java version. Please try updating Forge.
|
||||
launch.advice.newer_java=You are using an older Java version to launch the game. It is recommended to update to Java 8, otherwise some mods may cause the game to crash.
|
||||
@@ -1416,6 +1418,8 @@ settings.game.working_directory.hint=Enable the "Isolated" option in "Working Di
|
||||
settings.icon=Icon
|
||||
|
||||
settings.launcher=Launcher Settings
|
||||
settings.launcher.allow_auto_agent=Allow HMCL to modify the game
|
||||
settings.launcher.allow_auto_agent.subtitle=Allow HMCL to modify the game by attaching a Java Agent to improve the gaming experience.
|
||||
settings.launcher.appearance=Appearance
|
||||
settings.launcher.brightness=Theme Mode
|
||||
settings.launcher.brightness.auto=Follow System Settings
|
||||
|
||||
@@ -579,6 +579,8 @@ launch.advice.forge37_0_60=鍛三七點〇點五九與舊者弗兼爪哇十七
|
||||
launch.advice.java8_1_13=礦藝一點一三以晉但行於爪哇八與晉者。宜行以爪哇八與晉者。
|
||||
launch.advice.java8_51_1_13=爪哇之前一點八點〇之五一者或崩礦藝一點一三。宜新爪哇於一點八點〇之五一以晉,然後復啟。
|
||||
launch.advice.java9=礦藝之前一點一三而有改囊者弗見兼於爪哇九與晉者。宜啟以爪哇八。
|
||||
launch.advice.lwjgl_3_4_1=戲之是版有已知之謬,行戲之時或致頓滯。\nHMCL 可假爪哇 Agent 自優其戲,以弭是患。君其許 HMCL 自優其戲乎?\n誠有謬,可至於「置設 → 貫用」,廢「許改戲」之項。
|
||||
launch.advice.lwjgl_3_4_1.title=君其許 HMCL 自優其戲乎?
|
||||
launch.advice.modded_java=改囊或弗見兼於爪哇之新者。宜以爪哇 %s 啟礦藝 %s。
|
||||
launch.advice.modlauncher8=鍛版之所行弗兼於爪哇之所行。宜新鍛。
|
||||
launch.advice.newer_java=余識君之啟戲以舊爪哇也,蓋改囊或是以崩戲也。宜新爪哇於八,然後復啟。
|
||||
@@ -975,7 +977,10 @@ repositories.chooser=闕 JavaFX。HMCL 須之以行。\n擊「善」而引 JavaF
|
||||
repositories.chooser.title=擇 JavaFX 之源
|
||||
|
||||
resourcepack=資囊
|
||||
resourcepack.add=增資囊
|
||||
resourcepack.download=引資囊
|
||||
resourcepack.download.title=引資囊 - %1s
|
||||
resourcepack.manage=司資囊
|
||||
|
||||
reveal.in_file_manager=覽於理案臺
|
||||
|
||||
@@ -1123,6 +1128,8 @@ settings.game.working_directory.hint=夫于「運徑」擇「例獨」者,可
|
||||
settings.icon=戲徵
|
||||
|
||||
settings.launcher=啟者置設
|
||||
settings.launcher.allow_auto_agent=許改戲
|
||||
settings.launcher.allow_auto_agent.subtitle=許 HMCL 假附加爪哇 Agent 以改戲,而優其戲感。
|
||||
settings.launcher.appearance=外觀
|
||||
settings.launcher.common_path.tooltip=啟者置戲資與府庫於是。倘戲有成案,則弗取公庫之案。
|
||||
settings.launcher.debug=勘誤
|
||||
@@ -1193,6 +1200,8 @@ sponsor.hmcl=Hello Minecraft! Launcher,乃一免費,自由,開源之礦藝
|
||||
system.architecture=大構
|
||||
system.operating_system=械網
|
||||
|
||||
terracotta=眾戲
|
||||
|
||||
unofficial.hint=子方用非官築之 HMCL。余無能證其安,請君自辨。
|
||||
|
||||
update=啟者迭更
|
||||
@@ -1210,6 +1219,8 @@ update.channel.nightly.hint=君所用之 HMCL 乃預版也。預版之更迭常
|
||||
update.channel.nightly.title=預版告
|
||||
update.channel.stable=定版
|
||||
update.checking=甫察其新
|
||||
update.disable_auto_show_update_dialog=弗自顯迭更窗
|
||||
update.disable_auto_show_update_dialog.subtitle=啟此,HMCL 將弗自顯迭更窗。
|
||||
update.failed=迭更未成
|
||||
update.found=尋得新者
|
||||
update.newest_version=至新:%s
|
||||
@@ -1219,6 +1230,8 @@ update.note=开發版與預版,虽增功、修阙,然亦恐生他患。
|
||||
update.latest=當版至新
|
||||
update.no_browser=無啟瀏覽器。址固鈔訖,君可自粘之以啟頁。
|
||||
update.tooltip=迭更
|
||||
update.preview=先覽 HMCL 之版
|
||||
update.preview.subtitle=啟此,君可先得 HMCL 之新,試之於未行。
|
||||
|
||||
version=戲
|
||||
version.name=戲例之名
|
||||
|
||||
@@ -612,6 +612,8 @@ launch.advice.forge37_0_60=Forge 37.0.59 及更低版本與 Java 17 不相容。
|
||||
launch.advice.java8_1_13=Minecraft 1.13 及更高版本僅支援 Java 8 或更高版本。請使用 Java 8 或最新版本。
|
||||
launch.advice.java8_51_1_13=低於 1.8.0_51 的 Java 版本可能會導致 Minecraft 1.13 崩潰。建議你到 https://java.com 安裝最新版的 Java 8。
|
||||
launch.advice.java9=低於 (包含) 1.13 的有安裝模組的 Minecraft 版本不支援 Java 9 或更高版本。請使用 Java 8。
|
||||
launch.advice.lwjgl_3_4_1=當前遊戲版本存在已知問題,可能在遊戲中發生卡頓。\nHMCL 可以 (透過 Java Agent) 自動最佳化遊戲解決此問題。是否允許 HMCL 自動最佳化遊戲?\n如遇到問題,你可以在「設定 → 一般」中關閉「允許 HMCL 修改遊戲」選項。
|
||||
launch.advice.lwjgl_3_4_1.title=是否允許 HMCL 自動最佳化遊戲?
|
||||
launch.advice.modded_java=部分模組可能與高版本 Java 不相容。建議使用 Java %s 啟動 Minecraft %s。
|
||||
launch.advice.modlauncher8=你所使用的 Forge 版本與目前使用的 Java 不相容。請更新 Forge。
|
||||
launch.advice.newer_java=偵測到你正在使用舊版本 Java 啟動遊戲,這可能導致部分模組引發遊戲崩潰。建議更新至 Java 8 後再次啟動。
|
||||
@@ -1201,6 +1203,8 @@ settings.game.working_directory.hint=在「執行路徑」選項中選取「各
|
||||
settings.icon=遊戲圖示
|
||||
|
||||
settings.launcher=啟動器設定
|
||||
settings.launcher.allow_auto_agent=允許 HMCL 修改遊戲
|
||||
settings.launcher.allow_auto_agent.subtitle=允許 HMCL 透過附加 Java Agent 修改遊戲以改善遊戲體驗。
|
||||
settings.launcher.appearance=外觀
|
||||
settings.launcher.brightness=主題模式
|
||||
settings.launcher.brightness.auto=跟隨系統設定
|
||||
|
||||
@@ -617,6 +617,8 @@ launch.advice.forge37_0_60=Forge 37.0.59 及更低版本与 Java 17 不兼容。
|
||||
launch.advice.java8_1_13=Minecraft 1.13 及更高版本只能在 Java 8 或更高版本上运行。请使用 Java 8 或最新版本。
|
||||
launch.advice.java8_51_1_13=低于 1.8.0_51 的 Java 版本可能会导致 Minecraft 1.13 崩溃。建议更新 Java 至 1.8.0_51 或更高版本后再次启动。
|
||||
launch.advice.java9=低于 1.13 的有安装模组的 Minecraft 版本与 Java 9 或更高版本不兼容。请使用 Java 8。
|
||||
launch.advice.lwjgl_3_4_1=当前游戏版本存在已知问题,可能在游戏中发生卡顿。\nHMCL 可以 (通过 Java Agent) 自动优化游戏解决此问题。是否允许 HMCL 自动优化游戏?\n如遇到问题,你可以在“设置 → 通用”中关闭“允许 HMCL 修改游戏”选项。
|
||||
launch.advice.lwjgl_3_4_1.title=是否允许 HMCL 自动优化游戏?
|
||||
launch.advice.modded_java=部分模组可能与高版本 Java 不兼容。建议使用 Java %s 启动 Minecraft %s。
|
||||
launch.advice.modlauncher8=你所使用的 Forge 版本与当前使用的 Java 不兼容。请更新 Forge。
|
||||
launch.advice.newer_java=检测到你正在使用旧版本 Java 启动游戏,这可能导致部分模组引发游戏崩溃。建议更新至 Java 8 后再次启动。
|
||||
@@ -1206,6 +1208,8 @@ settings.game.working_directory.hint=在“版本隔离”中选择“各实例
|
||||
settings.icon=游戏图标
|
||||
|
||||
settings.launcher=启动器设置
|
||||
settings.launcher.allow_auto_agent=允许 HMCL 修改游戏
|
||||
settings.launcher.allow_auto_agent.subtitle=允许 HMCL 通过附加 Java Agent 修改游戏以改善游戏体验。
|
||||
settings.launcher.appearance=外观
|
||||
settings.launcher.brightness=主题模式
|
||||
settings.launcher.brightness.auto=跟随系统设置
|
||||
|
||||
+28
-12
@@ -4,6 +4,7 @@ import org.jackhuang.hmcl.download.DownloadProvider;
|
||||
import org.jackhuang.hmcl.download.VersionList;
|
||||
import org.jackhuang.hmcl.task.GetTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.gson.JsonSerializable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -58,16 +59,38 @@ public final class NeoForgeOfficialVersionList extends VersionList<NeoForgeRemot
|
||||
String mcVersion;
|
||||
|
||||
try {
|
||||
int si1 = version.indexOf('.'), si2 = version.indexOf('.', version.indexOf('.') + 1);
|
||||
int si1 = version.indexOf('.');
|
||||
int si2 = version.indexOf('.', si1 + 1);
|
||||
if (si1 < 0 || si2 < 0) {
|
||||
LOG.warning("Unsupported NeoForge version: " + version);
|
||||
continue;
|
||||
}
|
||||
|
||||
int majorVersion = Integer.parseInt(version.substring(0, si1));
|
||||
if (majorVersion == 0) { // Snapshot version.
|
||||
mcVersion = version.substring(si1 + 1, si2);
|
||||
} else {
|
||||
String ver = version.substring(0, Integer.parseInt(version.substring(si1 + 1, si2)) == 0 ? si1 : si2);
|
||||
if (majorVersion >= 26) {
|
||||
int si3 = version.indexOf('.', si2 + 1);
|
||||
|
||||
if (si3 < 0) {
|
||||
LOG.warning("Unsupported NeoForge version: " + version);
|
||||
continue;
|
||||
}
|
||||
|
||||
String ver = Integer.parseInt(version.substring(si2 + 1, si3)) == 0
|
||||
? version.substring(0, si2)
|
||||
: version.substring(0, si3);
|
||||
|
||||
int separator = version.indexOf('+');
|
||||
mcVersion = separator < 0 ? ver : ver + "-" + version.substring(separator + 1);
|
||||
if (separator < 0)
|
||||
mcVersion = ver;
|
||||
else
|
||||
mcVersion = ver + "-" + version.substring(separator + 1);
|
||||
} else {
|
||||
String ver = Integer.parseInt(version.substring(si1 + 1, si2)) == 0
|
||||
? version.substring(0, si1)
|
||||
: version.substring(0, si2);
|
||||
mcVersion = "1." + ver;
|
||||
}
|
||||
}
|
||||
@@ -89,14 +112,7 @@ public final class NeoForgeOfficialVersionList extends VersionList<NeoForgeRemot
|
||||
});
|
||||
}
|
||||
|
||||
private static final class OfficialAPIResult {
|
||||
private final boolean isSnapshot;
|
||||
|
||||
private final List<String> versions;
|
||||
|
||||
public OfficialAPIResult(boolean isSnapshot, List<String> versions) {
|
||||
this.isSnapshot = isSnapshot;
|
||||
this.versions = versions;
|
||||
}
|
||||
@JsonSerializable
|
||||
private record OfficialAPIResult(boolean isSnapshot, List<String> versions) {
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ public record GameJavaVersion(String component, int majorVersion) {
|
||||
public static final GameJavaVersion JAVA_16 = new GameJavaVersion("java-runtime-alpha", 16);
|
||||
public static final GameJavaVersion JAVA_8 = new GameJavaVersion("jre-legacy", 8);
|
||||
|
||||
public static final GameJavaVersion LATEST = JAVA_21;
|
||||
public static final GameJavaVersion LATEST = JAVA_25;
|
||||
|
||||
public static GameJavaVersion getMinimumJavaVersion(GameVersionNumber gameVersion) {
|
||||
if (gameVersion.compareTo("26.1") >= 0)
|
||||
|
||||
@@ -268,18 +268,26 @@ public abstract sealed class GameVersionNumber implements Comparable<GameVersion
|
||||
}
|
||||
|
||||
public static final class Release extends GameVersionNumber {
|
||||
private static final int MINIMUM_YEAR_MAJOR_VERSION = 25;
|
||||
private static final int MINIMUM_YEAR_MAJOR_VERSION = 26;
|
||||
|
||||
public enum ReleaseType {
|
||||
UNKNOWN(""),
|
||||
SNAPSHOT("-snapshot-"),
|
||||
PRE_RELEASE("-pre"),
|
||||
RELEASE_CANDIDATE("-rc"),
|
||||
PRE_RELEASE("-pre", "-pre-"),
|
||||
RELEASE_CANDIDATE("-rc", "-rc-"),
|
||||
GA("");
|
||||
private final String infix;
|
||||
|
||||
private final String legacyInfix;
|
||||
private final String newInfix;
|
||||
|
||||
ReleaseType(String infix) {
|
||||
this.infix = infix;
|
||||
this.legacyInfix = infix;
|
||||
this.newInfix = infix;
|
||||
}
|
||||
|
||||
ReleaseType(String legacyInfix, String newInfix) {
|
||||
this.legacyInfix = legacyInfix;
|
||||
this.newInfix = newInfix;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,6 +325,8 @@ public abstract sealed class GameVersionNumber implements Comparable<GameVersion
|
||||
|
||||
String suffix = matcher.group("suffix");
|
||||
|
||||
boolean isLegacyRelease = major == 1;
|
||||
|
||||
ReleaseType releaseType;
|
||||
VersionNumber eaVersion;
|
||||
Additional additional = Additional.NONE;
|
||||
@@ -342,10 +352,15 @@ public abstract sealed class GameVersionNumber implements Comparable<GameVersion
|
||||
releaseType = ReleaseType.SNAPSHOT;
|
||||
eaVersion = VersionNumber.asVersion(suffix.substring(" Snapshot ".length()));
|
||||
} else if (suffix.startsWith("-pre-")) {
|
||||
needNormalize = true;
|
||||
if (isLegacyRelease) {
|
||||
needNormalize = true;
|
||||
}
|
||||
releaseType = ReleaseType.PRE_RELEASE;
|
||||
eaVersion = VersionNumber.asVersion(suffix.substring("-pre-".length()));
|
||||
} else if (suffix.startsWith("-pre")) {
|
||||
if (!isLegacyRelease) {
|
||||
needNormalize = true;
|
||||
}
|
||||
releaseType = ReleaseType.PRE_RELEASE;
|
||||
eaVersion = VersionNumber.asVersion(suffix.substring("-pre".length()));
|
||||
} else if (suffix.startsWith(" Pre-Release ")) {
|
||||
@@ -358,10 +373,15 @@ public abstract sealed class GameVersionNumber implements Comparable<GameVersion
|
||||
releaseType = ReleaseType.PRE_RELEASE;
|
||||
eaVersion = VersionNumber.asVersion(suffix.substring(" Pre-release ".length()));
|
||||
} else if (suffix.startsWith("-rc-")) {
|
||||
needNormalize = true;
|
||||
if (isLegacyRelease) {
|
||||
needNormalize = true;
|
||||
}
|
||||
releaseType = ReleaseType.RELEASE_CANDIDATE;
|
||||
eaVersion = VersionNumber.asVersion(suffix.substring("-rc-".length()));
|
||||
} else if (suffix.startsWith("-rc")) {
|
||||
if (!isLegacyRelease) {
|
||||
needNormalize = true;
|
||||
}
|
||||
releaseType = ReleaseType.RELEASE_CANDIDATE;
|
||||
eaVersion = VersionNumber.asVersion(suffix.substring("-rc".length()));
|
||||
} else if (suffix.startsWith(" Release Candidate ")) {
|
||||
@@ -377,7 +397,7 @@ public abstract sealed class GameVersionNumber implements Comparable<GameVersion
|
||||
StringBuilder builder = new StringBuilder(value.length());
|
||||
builder.append(matcher.group("prefix"));
|
||||
if (releaseType != ReleaseType.GA) {
|
||||
builder.append(releaseType.infix);
|
||||
builder.append(isLegacyRelease ? releaseType.legacyInfix : releaseType.newInfix);
|
||||
builder.append(eaVersion);
|
||||
}
|
||||
builder.append(additional.suffix);
|
||||
@@ -607,6 +627,10 @@ public abstract sealed class GameVersionNumber implements Comparable<GameVersion
|
||||
throw new IllegalArgumentException(value);
|
||||
}
|
||||
|
||||
if (year >= Release.MINIMUM_YEAR_MAJOR_VERSION) {
|
||||
throw new IllegalArgumentException(value);
|
||||
}
|
||||
|
||||
char suffix = value.charAt(5);
|
||||
if (suffix < 'a' || suffix > 'z')
|
||||
throw new IllegalArgumentException(value);
|
||||
|
||||
@@ -895,3 +895,23 @@
|
||||
1.21.11-rc3_unobfuscated
|
||||
1.21.11
|
||||
1.21.11_unobfuscated
|
||||
26.1-snapshot-1
|
||||
26.1-snapshot-2
|
||||
26.1-snapshot-3
|
||||
26.1-snapshot-4
|
||||
26.1-snapshot-5
|
||||
26.1-snapshot-6
|
||||
26.1-snapshot-7
|
||||
26.1-snapshot-8
|
||||
26.1-snapshot-9
|
||||
26.1-snapshot-10
|
||||
26.1-snapshot-11
|
||||
26.1-pre-1
|
||||
26.1-pre-2
|
||||
26.1-pre-3
|
||||
26.1-rc-1
|
||||
26.1-rc-2
|
||||
26.1
|
||||
26.1.1-rc-1
|
||||
26.1.1
|
||||
26w14a
|
||||
+7
-4
@@ -376,10 +376,11 @@ public final class GameVersionNumberTest {
|
||||
"1.21.11-pre1_unobfuscated",
|
||||
"1.21.11-pre2",
|
||||
"1.21.11-pre2_unobfuscated",
|
||||
"99w99a",
|
||||
"26.1-snapshot-1",
|
||||
"26.1-snapshot-2",
|
||||
"26.1",
|
||||
"26.1.1",
|
||||
"26w14a",
|
||||
"26.2-snapshot-1",
|
||||
"26.2-snapshot-2",
|
||||
"26.2",
|
||||
@@ -432,14 +433,13 @@ public final class GameVersionNumberTest {
|
||||
assertNormalized(version, version);
|
||||
}
|
||||
|
||||
assertNormalized("26.1-snapshot-1", "26.1 Snapshot 1");
|
||||
assertNormalized("1.21.11-pre3", "1.21.11-pre-3");
|
||||
assertNormalized("1.21.11-pre3", "1.21.11 Pre-Release 3");
|
||||
assertNormalized("1.21.11-pre3_unobfuscated", "1.21.11 Pre-Release 3 Unobfuscated");
|
||||
assertNormalized("1.21.11-pre3_unobfuscated", "1.21.11-pre3 Unobfuscated");
|
||||
assertNormalized("26.1-pre1", "26.1-pre-1");
|
||||
assertNormalized("1.21.11-rc1", "1.21.11-rc-1");
|
||||
assertNormalized("1.21.11-rc1", "1.21.11 Release Candidate 1");
|
||||
assertNormalized("1.21.11-rc1_unobfuscated", "1.21.11 Release Candidate 1 Unobfuscated");
|
||||
assertNormalized("26.1-rc1", "26.1-rc-1");
|
||||
assertNormalized("1.14_combat-212796", "1.14.3 - Combat Test");
|
||||
assertNormalized("1.14_combat-0", "Combat Test 2");
|
||||
assertNormalized("1.14_combat-3", "Combat Test 3");
|
||||
@@ -463,6 +463,9 @@ public final class GameVersionNumberTest {
|
||||
assertNormalized("1.19_deep_dark_experimental_snapshot-1", "Deep Dark Experimental Snapshot 1");
|
||||
assertNormalized("20w14infinite", "20w14~");
|
||||
assertNormalized("22w13oneBlockAtATime", "22w13oneblockatatime");
|
||||
assertNormalized("26.1-snapshot-1", "26.1 Snapshot 1");
|
||||
assertNormalized("26.1-rc-1", "26.1-rc1");
|
||||
assertNormalized("26.1-pre-1", "26.1-pre1");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -17,6 +17,7 @@ jna = "5.18.1"
|
||||
pci-ids = "0.4.0"
|
||||
java-info = "1.0"
|
||||
authlib-injector = "1.2.7"
|
||||
lwjgl-unsafe-agent = "2.0"
|
||||
monet-fx = "0.4.0"
|
||||
terracotta = "0.4.2"
|
||||
nayuki-qrcodegen = "1.8.0"
|
||||
@@ -49,6 +50,7 @@ jna-platform = { module = "net.java.dev.jna:jna-platform", version.ref = "jna" }
|
||||
pci-ids = { module = "org.glavo:pci-ids", version.ref = "pci-ids" }
|
||||
java-info = { module = "org.glavo:java-info", version.ref = "java-info" }
|
||||
authlib-injector = { module = "org.glavo.hmcl:authlib-injector", version.ref = "authlib-injector" }
|
||||
lwjgl-unsafe-agent = { module = "org.glavo:lwjgl-unsafe-agent", version.ref = "lwjgl-unsafe-agent" }
|
||||
monet-fx = { module = "org.glavo:MonetFX", version.ref = "monet-fx" }
|
||||
nayuki-qrcodegen = { module = "io.nayuki:qrcodegen", version.ref = "nayuki-qrcodegen" }
|
||||
|
||||
|
||||
Reference in new issue
Block a user