Compare commits

...
82 Commits
Author SHA1 Message Date
Glavo 8047775bf8 feat: add support for virtual GPU type in AboutPage (#7158) 2026-11-01 21:54:37 +08:00
Glavo 740d3c5d80 重构 TwoLineListItem (#7153) 2026-11-01 21:48:48 +08:00
Glavo 967c326219 允许修改没有 patches 的原版实例 (#7145) 2026-11-01 21:29:48 +08:00
快乐凤爪王 fdc3500cc4 style: 为 checkstyle 添加了 RegexpSingleline 规则 (#7156) 2026-11-01 21:25:13 +08:00
Glavo 2f17995955 更新关于页面“桌面环境”条目的图标 (#7157) 2026-11-01 21:22:43 +08:00
Glavo ef311560fd Enhance SHA-1 table and update task for version detection (#7155) 2026-11-01 21:10:33 +08:00
Glavo 440b42a8b7 优化关于页面运行环境信息的排版 (#7151) 2026-11-01 15:55:40 +08:00
Glavo 8b706466e7 feat: log process PID in Launcher (#7152) 2026-11-01 15:48:28 +08:00
快乐凤爪王 8e16127845 feat: 改进 GameListCell (#7144) 2026-10-31 21:56:29 +08:00
Glavo bdbf5773a8 调整自动内存分配算法 (#7134) 2026-10-31 13:59:32 +08:00
Glavo 1ca146c615 Bump mesa-loader-windows to 26.2.6 (#7132) 2026-10-30 21:28:12 +08:00
Glavo de8ae88ee4 改进 AVF 虚拟机内的硬件检测逻辑 (#7130) 2026-10-30 17:57:27 +08:00
Glavo ba62160c76 改进 GPU 类型推断逻辑 (#7124) 2026-10-30 02:05:12 +08:00
快乐凤爪王 8e7f36c681 fix: MicrosoftAccountLoginPane 在缺失 Client ID 时禁用二维码登录 (#7119) 2026-10-29 22:22:07 +08:00
快乐凤爪王 b08f3869cf fix: 关于页面的版权条目使用 LinePane (#7122) 2026-10-29 22:01:42 +08:00
Glavo f05647fc82 支持在使用 Panthor 驱动的环境探测 Mali GPU (#7115) 2026-10-29 16:01:59 +08:00
Glavo 67e9826309 改进 CPU 拓扑探测能力 (#7113) 2026-10-29 15:18:38 +08:00
Glavo f1c9b77df5 Refactor SystemInfo and improve hardware info caching and documentation (#7112) 2026-10-29 03:09:30 +08:00
Glavo c3abfcf1d9 更新 amdgpu.ids (#7111) 2026-10-29 02:37:36 +08:00
Glavo 6632a91426 优化 GPU 信息显示逻辑 (#7109) 2026-10-28 21:55:33 +08:00
Glavo ac378ad46a 预热设置页面时预加载游戏预设 (#7105) 2026-10-28 03:38:08 +08:00
Glavo 6bbb1d157c 简化 TabItem (#7106) 2026-10-28 03:19:15 +08:00
Glavo efa1012a1c 重构 TabHeader (#7104) 2026-10-28 02:26:08 +08:00
Glavo 5058c68be8 优化窗口动画性能 (#7103) 2026-10-28 00:52:29 +08:00
鱼前三百 3612f04657 docs: 修复 withRunAsync 文档错误 (#7095) 2026-10-27 22:25:55 +08:00
快乐凤爪王 a2d3bb3b42 chore: 抑制 Decorator 中未经检查的类型转换警告 (#7098) 2026-10-27 21:50:33 +08:00
Glavo d3efc81332 为侧边栏菜单项背景色添加渐变动画 (#7101) 2026-10-27 21:22:47 +08:00
Glavo 6b1799838f 重构 RipplerContainer (#7096) 2026-10-27 20:14:05 +08:00
Glavo 5ad4880182 支持使用 CurseForge CDN 访问 NeoForge 相关文件 (#7092) 2026-10-26 23:05:08 +08:00
Glavo a3781141fe 由 TransitionPane 提供节点预热能力 (#7090) 2026-10-26 21:30:43 +08:00
Glavo ed168e14d6 清理 Controllers (#7082) 2026-10-26 21:11:06 +08:00
Glavo ee81d7cc66 使用 SPDX 文件头声明版权与开源协议 (#7091) 2026-10-26 20:15:54 +08:00
Glavo 299077d1cb 恢复使用页面预热 (#7081) 2026-10-26 02:09:11 +08:00
nekoside 7448ea90b2 fix: handle odd-length UTF-16LE GPU registry values on Windows (#7080) 2026-10-26 02:00:05 +08:00
AlexYang ac578c044f chore: update avatar for yushijinhun and update a URL (#7078) 2026-10-25 21:34:53 +08:00
快乐凤爪王 fc68029adc feat: 帮助页面添加异常提示及刷新功能 (#7047) 2026-10-25 21:32:51 +08:00
Glavo f6a92c1806 过滤模组中文名中的 Emoji (#7077) 2026-10-25 20:55:54 +08:00
Glavo 58eb452e90 在播放 UI 动画前应用 UI 布局 (#7076) 2026-10-25 19:17:39 +08:00
Wulian233 fb8a96a170 优化账户页面「上传/编辑皮肤」按钮文案 (#7050)
Close #3633
2026-10-25 19:02:55 +08:00
快乐凤爪王 ced441a830 refactor: 提取 DownloadListCell (#7075) 2026-10-25 17:30:14 +08:00
Glavo c5693c3450 清理未使用的代码与资源 (#7074) 2026-10-25 16:59:13 +08:00
鱼前三百 bc27eda220 chore(event): 移除过时且远古的进程退出事件,并将下载速度事件与全局 EventBus 解耦 (#7063) 2026-10-25 16:40:47 +08:00
Matt Van Horn 0c40dcdeed fix: honor declared modern Java requirements on legacy Linux instances (#7073) 2026-10-25 16:39:11 +08:00
Glavo 4282147042 优化设备信息的检测与显示逻辑 (#7071) 2026-10-25 16:36:49 +08:00
Glavo 0874c98d21 Fix TLS security tests on JDKs that block compromised certificates (#7065) 2026-10-25 11:42:41 +08:00
ToobLac 0c3c7dd62a chore: Bump commonmark to 0.31.0 & Update deps.json (#7056) 2026-10-25 03:04:20 +08:00
Glavo f663e5568c 在关于页面显示用户环境信息 (#7040) 2026-10-24 21:32:25 +08:00
ToobLac b8c1738f96 perf(ui): MicrosoftAccountLoginPane 在缺失 client id 时直接禁用登录按钮并显示错误提示 (#7054) 2026-10-24 19:38:51 +08:00
Glavo 41c61645e7 Detect instance manifests among multiple JSON files (#7048) 2026-10-24 18:31:52 +08:00
ToobLac 9fc697751c chore(git): 补充 schematic git attr (#7053) 2026-10-24 18:21:30 +08:00
Glavo a4db0532b9 在 default_script.csv 和 sublanguages.csv 中记录数据来源 (#7049) 2026-10-24 14:14:24 +08:00
Minecraft269andMinecraft269 8954139b5e docs: update contributor count from 130 to 140 (#7043)
Co-authored-by: Minecraft269 <[email protected]>
2026-10-24 13:52:30 +08:00
Glavo b2f7e724e4 使用 IANA 时区地区映射表推断设备地区 (#7046) 2026-10-24 12:38:08 +08:00
Glavo 0d20910ea3 Block compromised eMudhra CA keys in application TLS validation (#7033) 2026-10-22 21:27:52 +08:00
Glavo 5c90299073 移除下载页面提示 (#7038) 2026-10-22 21:04:39 +08:00
Glavo fc66cbcf96 更新模组数据 (2026-10-22) (#7032) 2026-10-22 02:15:14 +08:00
Glavo e7b9a95df0 为非官方构建添加醒目标识 (#7028) 2026-10-21 21:24:41 +08:00
ToobLac acc9740fa9 perf(addon): 完善 AddonUpdatesPage (#7003) 2026-10-20 21:27:59 +08:00
鱼前三百 5789f82617 fix: 在重新检查更新的时候提示正在检查更新 (#7015)
fix: #7014
2026-10-20 21:25:24 +08:00
Glavo 8827fd06d8 优化地区检测逻辑 (#7020) 2026-10-20 18:06:54 +08:00
Glavo 583e004d71 在中国大陆地区禁用游戏下载功能 (#7017) 2026-10-20 16:37:22 +08:00
Glavo 63207affc6 更新配置文件 Json Schema (#7012) 2026-10-19 20:34:27 +08:00
Glavo 8b147bf20a Windows 平台自动使用 javaw.exe 启动游戏 (#7009) 2026-10-19 20:21:15 +08:00
鱼前三百 15754119d5 fix: 修复原生窗口透明标题栏重复绘制背景 (#7010)
fix #6959
2026-10-19 20:08:39 +08:00
快乐凤爪王 8119324a92 fix: JavaFX Alert 失败时回退到 Swing (#6918) 2026-10-18 21:15:34 +08:00
辞庐 c0ad7764b0 更新用户未购买 Minecraft 时的提示文本 (#6998) 2026-10-18 20:55:43 +08:00
辞庐 3ea054ae31 将 JFXSpinner 改为顺时针旋转 (#7000) 2026-10-18 20:52:20 +08:00
快乐凤爪王 d03ad38e24 fix: ModpackInfoPage 文件选择器关闭后不清空页面栈 (#6992) 2026-10-17 20:38:35 +08:00
快乐凤爪王 93eaee317c feat: 参考 VersionsPage 样式改进 AddonUpdatesPage (#6970) 2026-10-16 21:51:41 +08:00
ToobLac 68b3a9f076 enhance(i18n): 优化拖拽以安装本地整合包的文字提示 (#6893)
Fixes #6891
2026-10-16 21:47:09 +08:00
鱼前三百 c943e4c74f fix: 在模组/资源包文件操作失败时提示 (#6922)
fix #4314, fix #6396
2026-10-16 21:44:50 +08:00
Minecraft269 4dba96e635 chore: 在 Gitee 与 CNB Issue 模板中添加 GitHub Issue 入口 (#6967) 2026-10-16 21:19:32 +08:00
Glavo e521a1b91a Fix #6969: 修复第二次打开游戏下载页面时页面空白的问题 (#6988) 2026-10-16 21:16:18 +08:00
gunngz a7e0fe7499 Fix indeterminate checkbox rendering in modpack export wizard (#6989)
Fixes #6929
2026-10-16 21:15:44 +08:00
鱼前三百andGlavo 4e2d5cac9e chore: 转换 TaskCancellationAction 为函数式接口 (#6991)
Co-authored-by: Glavo <[email protected]>
2026-10-16 20:49:23 +08:00
ToobLac 452d030817 refactor(addon): Make LocalAddonFile implement Comparable (#6984) 2026-10-15 20:33:13 +08:00
ToobLac da9ec2c1e1 chore: sync translations (#6983) 2026-10-15 20:31:07 +08:00
Glavo 4ebbb400ab 重构 ModTranslations (#6987) 2026-10-15 20:29:12 +08:00
Glavo 0cfc2471a0 使用 BellSoft Full JDK 运行 GitHub Action (#6978) 2026-10-13 21:13:42 +08:00
Glavo 413a7291ec 修复 DateRangeDialog 调用 JavaFX 21 API 的问题 (#6979) 2026-10-13 20:55:15 +08:00
鱼前三百 e4893a6df9 feat: 缓存 MicrosoftAccount 的 CompleteGameProfile (#6975)
Fix #5055
2026-10-13 20:16:44 +08:00
ToobLac bb16a0b6c0 fix(addon): AddonUpdatePage 显示测试版本复选框无效 (#6976)
Fixes #6974
2026-10-13 20:16:03 +08:00
992 changed files with 49810 additions and 52387 deletions

No files matched your search

+3
View File
@@ -6,3 +6,6 @@ contact_links:
- name: Discord 服务器
url: https://discord.gg/jVvC7HfM6U
about: Hello Minecraft! Launcher 的官方 Discord 服务器。
- name: GitHub Issue
url: https://github.com/HMCL-dev/HMCL/issues/new/choose
about: 本仓库为镜像仓库,Bug 报告与功能请求请在 GitHub 上提交。
+3
View File
@@ -59,6 +59,9 @@ Jenkinsfile text eol=lf
# Minecraft schematic
*.litematic binary
*.nbt binary
*.schem binary
*.schematic binary
# Compiled / intermediate build artefacts
*.bin binary
+3
View File
@@ -3,3 +3,6 @@ contact_links:
- name: QQ 群
url: https://docs.hmcl.net/groups.html
about: Hello Minecraft! Launcher 的官方 QQ 交流群。
- name: GitHub Issue
url: https://github.com/HMCL-dev/HMCL/issues/new/choose
about: 本仓库为镜像仓库,Bug 报告与功能请求请在 GitHub 上提交。
+2 -2
View File
@@ -14,9 +14,9 @@ jobs:
steps:
- uses: actions/checkout@v6
- name: Set up JDK 17
uses: actions/setup-java@v5
uses: actions/setup-java@v6
with:
distribution: 'zulu'
distribution: 'liberica'
java-version: '17'
java-package: 'jdk+fx'
- name: Setup Gradle
+4 -4
View File
@@ -1,6 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Hello Minecraft! Launcher&#10;Copyright (C) &amp;#36;today.year huangyuhui &lt;[email protected]&gt; and contributors&#10;&#10;This program is free software: you can redistribute it and/or modify&#10;it under the terms of the GNU General Public License as published by&#10;the Free Software Foundation, either version 3 of the License, or&#10;(at your option) any later version.&#10;&#10;This program is distributed in the hope that it will be useful,&#10;but WITHOUT ANY WARRANTY; without even the implied warranty of&#10;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the&#10;GNU General Public License for more details.&#10;&#10;You should have received a copy of the GNU General Public License&#10;along with this program. If not, see &lt;https://www.gnu.org/licenses/&gt;." />
<option name="myName" value="HMCL" />
</copyright>
<copyright>
<option name="notice" value="SPDX-FileCopyrightText: Copyright (C) &amp;#36;today.year The HMCL Authors&#10;SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL" />
<option name="myName" value="HMCL" />
</copyright>
</component>
+1
View File
@@ -3,6 +3,7 @@
<LanguageOptions name="JAVA">
<option name="fileTypeOverride" value="3" />
<option name="addBlankAfter" value="false" />
<option name="block" value="false" />
</LanguageOptions>
</settings>
</component>
+48 -41
View File
@@ -1,4 +1,6 @@
import org.jackhuang.hmcl.gradle.TerracottaConfigUpgradeTask
import org.jackhuang.hmcl.gradle.addon.FormatJsonFile
import org.jackhuang.hmcl.gradle.addon.UpdateAddonProjectInfos
import org.jackhuang.hmcl.gradle.ci.GitHubActionUtils
import org.jackhuang.hmcl.gradle.ci.JenkinsUtils
import org.jackhuang.hmcl.gradle.l10n.CheckTranslations
@@ -6,10 +8,10 @@ import org.jackhuang.hmcl.gradle.l10n.CreateLanguageList
import org.jackhuang.hmcl.gradle.l10n.CreateLocaleNamesResourceBundle
import org.jackhuang.hmcl.gradle.l10n.SyncTranslations
import org.jackhuang.hmcl.gradle.l10n.UpsideDownTranslate
import org.jackhuang.hmcl.gradle.mod.ParseModDataTask
import org.jackhuang.hmcl.gradle.pack.CreateDeb
import org.jackhuang.hmcl.gradle.pack.ReleaseType
import org.jackhuang.hmcl.gradle.utils.PropertiesUtils
import org.jackhuang.hmcl.gradle.utils.OfficialBuildValueSource
import java.net.URI
import java.nio.file.FileSystems
import java.nio.file.Files
@@ -154,33 +156,28 @@ tasks.compileJava {
options.compilerArgs.addAll(addOpens.map { "--add-exports=$it=ALL-UNNAMED" })
}
val hmclProperties = buildList {
add("hmcl.version" to project.version.toString())
add("hmcl.add-opens" to addOpens.joinToString(" "))
System.getenv("GITHUB_SHA")?.let {
add("hmcl.version.hash" to it)
}
add("hmcl.version.type" to versionType)
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 createPropertiesFile = tasks.register<WriteProperties>("createPropertiesFile") {
destinationFile.set(layout.buildDirectory.file("hmcl.properties"))
encoding = "UTF-8"
val hmclPropertiesFile = layout.buildDirectory.file("hmcl.properties")
val createPropertiesFile = tasks.register("createPropertiesFile") {
outputs.file(hmclPropertiesFile)
hmclProperties.forEach { (k, v) -> inputs.property(k, v) }
doLast {
val targetFile = hmclPropertiesFile.get().asFile
targetFile.parentFile.mkdir()
targetFile.bufferedWriter().use {
for ((k, v) in hmclProperties) {
it.write("$k=$v\n")
}
}
}
property("hmcl.version", project.version.toString())
property("hmcl.add-opens", addOpens.joinToString(" "))
System.getenv("GITHUB_SHA")?.let { property("hmcl.version.hash", it) }
property("hmcl.version.type", versionType)
property("hmcl.microsoft.auth.id", microsoftAuthId)
property("hmcl.curseforge.apikey", curseForgeApiKey)
property("hmcl.authlib-injector.version", libs.authlib.injector.get().version!!)
property("hmcl.lwjgl-unsafe-agent.version", libs.lwjgl.unsafe.agent.get().version!!)
property("hmcl.official", providers.of(OfficialBuildValueSource::class) {
parameters.publicKeyFile.set(layout.projectDirectory.file("src/main/resources/assets/hmcl_signature_publickey.der"))
parameters.privateKeyLocation.set(providers.environmentVariable("HMCL_SIGNATURE_KEY"))
// Pin the official public key independently of the replaceable resource file.
// Under HMCL’s license agreement, you **MUST** change the software name or the version number in
// a reasonable way to distinguish it from the original version.
// You may modify this hash if and only if you have changed the software name or version number
// in accordance with the license requirements.
parameters.expectedSha256.set("36aadcfde8626b9d4c7a74facb3fdfda47e703c205a673fbe6a56b1d419f8b8e")
})
}
tasks.jar {
@@ -214,7 +211,7 @@ tasks.shadowJar {
}
manifest.attributes(
"Created-By" to "Copyright(c) 2013-2025 huangyuhui.",
"Created-By" to "Copyright(c) 2013-2026 The HMCL Authors",
"Implementation-Version" to project.version.toString(),
"Main-Class" to "org.jackhuang.hmcl.Main",
"Multi-Release" to "true",
@@ -236,13 +233,12 @@ tasks.shadowJar {
}
tasks.processResources {
dependsOn(createPropertiesFile)
dependsOn(upsideDownTranslate)
dependsOn(createLocaleNamesResourceBundle)
dependsOn(createLanguageList)
into("assets/") {
from(hmclPropertiesFile)
from(createPropertiesFile.flatMap { it.destinationFile })
from(embedResources)
}
@@ -462,21 +458,32 @@ val createLanguageList = tasks.register<CreateLanguageList>("createLanguageList"
outputFile.set(generatedDir.map { it.file("languages.json") })
}
val createLocaleNamesResourceBundle = tasks.register<CreateLocaleNamesResourceBundle>("createLocaleNamesResourceBundle") {
dependsOn(createLanguageList)
val createLocaleNamesResourceBundle =
tasks.register<CreateLocaleNamesResourceBundle>("createLocaleNamesResourceBundle") {
dependsOn(createLanguageList)
languagesFile.set(createLanguageList.flatMap { it.outputFile })
outputDirectory.set(generatedDir.map { it.dir("generated/LocaleNames") })
}
languagesFile.set(createLanguageList.flatMap { it.outputFile })
outputDirectory.set(generatedDir.map { it.dir("generated/LocaleNames") })
}
// mcmod data
tasks.register<ParseModDataTask>("parseModData") {
inputFile.set(layout.projectDirectory.file("mod.json"))
outputFile.set(layout.projectDirectory.file("src/main/resources/assets/mod_data.txt"))
tasks.register<FormatJsonFile>("formatModJson") {
file.set(layout.projectDirectory.file("mod.json"))
}
tasks.register<ParseModDataTask>("parseModPackData") {
inputFile.set(layout.projectDirectory.file("modpack.json"))
outputFile.set(layout.projectDirectory.file("src/main/resources/assets/modpack_data.txt"))
tasks.register<FormatJsonFile>("formatModpackJson") {
file.set(layout.projectDirectory.file("modpack.json"))
}
tasks.register<UpdateAddonProjectInfos>("updateModProjectInfos") {
inputFile.set(layout.projectDirectory.file("mod.json"))
outputFile.set(layout.projectDirectory.file("src/main/resources/assets/addon/mod.csv"))
projectType.set(UpdateAddonProjectInfos.AddonProjectType.MOD)
}
tasks.register<UpdateAddonProjectInfos>("updateModpackProjectInfos") {
inputFile.set(layout.projectDirectory.file("modpack.json"))
outputFile.set(layout.projectDirectory.file("src/main/resources/assets/addon/modpack.csv"))
projectType.set(UpdateAddonProjectInfos.AddonProjectType.MODPACK)
}
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package com.jfoenix.controls;
import com.jfoenix.skins.JFXCheckBoxSkin;
@@ -30,6 +30,7 @@ import org.jackhuang.hmcl.ui.animation.AnimationUtils;
public class JFXCheckBoxSkin extends CheckBoxSkin {
private final StackPane box = new StackPane();
private final StackPane mark = new StackPane();
private final SVGPath markShape = new SVGPath();
private final double lineThick = 2.0;
private final double padding = 10.0;
private final JFXRippler rippler;
@@ -37,7 +38,11 @@ public class JFXCheckBoxSkin extends CheckBoxSkin {
private final double labelOffset = -8.0;
private final Transition transition;
private boolean invalid = true;
private JFXFillTransition select;
private boolean selected;
private boolean indeterminate;
/// The checkbox fill animation, initialized with the configured checked color.
private JFXFillTransition fillTransition;
public JFXCheckBoxSkin(JFXCheckBox control) {
super(control);
@@ -50,22 +55,17 @@ public class JFXCheckBoxSkin extends CheckBoxSkin {
boxContainer.getChildren().add(this.box);
boxContainer.setPadding(new Insets(this.padding));
this.rippler = new JFXRippler(boxContainer, RipplerMask.CIRCLE, RipplerPos.BACK);
this.updateRippleColor();
SVGPath shape = new SVGPath();
shape.setContent("M384 690l452-452 60 60-512 512-238-238 60-60z");
this.mark.setShape(shape);
this.mark.setMaxSize(15.0, 12.0);
this.mark.setStyle("-fx-background-color:-monet-on-primary; -fx-border-color:-monet-on-primary; -fx-border-width:2px;");
this.updateRippleColor(control.isSelected(), control.isIndeterminate());
this.mark.setShape(this.markShape);
this.updateMarkShape(true, false);
this.mark.setVisible(false);
this.mark.setScaleX(0.0);
this.mark.setScaleY(0.0);
boxContainer.getChildren().add(this.mark);
this.container.getChildren().add(this.rippler);
AnchorPane.setRightAnchor(this.rippler, this.labelOffset);
control.selectedProperty().addListener((o, oldVal, newVal) -> {
this.updateRippleColor();
this.playSelectAnimation(newVal);
});
this.registerChangeListener(control.selectedProperty(), ignored -> requestSelectionUpdate());
this.registerChangeListener(control.indeterminateProperty(), ignored -> requestSelectionUpdate());
ReadOnlyBooleanProperty focusVisibleProperty = FXUtils.focusVisibleProperty(control);
if (focusVisibleProperty == null)
@@ -82,37 +82,63 @@ public class JFXCheckBoxSkin extends CheckBoxSkin {
control.pressedProperty().addListener((o, oldVal, newVal) -> this.rippler.hideOverlay());
this.updateChildren();
this.registerChangeListener(control.checkedColorProperty(), ignored -> {
if (select != null) {
select.stop();
if (fillTransition != null) {
fillTransition.stop();
}
this.createFillTransition();
updateColors();
boolean selected = control.isSelected();
boolean indeterminate = control.isIndeterminate();
JFXFillTransition fillTransition = this.createFillTransition();
this.fillTransition = fillTransition;
fillTransition.jumpTo(selected || indeterminate ? fillTransition.getCycleDuration() : Duration.ZERO);
updateColors(selected, indeterminate);
});
this.registerChangeListener(control.unCheckedColorProperty(), ignored -> updateColors());
this.registerChangeListener(control.unCheckedColorProperty(), ignored -> updateColors(control.isSelected(), control.isIndeterminate()));
this.transition = new CheckBoxTransition();
this.createFillTransition();
this.fillTransition = this.createFillTransition();
}
private void updateRippleColor() {
var control = (JFXCheckBox) this.getSkinnable();
this.rippler.setRipplerFill(control.isSelected()
private void requestSelectionUpdate() {
this.invalid = true;
this.getSkinnable().requestLayout();
}
private void updateRippleColor(boolean selected, boolean indeterminate) {
JFXCheckBox control = (JFXCheckBox) this.getSkinnable();
this.rippler.setRipplerFill(selected || indeterminate
? control.getCheckedColor()
: control.getUnCheckedColor());
}
private void updateColors() {
private void updateColors(boolean selected, boolean indeterminate) {
var control = (JFXCheckBox) getSkinnable();
boolean isSelected = control.isSelected();
JFXNodeUtils.updateBackground(box.getBackground(), box, isSelected ? control.getCheckedColor() : Color.TRANSPARENT);
rippler.setRipplerFill(isSelected ? control.getCheckedColor() : control.getUnCheckedColor());
boolean marked = selected || indeterminate;
JFXNodeUtils.updateBackground(box.getBackground(), box, marked ? control.getCheckedColor() : Color.TRANSPARENT);
rippler.setRipplerFill(marked ? control.getCheckedColor() : control.getUnCheckedColor());
this.updateBorder(selected, indeterminate);
}
private void updateBorder(boolean selected, boolean indeterminate) {
JFXCheckBox control = (JFXCheckBox) this.getSkinnable();
final BorderStroke borderStroke = box.getBorder().getStrokes().get(0);
box.setBorder(new Border(new BorderStroke(
isSelected ? control.getCheckedColor() : Themes.getColorScheme().getOnSurfaceVariant(),
selected || indeterminate ? control.getCheckedColor() : Themes.getColorScheme().getOnSurfaceVariant(),
borderStroke.getTopStyle(),
borderStroke.getRadii(),
borderStroke.getWidths())));
}
private void updateMarkShape(boolean selected, boolean indeterminate) {
if (indeterminate) {
this.markShape.setContent("M1 0 H9 A1 1 0 0 1 10 1 A1 1 0 0 1 9 2 H1 A1 1 0 0 1 0 1 A1 1 0 0 1 1 0 Z");
this.mark.setMaxSize(10.0, 2.0);
this.mark.setStyle("-fx-background-color:-monet-on-primary;");
} else if (selected) {
this.markShape.setContent("M384 690l452-452 60 60-512 512-238-238 60-60z");
this.mark.setMaxSize(15.0, 12.0);
this.mark.setStyle("-fx-background-color:-monet-on-primary; -fx-border-color:-monet-on-primary; -fx-border-width:2px;");
}
}
protected void updateChildren() {
super.updateChildren();
if (this.container != null) {
@@ -140,9 +166,10 @@ public class JFXCheckBoxSkin extends CheckBoxSkin {
double xOffset = computeXOffset(w, labelWidth + boxWidth, checkBox.getAlignment().getHpos()) + x;
double yOffset = computeYOffset(h, maxHeight, checkBox.getAlignment().getVpos()) + x;
if (this.invalid) {
if (this.getSkinnable().isSelected()) {
this.playSelectAnimation(true);
}
boolean selected = checkBox.isSelected();
boolean indeterminate = checkBox.isIndeterminate();
this.updateRippleColor(selected, indeterminate);
this.playSelectAnimation(selected, indeterminate);
this.invalid = false;
}
@@ -169,47 +196,85 @@ public class JFXCheckBoxSkin extends CheckBoxSkin {
};
}
/// Animates a selection change, or applies it immediately when animations are disabled.
private void playSelectAnimation(boolean selection) {
JFXCheckBox control = (JFXCheckBox) this.getSkinnable();
private void playSelectAnimation(boolean selected, boolean indeterminate) {
boolean previousSelected = this.selected;
boolean previousIndeterminate = this.indeterminate;
this.selected = selected;
this.indeterminate = indeterminate;
boolean previousMarked = previousSelected || previousIndeterminate;
boolean marked = selected || indeterminate;
boolean sameVisualState = previousIndeterminate == indeterminate
&& (indeterminate || previousSelected == selected);
this.updateBorder(selected, indeterminate);
this.box.setBorder(new Border(new BorderStroke(
selection ? control.getCheckedColor() : Themes.getColorScheme().getOnSurfaceVariant(),
BorderStrokeStyle.SOLID,
new CornerRadii(2.0),
new BorderWidths(this.lineThick))));
if (sameVisualState) {
return;
}
this.invalid = false;
if (!AnimationUtils.isAnimationEnabled()) {
finishSelectionAnimation();
finishSelectionAnimation(selected, indeterminate);
return;
}
this.transition.setRate(selection ? 1.0 : -1.0);
this.select.setRate(selection ? 1.0 : -1.0);
if (previousMarked && marked) {
this.transition.stop();
this.transition.setOnFinished(null);
this.transition.jumpTo(this.transition.getCycleDuration());
this.transition.setRate(-1.0);
this.transition.setOnFinished(event -> {
this.transition.setOnFinished(null);
this.updateMarkShape(selected, indeterminate);
this.transition.jumpTo(Duration.ZERO);
this.transition.setRate(1.0);
this.transition.play();
});
this.transition.play();
return;
}
this.transition.setOnFinished(null);
if (marked) {
this.updateMarkShape(selected, indeterminate);
}
this.transition.setRate(marked ? 1.0 : -1.0);
this.fillTransition.setRate(marked ? 1.0 : -1.0);
this.fillTransition.play();
this.transition.play();
this.select.play();
}
/// Stops selection animations and immediately displays the checkbox's current selected state.
/// Stops selection animations and immediately displays the checkbox's current state.
///
/// The check mark, fill, and border are updated even if no animation is running.
/// This also suppresses the initial selection animation on the first layout.
/// The state indicator, fill, and border are updated even if no animation is running.
/// This also suppresses pending selection updates and the initial selection animation.
/// The skin must not have been disposed.
public void finishSelectionAnimation() {
transition.stop();
select.stop();
invalid = false;
boolean selected = getSkinnable().isSelected();
mark.setVisible(selected);
mark.setScaleX(selected ? 1.0 : 0.0);
mark.setScaleY(selected ? 1.0 : 0.0);
updateColors();
CheckBox checkBox = this.getSkinnable();
this.finishSelectionAnimation(checkBox.isSelected(), checkBox.isIndeterminate());
}
private void createFillTransition() {
this.select = new JFXFillTransition(Duration.millis(120.0), this.box, Color.TRANSPARENT,
private void finishSelectionAnimation(boolean selected, boolean indeterminate) {
this.selected = selected;
this.indeterminate = indeterminate;
boolean marked = selected || indeterminate;
transition.stop();
transition.setOnFinished(null);
transition.jumpTo(marked ? transition.getCycleDuration() : Duration.ZERO);
fillTransition.stop();
fillTransition.jumpTo(marked ? fillTransition.getCycleDuration() : Duration.ZERO);
invalid = false;
updateMarkShape(selected, indeterminate);
mark.setVisible(marked);
mark.setScaleX(marked ? 1.0 : 0.0);
mark.setScaleY(marked ? 1.0 : 0.0);
updateColors(selected, indeterminate);
}
private JFXFillTransition createFillTransition() {
JFXFillTransition fillTransition = new JFXFillTransition(Duration.millis(120.0), this.box, Color.TRANSPARENT,
(Color) ((JFXCheckBox) this.getSkinnable()).getCheckedColor());
this.select.setInterpolator(Interpolator.EASE_OUT);
fillTransition.setInterpolator(Interpolator.EASE_OUT);
return fillTransition;
}
private final class CheckBoxTransition extends CachedTransition {
@@ -133,7 +133,7 @@ public class JFXDatePickerContent extends VBox {
setText(null);
if (Objects.equals(oldItem, item) && oldEmpty == empty) return;
ripplerContainer.releaseRippleImmediately();
ripplerContainer.resetFeedback();
if (!empty && item != null) {
setGraphic(root);
@@ -69,7 +69,7 @@ public class JFXSpinnerSkin extends SkinBase<JFXSpinner> {
arc = new Arc();
arc.setManaged(false);
arc.setLength(180);
arc.setLength(-180);
arc.getStyleClass().setAll("arc");
arc.setFill(Color.TRANSPARENT);
arc.setStrokeWidth(DEFAULT_STROKE_WIDTH);
@@ -192,24 +192,24 @@ public class JFXSpinnerSkin extends SkinBase<JFXSpinner> {
private void addKeyFrames(List<KeyFrame> frames, double angle, double duration) {
frames.add(new KeyFrame(Duration.seconds(duration),
new KeyValue(arc.lengthProperty(), 5, Interpolator.LINEAR),
new KeyValue(arc.lengthProperty(), -5, Interpolator.LINEAR),
new KeyValue(arc.startAngleProperty(),
angle + 45 + startingAngle,
-(angle + 45 + startingAngle),
Interpolator.LINEAR)));
frames.add(new KeyFrame(Duration.seconds(duration + 0.4),
new KeyValue(arc.lengthProperty(), 250, Interpolator.LINEAR),
new KeyValue(arc.lengthProperty(), -250, Interpolator.LINEAR),
new KeyValue(arc.startAngleProperty(),
angle + 90 + startingAngle,
-(angle + 90 + startingAngle),
Interpolator.LINEAR)));
frames.add(new KeyFrame(Duration.seconds(duration + 0.7),
new KeyValue(arc.lengthProperty(), 250, Interpolator.LINEAR),
new KeyValue(arc.lengthProperty(), -250, Interpolator.LINEAR),
new KeyValue(arc.startAngleProperty(),
angle + 135 + startingAngle,
-(angle + 135 + startingAngle),
Interpolator.LINEAR)));
frames.add(new KeyFrame(Duration.seconds(duration + 1.1),
new KeyValue(arc.lengthProperty(), 5, Interpolator.LINEAR),
new KeyValue(arc.lengthProperty(), -5, Interpolator.LINEAR),
new KeyValue(arc.startAngleProperty(),
angle + 435 + startingAngle,
-(angle + 435 + startingAngle),
Interpolator.LINEAR)));
}
@@ -222,21 +222,21 @@ public class JFXSpinnerSkin extends SkinBase<JFXSpinner> {
addKeyFrames(keyFrames, 900, 2.8);
addKeyFrames(keyFrames, 1350, 4.2);
keyFrames.add(new KeyFrame(Duration.seconds(5.6),
new KeyValue(arc.lengthProperty(), 5, Interpolator.LINEAR),
new KeyValue(arc.lengthProperty(), -5, Interpolator.LINEAR),
new KeyValue(arc.startAngleProperty(),
1845 + startingAngle,
-(1845 + startingAngle),
Interpolator.LINEAR)));
timeline = new Timeline();
timeline.getKeyFrames().setAll(keyFrames);
} else {
final double arcLength = 250;
final double arcLength = -250;
timeline = new Timeline(
new KeyFrame(Duration.ZERO,
new KeyValue(arc.startAngleProperty(), 45 + startingAngle, Interpolator.LINEAR),
new KeyValue(arc.startAngleProperty(), -(45 + startingAngle), Interpolator.LINEAR),
new KeyValue(arc.lengthProperty(), arcLength, Interpolator.DISCRETE)),
new KeyFrame(Duration.seconds(1.2),
new KeyValue(arc.startAngleProperty(), 45 + 360 + startingAngle, Interpolator.LINEAR),
new KeyValue(arc.startAngleProperty(), -(45 + 360 + startingAngle), Interpolator.LINEAR),
new KeyValue(arc.lengthProperty(), arcLength, Interpolator.DISCRETE))
);
}
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2020 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl;
import org.jackhuang.hmcl.util.FileSaver;
@@ -23,6 +8,7 @@ import org.jackhuang.hmcl.util.SwingUtils;
import org.jackhuang.hmcl.java.JavaRuntime;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.JarUtils;
import org.jackhuang.hmcl.util.io.TLSSecurity;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import javax.swing.JOptionPane;
@@ -42,6 +28,7 @@ public final class EntryPoint {
private EntryPoint() {
}
/// Initializes TLS protection before downloading dependencies and starting the launcher.
public static void main(String[] args) {
System.getProperties().putIfAbsent("java.net.useSystemProxies", "true");
System.getProperties().putIfAbsent("javafx.autoproxy.disable", "true");
@@ -49,6 +36,7 @@ public final class EntryPoint {
createHMCLDirectories();
LOG.start(Metadata.HMCL_LOCAL_HOME.resolve("logs"));
TLSSecurity.install();
checkWine();
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2020 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl;
import com.sun.jna.Pointer;
@@ -297,6 +282,10 @@ public final class Launcher extends Application {
LOG.info("Processor Identifier: " + System.getenv("PROCESSOR_IDENTIFIER"));
}
LOG.info("System Architecture: " + Architecture.SYSTEM_ARCH.getDisplayName());
try {
LOG.info("Process PID: " + ProcessHandle.current().pid());
} catch (UnsupportedOperationException ignored) {
}
LOG.info("Native Encoding: " + OperatingSystem.NATIVE_CHARSET);
LOG.info("JNU Encoding: " + System.getProperty("sun.jnu.encoding"));
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2021 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2021 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl;
import org.jackhuang.hmcl.util.StringUtils;
@@ -42,14 +27,16 @@ public final class Metadata {
public static final String WINDOWS_APP_USER_MODEL_ID = "org.jackhuang.hmcl";
public static final String TITLE = NAME + " " + VERSION;
public static final String FULL_TITLE = FULL_NAME + " v" + VERSION;
/// Whether the build metadata identifies this launcher as an official build.
public static final boolean OFFICIAL_BUILD = Boolean.parseBoolean(JarUtils.getAttribute("hmcl.official", "false"));
public static final int MINIMUM_REQUIRED_JAVA_VERSION = 17;
public static final int MINIMUM_SUPPORTED_JAVA_VERSION = 17;
public static final int RECOMMENDED_JAVA_VERSION = 21;
public static final String PUBLISH_URL = "https://hmcl.huangyuhui.net";
public static final String DOWNLOAD_URL = PUBLISH_URL + "/download";
public static final String REPOSITORY_URL = "https://github.com/HMCL-dev/HMCL";
public static final String HMCL_UPDATE_URL = System.getProperty("hmcl.update_source.override", PUBLISH_URL + "/api/update_link");
public static final String MANUAL_UPDATE_URL = "https://github.com/HMCL-dev/HMCL/releases";
@@ -0,0 +1,478 @@
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.addon;
import org.jackhuang.hmcl.addon.mod.ModProjectInfo;
import org.jackhuang.hmcl.modpack.ModpackProjectInfo;
import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.StringUtils;
import org.jetbrains.annotations.NotNullByDefault;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.ref.SoftReference;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
/// @author Glavo
@NotNullByDefault
public abstract class AddonProjectInfoRegistry<I extends AddonProjectInfo> {
public static final AddonProjectInfoRegistry<ModProjectInfo> MOD = new AddonProjectInfoRegistry<>(
"/assets/addon/mod.csv",
32768
) {
@Override
protected int getFieldsCount() {
return MOD_IDS_INDEX + 1;
}
@Override
protected ModProjectInfo parseAddonProjectInfo(String[] fields) throws Exception {
return new ModProjectInfo(
Integer.parseInt(fields[MCMOD_ID_INDEX]),
fields[CURSEFORGE_ID_INDEX],
fields[MODRINTH_ID_INDEX],
fields[MAIN_NAME_INDEX],
fields[SUB_NAME_INDEX],
fields[ABBR_NAME_INDEX],
fields[MOD_IDS_INDEX]
);
}
};
/// Provides metadata for modpacks.
public static final AddonProjectInfoRegistry<ModpackProjectInfo> MODPACK = new AddonProjectInfoRegistry<>(
"/assets/addon/modpack.csv", 2048
) {
@Override
protected int getFieldsCount() {
return ABBR_NAME_INDEX + 1;
}
@Override
protected ModpackProjectInfo parseAddonProjectInfo(String[] fields) {
return new ModpackProjectInfo(Integer.parseInt(fields[MCMOD_ID_INDEX]),
fields[CURSEFORGE_ID_INDEX], fields[MODRINTH_ID_INDEX],
fields[MAIN_NAME_INDEX], fields[SUB_NAME_INDEX], fields[ABBR_NAME_INDEX]);
}
};
/// Returns the registry for the addon type, or `null` for null or unsupported types.
public static @Nullable AddonProjectInfoRegistry<?> getByAddonType(@Nullable RemoteAddon.Type type) {
if (type == null) return null;
return switch (type) {
case MOD -> MOD;
case MODPACK -> MODPACK;
default -> null;
};
}
protected static final int MCMOD_ID_INDEX = 0;
protected static final int CURSEFORGE_ID_INDEX = 1;
protected static final int MODRINTH_ID_INDEX = 2;
protected static final int MAIN_NAME_INDEX = 3;
protected static final int SUB_NAME_INDEX = 4;
protected static final int ABBR_NAME_INDEX = 5;
protected static final int MOD_IDS_INDEX = 6;
private final ReentrantLock lock = new ReentrantLock();
private final String assetsPath;
private final int initialCapacity;
private volatile @Nullable SoftReference<@Unmodifiable List<I>> infosRef;
/// Softly caches projects indexed by mod ID.
private volatile @Nullable SoftReference<@Unmodifiable Map<String, I>> modIdMapRef;
/// Softly caches projects indexed by cleaned secondary name.
private volatile @Nullable SoftReference<@Unmodifiable Map<String, I>> subnameMapRef;
/// Softly caches projects indexed by CurseForge identifier.
private volatile @Nullable SoftReference<@Unmodifiable Map<String, I>> curseForgeMapRef;
/// Softly caches searchable names in resource and field order.
private volatile @Nullable SoftReference<@Unmodifiable List<Pair<String, I>>> keywordsRef;
/// Creates a registry reading records from the given classpath resource.
AddonProjectInfoRegistry(String assetsPath, int initialCapacity) {
this.assetsPath = assetsPath;
this.initialCapacity = initialCapacity;
}
protected abstract int getFieldsCount();
protected abstract I parseAddonProjectInfo(String[] fields) throws Exception;
private @Unmodifiable List<I> loadInfos() throws IOException {
@Nullable InputStream inputStream = AddonProjectInfoRegistry.class.getResourceAsStream(assetsPath);
if (inputStream == null) {
return List.of();
}
try (var reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
ArrayList<I> infos = new ArrayList<>(initialCapacity);
@Unmodifiable List<I> result = Collections.unmodifiableList(infos);
int fieldsCount = getFieldsCount();
String[] fields = new String[fieldsCount];
@Nullable StringBuilder fieldBuilder = null;
@Nullable String line;
loop:
while ((line = reader.readLine()) != null) {
if (line.isEmpty() || line.startsWith("#")) {
continue;
}
int offset = 0;
for (int fieldIndex = 0; fieldIndex < fieldsCount; fieldIndex++) {
if (offset > line.length()) {
LOG.warning("Invalid line in " + assetsPath + ": " + line);
continue loop;
}
int end = line.indexOf(',', offset);
if (end < 0)
end = line.length();
String field;
if (offset == end) {
field = "";
} else {
int cursor = offset;
while (cursor < end) {
if (line.charAt(cursor) == '\\') {
break;
} else {
cursor++;
}
}
if (cursor == end) {
field = line.substring(offset, end);
} else {
if (fieldBuilder == null) {
fieldBuilder = new StringBuilder(32);
} else {
fieldBuilder.setLength(0);
}
fieldBuilder.append(line, offset, cursor);
while (cursor < end) {
char c = line.charAt(cursor);
if (c == '\\') {
if (cursor < end - 1) {
char next = line.charAt(cursor + 1);
switch (next) {
case '0' -> {
fieldBuilder.append('\0');
cursor += 2;
}
case 'n' -> {
fieldBuilder.append('\n');
cursor += 2;
}
case 'r' -> {
fieldBuilder.append('\r');
cursor += 2;
}
case 't' -> {
fieldBuilder.append('\t');
cursor += 2;
}
case '\\' -> {
fieldBuilder.append('\\');
cursor += 2;
}
case 'c' -> {
fieldBuilder.append(',');
cursor += 2;
}
case 'u' -> {
if (cursor < end - 5) {
try {
int codePoint = Integer.parseInt(line, cursor + 2, cursor + 6, 16);
fieldBuilder.append((char) codePoint);
cursor += 6;
} catch (NumberFormatException e) {
LOG.warning("Invalid line in " + assetsPath + ": " + line);
continue loop;
}
} else {
fieldBuilder.append(c);
cursor++;
}
}
default -> {
LOG.warning("Invalid line in " + assetsPath + ": " + line);
continue loop;
}
}
} else {
fieldBuilder.append(c);
cursor++;
}
} else {
fieldBuilder.append(c);
cursor++;
}
}
field = fieldBuilder.toString();
}
}
fields[fieldIndex] = field;
offset = end + 1;
}
try {
I info = parseAddonProjectInfo(fields);
info.setKeepAlive(result);
infos.add(info);
} catch (Exception e) {
LOG.warning("Failed to parse line in " + assetsPath + ": " + line, e);
}
}
infos.trimToSize();
return result;
}
}
/// Returns an unmodifiable index, rebuilding it after its soft reference is cleared.
/// Duplicate keys retain the first project in resource order.
private @Unmodifiable Map<String, I> getModIdMap() {
@Nullable SoftReference<@Unmodifiable Map<String, I>> reference = this.modIdMapRef;
@Unmodifiable Map<String, I> cached = reference != null ? reference.get() : null;
if (cached != null)
return cached;
lock.lock();
try {
reference = this.modIdMapRef;
cached = reference != null ? reference.get() : null;
if (cached != null)
return cached;
Map<String, I> map = new HashMap<>();
for (I info : getInfos()) {
if (info instanceof ModProjectInfo mod) {
for (String id : mod.getModIds()) {
if (!id.isEmpty())
map.putIfAbsent(id, info);
}
}
}
cached = Collections.unmodifiableMap(map);
this.modIdMapRef = new SoftReference<>(cached);
return cached;
} finally {
lock.unlock();
}
}
/// Returns an unmodifiable index, rebuilding it after its soft reference is cleared.
/// Duplicate keys retain the first project in resource order.
private @Unmodifiable Map<String, I> getSubnameMap() {
@Nullable SoftReference<@Unmodifiable Map<String, I>> reference = this.subnameMapRef;
@Unmodifiable Map<String, I> cached = reference != null ? reference.get() : null;
if (cached != null)
return cached;
lock.lock();
try {
reference = this.subnameMapRef;
cached = reference != null ? reference.get() : null;
if (cached != null)
return cached;
Map<String, I> map = new HashMap<>();
for (I info : getInfos()) {
String name = cleanSubname(info.subName());
if (!name.isEmpty())
map.putIfAbsent(name, info);
}
cached = Collections.unmodifiableMap(map);
this.subnameMapRef = new SoftReference<>(cached);
return cached;
} finally {
lock.unlock();
}
}
/// Returns an unmodifiable index, rebuilding it after its soft reference is cleared.
/// Duplicate keys retain the first project in resource order.
private @Unmodifiable Map<String, I> getCurseForgeMap() {
@Nullable SoftReference<@Unmodifiable Map<String, I>> reference = this.curseForgeMapRef;
@Unmodifiable Map<String, I> cached = reference != null ? reference.get() : null;
if (cached != null)
return cached;
lock.lock();
try {
reference = this.curseForgeMapRef;
cached = reference != null ? reference.get() : null;
if (cached != null)
return cached;
Map<String, I> map = new HashMap<>();
for (I info : getInfos()) {
String id = info.curseforgeId();
if (StringUtils.isNotBlank(id))
map.putIfAbsent(id, info);
}
cached = Collections.unmodifiableMap(map);
this.curseForgeMapRef = new SoftReference<>(cached);
return cached;
} finally {
lock.unlock();
}
}
/// Returns the first project with the exact CurseForge identifier, or `null` if the
/// identifier is null, blank or unknown.
public @Nullable I getInfoByCurseForgeId(@Nullable String id) {
return StringUtils.isBlank(id) ? null : getCurseForgeMap().get(id);
}
/// Finds a project by its cleaned secondary name, falling back to its exact mod ID.
/// A name match is accepted only when the ID is blank or belongs to that mod project.
/// Null and blank inputs are absent; returns `null` if neither lookup matches.
/// Duplicate keys resolve to the first project in resource order.
public @Nullable I getInfo(@Nullable String id, @Nullable String subname) {
String name = cleanSubname(subname);
if (StringUtils.isNotBlank(name)) {
@Nullable I info = getSubnameMap().get(name);
if (info != null && (StringUtils.isBlank(id)
|| info instanceof ModProjectInfo mod && mod.getModIds().contains(id)))
return info;
}
return StringUtils.isBlank(id) ? null : getModIdMap().get(id);
}
private static boolean isSupportedSubnameChar(int ch) {
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')
|| ".+\\".indexOf(ch) >= 0;
}
/// Removes supported separators and pictographs from a secondary name.
/// Returns an empty string for null, blank or unsupported names; matching is case-sensitive.
private static String cleanSubname(@Nullable String subname) {
if (StringUtils.isBlank(subname))
return "";
int offset = 0;
while (offset < subname.length()) {
int ch = subname.charAt(offset);
if (!isSupportedSubnameChar(ch))
break;
offset++;
}
if (offset == subname.length())
return subname;
StringBuilder builder = new StringBuilder(subname.length());
builder.append(subname, 0, offset);
while (offset < subname.length()) {
int ch = subname.codePointAt(offset);
if (isSupportedSubnameChar(ch)) {
builder.appendCodePoint(ch);
} else if (!(Character.isWhitespace(ch)
|| "':_-/&()[]{}|,!?~•".indexOf(ch) >= 0
|| ch >= 0x1F300 && ch <= 0x1FAFF)) {
return "";
}
offset += Character.charCount(ch);
}
return builder.toString();
}
/// Returns searchable names, rebuilding the index after its soft reference is cleared.
private @Unmodifiable List<Pair<String, I>> getKeywords() {
@Nullable SoftReference<@Unmodifiable List<Pair<String, I>>> reference = keywordsRef;
@Unmodifiable List<Pair<String, I>> cached = reference != null ? reference.get() : null;
if (cached != null)
return cached;
lock.lock();
try {
reference = keywordsRef;
cached = reference != null ? reference.get() : null;
if (cached != null)
return cached;
List<Pair<String, I>> keywords = new ArrayList<>();
for (I info : getInfos()) {
if (!info.mainName().isEmpty())
keywords.add(Pair.pair(info.mainName(), info));
if (!info.subName().isEmpty())
keywords.add(Pair.pair(info.subName(), info));
if (!info.abbrName().isEmpty())
keywords.add(Pair.pair(info.abbrName(), info));
}
cached = List.copyOf(keywords);
keywordsRef = new SoftReference<>(cached);
return cached;
} finally {
lock.unlock();
}
}
/// Returns projects ranked by descending longest common subsequence length after removing
/// space characters from the query. Comparison is case-sensitive and uses UTF-16 units.
/// Matches require at least one unit and at least query length minus three units.
/// Each matching name contributes a result, so projects may occur more than once.
/// Ties preserve resource order, then primary name, secondary name and abbreviation order.
public @Unmodifiable List<I> search(String query) {
query = query.chars().filter(ch -> !Character.isSpaceChar(ch))
.collect(StringBuilder::new, (sb, ch) -> sb.append((char) ch), StringBuilder::append).toString();
@Unmodifiable List<Pair<String, I>> keywords = getKeywords();
int maxLength = keywords.stream().mapToInt(keyword -> keyword.getKey().length()).max().orElse(0);
StringUtils.LongestCommonSubsequence lcs = new StringUtils.LongestCommonSubsequence(query.length(), maxLength);
List<Pair<Integer, I>> matches = new ArrayList<>();
for (Pair<String, I> keyword : keywords) {
int score = lcs.calc(query, keyword.getKey());
if (score >= Math.max(1, query.length() - 3))
matches.add(Pair.pair(score, keyword.getValue()));
}
return matches.stream().sorted((a, b) -> Integer.compare(b.getKey(), a.getKey()))
.map(Pair::getValue).toList();
}
/// Returns cached project metadata, loading it on demand. Missing resources and I/O failures
/// produce an empty list; malformed records are skipped. The cache is softly referenced.
public @Unmodifiable List<I> getInfos() {
@Nullable SoftReference<@Unmodifiable List<I>> infosRef = this.infosRef;
@Unmodifiable List<I> infos = infosRef != null ? infosRef.get() : null;
if (infos != null)
return infos;
lock.lock();
try {
infosRef = this.infosRef;
infos = infosRef != null ? infosRef.get() : null;
if (infos != null)
return infos;
try {
infos = loadInfos();
} catch (IOException e) {
LOG.warning("Failed to load addon project info from " + assetsPath, e);
infos = List.of();
}
this.infosRef = new SoftReference<>(infos);
return infos;
} finally {
lock.unlock();
}
}
}
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.addon.update;
import org.jackhuang.hmcl.download.DownloadProvider;
@@ -36,7 +21,7 @@ import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public class AddonCheckUpdatesTask extends Task<AddonUpdates> {
private final List<Task<Pair<AddonUpdate, @Nullable AddonUpdate>>> dependents;
public AddonCheckUpdatesTask(DownloadProvider downloadProvider, String gameVersion, Collection<? extends LocalAddonFile> addons) {
public AddonCheckUpdatesTask(DownloadProvider downloadProvider, String gameVersion, Collection<? extends LocalAddonFile<?>> addons) {
dependents = addons.stream().map(addon ->
Task.supplyAsync(Schedulers.io(), () -> {
AddonUpdate candidate = null;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.addon.update;
import org.jackhuang.hmcl.addon.LocalAddonFile;
@@ -37,14 +22,14 @@ import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public class AddonUpdateTask extends Task<Void> {
private final Collection<Task<?>> dependents = new ArrayList<>();
private final List<LocalAddonFile> failedAddons = new ArrayList<>();
private final List<LocalAddonFile<?>> failedAddons = new ArrayList<>();
public AddonUpdateTask(DownloadProvider downloadProvider, Path addonDirectory, List<AddonUpdate> addons) {
setStage("addon.check_update.confirm");
getProperties().put("total", addons.size());
for (AddonUpdate addon : addons) {
LocalAddonFile local = addon.localAddonFile();
LocalAddonFile<?> local = addon.localAddonFile();
RemoteAddon.Version remote = addon.targetVersion();
boolean isDisabled = local.isDisabled();
String fileName = remote.file().filename();
@@ -91,7 +76,7 @@ public class AddonUpdateTask extends Task<Void> {
}
}
public List<LocalAddonFile> getFailedAddons() {
public List<LocalAddonFile<?>> getFailedAddons() {
return failedAddons;
}
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.countly;
import org.jackhuang.hmcl.Metadata;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.download;
import org.glavo.url.WebURL;
@@ -29,7 +14,7 @@ import org.jackhuang.hmcl.game.GameComponentType;
import org.jackhuang.hmcl.game.HMCLCacheRepository;
import org.jackhuang.hmcl.setting.DownloadSource;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.i18n.LocaleUtils;
import org.jackhuang.hmcl.util.RegionUtils;
import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
import org.jetbrains.annotations.NotNullByDefault;
import org.jetbrains.annotations.Nullable;
@@ -46,7 +31,7 @@ public final class HMCLDownloadProvider extends DownloadProvider {
DownloadSource source,
WebURL defaultUrl, WebURL bmclapiUrl
) {
if (LocaleUtils.IS_CHINA_MAINLAND) {
if ("CN".equals(RegionUtils.MACHINE_REGION)) {
return switch (source) {
case DEFAULT, OFFICIAL -> DownloadCandidates.of(defaultUrl, bmclapiUrl);
case MIRROR -> DownloadCandidates.of(bmclapiUrl, defaultUrl);
@@ -66,7 +51,7 @@ public final class HMCLDownloadProvider extends DownloadProvider {
// true means prefer mirror, false means prefer official, null means do not use mirror
@Nullable Boolean mirrorFirst;
if (LocaleUtils.IS_CHINA_MAINLAND) {
if ("CN".equals(RegionUtils.MACHINE_REGION)) {
mirrorFirst = switch (source) {
case DEFAULT, MIRROR -> true;
case OFFICIAL -> false;
@@ -91,25 +76,18 @@ public final class HMCLDownloadProvider extends DownloadProvider {
continue;
}
@Nullable DownloadCandidate mirrorCandidate = null;
boolean fallback = false;
boolean added = false;
for (MirrorRule rule : rules) {
if (url.startsWith(rule.source)) {
mirrorCandidate = DownloadCandidate.of(rule.target + url.substring(rule.source.length()));
fallback = rule.fallback;
@Nullable List<DownloadCandidate> list = rule.getCandidates(candidate, mirrorFirst);
if (list != null) {
candidates.addAll(list);
added = true;
break;
}
}
if (mirrorCandidate == null) {
if (!added)
candidates.add(candidate);
} else if (mirrorFirst && !fallback) {
candidates.add(mirrorCandidate);
candidates.add(candidate);
} else {
candidates.add(candidate);
candidates.add(mirrorCandidate);
}
}
return DownloadCandidates.of(List.copyOf(candidates));
@@ -121,32 +99,59 @@ public final class HMCLDownloadProvider extends DownloadProvider {
public HMCLDownloadProvider(String bmclRoot) {
this.bmclRoot = bmclRoot;
this.rules = List.of(
new MirrorRule("https://bmclapi2.bangbang93.com", bmclRoot),
new MirrorRule("https://launchermeta.mojang.com", bmclRoot),
new MirrorRule("https://piston-meta.mojang.com", bmclRoot),
new MirrorRule("https://piston-data.mojang.com", bmclRoot),
new MirrorRule("https://launcher.mojang.com", bmclRoot),
new MirrorRule("https://libraries.minecraft.net", bmclRoot + "/libraries"),
new MirrorRule("http://files.minecraftforge.net/maven", bmclRoot + "/maven"),
new MirrorRule("https://files.minecraftforge.net/maven", bmclRoot + "/maven"),
new MirrorRule("https://maven.minecraftforge.net", bmclRoot + "/maven"),
new MirrorRule("https://maven.neoforged.net/releases/", bmclRoot + "/maven/"),
new MirrorRule("http://dl.liteloader.com/versions", bmclRoot + "/maven"),
new MirrorRule("https://dl.liteloader.com/versions", bmclRoot + "/maven"),
new MirrorRule("https://meta.fabricmc.net", bmclRoot + "/fabric-meta"),
new MirrorRule("https://maven.fabricmc.net", bmclRoot + "/maven"),
new MirrorRule("https://authlib-injector.yushi.moe", bmclRoot + "/mirrors/authlib-injector"),
new MirrorRule("https://repo1.maven.org/maven2", "https://mirrors.cloud.tencent.com/nexus/repository/maven-public"),
new MirrorRule("https://repo.maven.apache.org/maven2", "https://mirrors.cloud.tencent.com/nexus/repository/maven-public"),
new MirrorRule("https://hmcl.glavo.site/metadata/cleanroom", "https://alist.8mi.tech/d/mirror/HMCL-Metadata/Auto/cleanroom"),
new MirrorRule("https://hmcl.glavo.site/metadata/fmllibs", "https://alist.8mi.tech/d/mirror/HMCL-Metadata/Auto/fmllibs"),
new MirrorRule("https://zkitefly.github.io/unlisted-versions-of-minecraft", "https://alist.8mi.tech/d/mirror/unlisted-versions-of-minecraft/Auto"),
new SimpleRule("https://bmclapi2.bangbang93.com", bmclRoot),
new SimpleRule("https://launchermeta.mojang.com", bmclRoot),
new SimpleRule("https://piston-meta.mojang.com", bmclRoot),
new SimpleRule("https://piston-data.mojang.com", bmclRoot),
new SimpleRule("https://launcher.mojang.com", bmclRoot),
new SimpleRule("https://libraries.minecraft.net", bmclRoot + "/libraries"),
new SimpleRule("http://files.minecraftforge.net/maven", bmclRoot + "/maven"),
new SimpleRule("https://files.minecraftforge.net/maven", bmclRoot + "/maven"),
new SimpleRule("https://maven.minecraftforge.net", bmclRoot + "/maven"),
(source, mirrorFirst) -> {
String neoforgedMaven = "https://maven.neoforged.net/";
String neoforgedMavenRelease = "https://maven.neoforged.net/releases/";
if (source.url() == null || !source.url().href().startsWith(neoforgedMaven))
return null;
var candidates = new ArrayList<DownloadCandidate>();
if (source.url().href().startsWith(neoforgedMavenRelease)) {
DownloadCandidate bmclapiMirror = DownloadCandidate.of(bmclRoot + "/maven/"
+ source.url().href().substring(neoforgedMavenRelease.length()));
if (mirrorFirst) {
candidates.add(bmclapiMirror);
candidates.add(source);
} else {
candidates.add(source);
candidates.add(bmclapiMirror);
}
} else {
candidates.add(source);
}
// https://neoforged.forgecdn.net
candidates.add(DownloadCandidate.of("https://neoforged.forgecdn.net/" + source.url().href().substring(neoforgedMaven.length())));
return candidates;
},
new SimpleRule("http://dl.liteloader.com/versions", bmclRoot + "/maven"),
new SimpleRule("https://dl.liteloader.com/versions", bmclRoot + "/maven"),
new SimpleRule("https://meta.fabricmc.net", bmclRoot + "/fabric-meta"),
new SimpleRule("https://maven.fabricmc.net", bmclRoot + "/maven"),
new SimpleRule("https://authlib-injector.yushi.moe", bmclRoot + "/mirrors/authlib-injector"),
new SimpleRule("https://repo1.maven.org/maven2", "https://mirrors.cloud.tencent.com/nexus/repository/maven-public"),
new SimpleRule("https://repo.maven.apache.org/maven2", "https://mirrors.cloud.tencent.com/nexus/repository/maven-public"),
new SimpleRule("https://hmcl.glavo.site/metadata/cleanroom", "https://alist.8mi.tech/d/mirror/HMCL-Metadata/Auto/cleanroom"),
new SimpleRule("https://hmcl.glavo.site/metadata/fmllibs", "https://alist.8mi.tech/d/mirror/HMCL-Metadata/Auto/fmllibs"),
new SimpleRule("https://zkitefly.github.io/unlisted-versions-of-minecraft", "https://alist.8mi.tech/d/mirror/unlisted-versions-of-minecraft/Auto"),
// https://github.com/mcmod-info-mirror/mcim-rust-api
new MirrorRule("https://api.modrinth.com", "https://mod.mcimirror.top/modrinth", true),
new MirrorRule("https://cdn.modrinth.com", "https://mod.mcimirror.top", true),
new MirrorRule("https://api.curseforge.com", "https://mod.mcimirror.top/curseforge", true),
new MirrorRule("https://edge.forgecdn.net", "https://mod.mcimirror.top", true)
new SimpleRule("https://api.modrinth.com", null, "https://mod.mcimirror.top/modrinth"),
new SimpleRule("https://cdn.modrinth.com", null, "https://mod.mcimirror.top"),
new SimpleRule("https://api.curseforge.com", null, "https://mod.mcimirror.top/curseforge"),
new SimpleRule("https://edge.forgecdn.net", null, "https://mod.mcimirror.top")
);
}
@@ -158,7 +163,7 @@ public final class HMCLDownloadProvider extends DownloadProvider {
Task<ComponentRemoteVersionList<ForgeRemoteVersion>> fetchOfficial = ForgeRemoteVersion.fetchAsync(this, gameVersion);
DownloadSource source = versionListSource;
if (!LocaleUtils.IS_CHINA_MAINLAND && (source == DownloadSource.DEFAULT || source == DownloadSource.OFFICIAL)) {
if (source == DownloadSource.DEFAULT || source == DownloadSource.OFFICIAL) {
return fetchOfficial;
}
@@ -173,7 +178,7 @@ public final class HMCLDownloadProvider extends DownloadProvider {
Task<ComponentRemoteVersionList<NeoForgeRemoteVersion>> fetchOfficial = NeoForgeRemoteVersion.fetchAsync(this, gameVersion);
DownloadSource source = versionListSource;
if (!LocaleUtils.IS_CHINA_MAINLAND && (source == DownloadSource.DEFAULT || source == DownloadSource.OFFICIAL)) {
if (source == DownloadSource.DEFAULT || source == DownloadSource.OFFICIAL) {
return fetchOfficial;
}
Task<ComponentRemoteVersionList<NeoForgeRemoteVersion>> fetchBMCL = NeoForgeRemoteVersion.fetchBMCLAsync(bmclRoot, gameVersion);
@@ -224,7 +229,7 @@ public final class HMCLDownloadProvider extends DownloadProvider {
@Override
public DownloadCandidates getCleanroomVersionListCandidates() {
return LocaleUtils.IS_CHINA_MAINLAND
return "CN".equals(RegionUtils.MACHINE_REGION)
? DownloadCandidates.of(CleanroomRemoteVersion.LOADER_LIST_URL, WebURL.parse("https://alist.8mi.tech/d/mirror/HMCL-Metadata/Auto/cleanroom/index.json"))
: DownloadCandidates.of(CleanroomRemoteVersion.LOADER_LIST_URL);
}
@@ -287,9 +292,41 @@ public final class HMCLDownloadProvider extends DownloadProvider {
}
}
private record MirrorRule(String source, String target, boolean fallback) {
public MirrorRule(String source, String target) {
this(source, target, false);
@NotNullByDefault
@FunctionalInterface
private interface MirrorRule {
@Nullable List<DownloadCandidate> getCandidates(DownloadCandidate source, boolean mirrorFirst);
}
@NotNullByDefault
private record SimpleRule(String source, @Nullable String first, @Nullable String fallback) implements MirrorRule {
public SimpleRule(String source, String target) {
this(source, target, null);
}
@Override
public @Nullable List<DownloadCandidate> getCandidates(DownloadCandidate source, boolean mirrorFirst) {
if (source.url() == null || !source.url().href().startsWith(this.source))
return null;
boolean addSourceFirst = !mirrorFirst || first == null;
String urlWithoutPrefix = source.url().href().substring(this.source.length());
var candidates = new ArrayList<DownloadCandidate>();
if (addSourceFirst)
candidates.add(source);
if (first != null)
candidates.add(DownloadCandidate.of(first + urlWithoutPrefix));
if (!addSourceFirst)
candidates.add(source);
if (fallback != null)
candidates.add(DownloadCandidate.of(fallback + urlWithoutPrefix));
return candidates;
}
}
}
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2020 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import javafx.beans.property.SimpleStringProperty;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.download.DefaultCacheRepository;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.download.DefaultGameBuilder;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import com.google.gson.JsonObject;
@@ -565,7 +550,13 @@ public class HMCLGameInstance extends DefaultGameInstance {
return getLayout().getInstanceGameSettingsFile(id);
}
public LaunchOptions.Builder getLaunchOptions(JavaRuntime javaVersion, Path gameDir, List<String> javaAgents, List<String> javaArguments, boolean makeLaunchScript) {
public LaunchOptions.Builder getLaunchOptions(
JavaRuntime javaRuntime,
Path javaExecutable,
Path gameDir,
List<String> javaAgents,
List<String> javaArguments,
boolean makeLaunchScript) {
GameSettings.Effective vs = getEffectiveSettings();
boolean noJVMOptions = vs.getInheritable(GameSettings::noJVMOptionsProperty);
boolean autoMemory = vs.getInheritable(GameSettings::autoMemoryProperty);
@@ -576,8 +567,8 @@ public class HMCLGameInstance extends DefaultGameInstance {
maxMemory = noJVMOptions
? null
: Math.toIntExact(HMCLGameRepository.getAutoAllocatedMemory(
SystemInfo.getPhysicalMemoryStatus().available(),
javaVersion.getPlatform()) / 1024L / 1024L);
SystemInfo.getPhysicalMemoryStatus(),
javaRuntime.getPlatform()) / 1024L / 1024L);
} else {
maxMemory = vs.getMaxMemory();
}
@@ -585,7 +576,8 @@ public class HMCLGameInstance extends DefaultGameInstance {
LaunchOptions.Builder builder = new LaunchOptions.Builder()
.setInstanceId(getId())
.setGameDir(gameDir)
.setJava(javaVersion)
.setJava(javaRuntime)
.setJavaExecutable(javaExecutable)
.setVersionType(Metadata.TITLE)
.setVersionName(getId().id())
.setProfileName(Metadata.TITLE)
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2020 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.Metadata;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2021 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2021 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import javafx.beans.binding.Bindings;
@@ -34,11 +19,13 @@ import org.jackhuang.hmcl.setting.LegacyGameSettingsMigrator;
import org.jackhuang.hmcl.setting.GameSettingsPresetID;
import org.jackhuang.hmcl.util.FileSaver;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.MathUtils;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.platform.Bits;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.platform.Platform;
import org.jackhuang.hmcl.util.platform.hardware.PhysicalMemoryStatus;
import org.jackhuang.hmcl.util.versioning.VersionNumber;
import org.jetbrains.annotations.NotNullByDefault;
import org.jetbrains.annotations.Nullable;
@@ -511,23 +498,43 @@ public final class HMCLGameRepository extends DefaultGameRepository {
}
}
public static long getAutoAllocatedMemory(long available, Platform platform) {
long usable = available - 512 * 1024 * 1024; // Reserve 512 MiB memory for off-heap memory and HMCL itself
if (usable <= 0) {
return available;
public static long getAutoAllocatedMemory(PhysicalMemoryStatus memoryStatus, Platform platform) {
final long minHeapSize;
final long maxHeapSize;
if (platform.getBits() == Bits.BIT_32) {
// https://github.com/HMCL-dev/HMCL/issues/6638
maxHeapSize = 768 * 1024 * 1024; // 768 MiB
minHeapSize = 256 * 1024 * 1024; // 128 MiB
} else {
maxHeapSize = 24L * 1024 * 1024 * 1024; // 24 GiB
minHeapSize = 512 * 1024 * 1024; // 512 MiB
}
final long threshold = 8L * 1024 * 1024 * 1024; // 8 GiB
final long suggested;
if (usable <= threshold)
// Reserve memory for off-heap memory and HMCL itself
final long reserved = 256 * 1024 * 1024; // 256 MiB
final long threshold1 = 8L * 1024 * 1024 * 1024; // 8 GiB
final long threshold2 = 16L * 1024 * 1024 * 1024; // 16 GiB
if (memoryStatus.total() <= minHeapSize || memoryStatus.available() < 0) {
return -1L;
}
final long usable = Math.max(
Math.max(memoryStatus.available(), memoryStatus.total() / 16) - reserved,
0
);
long suggested;
if (usable <= threshold1)
suggested = (long) (usable * 0.8);
else if (usable <= threshold2)
suggested = (long) (threshold1 * 0.8 + (usable - threshold1) * 0.4);
else
suggested = Math.min(
(long) (threshold * 0.8 + (usable - threshold) * 0.2),
16L * 1024 * 1024 * 1024);
return platform.getBits() == Bits.BIT_32
? Math.min(suggested, 768 * 1024 * 1024) // https://github.com/HMCL-dev/HMCL/issues/6638
: suggested;
suggested = (long) (threshold1 * 0.8 + (threshold2 - threshold1) * 0.4 + (usable - threshold2) * 0.2);
return MathUtils.clamp(suggested & ~0xFFFFFL, minHeapSize, maxHeapSize);
}
}
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import org.jetbrains.annotations.NotNullByDefault;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import org.jetbrains.annotations.NotNullByDefault;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2020 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import com.google.gson.JsonParseException;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2020 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.modpack.ModpackManifest;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2022 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2022 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import com.google.gson.JsonParseException;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2021 huangyuhui <[email protected]> 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2021 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import com.jfoenix.controls.JFXButton;
@@ -57,11 +42,11 @@ import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.SocketTimeoutException;
import java.nio.file.AccessDeniedException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
@@ -148,29 +133,46 @@ public final class LauncherHelper {
}
/// Builds and executes the launch pipeline for the captured game instance.
@SuppressWarnings("NonAtomicOperationOnVolatileField")
private void launch0() {
// https://github.com/HMCL-dev/HMCL/pull/4121
PROCESSES.removeIf(it -> it.get() == null);
final var context = new Object() {
volatile GameInstanceManifest launchManifest;
volatile JavaRuntime javaRuntime;
volatile Path javaExecutable;
};
HMCLGameRepository repository = repository();
DefaultDependencyManager dependencyManager = repository.getDependency();
// Resolve already deduplicated libraries; apply loader-specific argument repairs for this launch.
var launchManifest = new AtomicReference<>(LaunchManifestNormalizer.repairForLaunch(gameInstance.getResolvedManifest()));
boolean integrityCheck = gameInstance.unmarkLaunchedAbnormally();
CountDownLatch launchingLatch = new CountDownLatch(1);
List<String> javaAgents = new ArrayList<>(0);
List<String> javaArguments = new ArrayList<>(0);
AtomicReference<JavaRuntime> javaVersionRef = new AtomicReference<>();
// Resolve already deduplicated libraries; apply loader-specific argument repairs for this launch.
context.launchManifest = LaunchManifestNormalizer.repairForLaunch(gameInstance.getResolvedManifest());
TaskExecutor executor = checkGameState(gameInstance, setting, launchManifest.get())
TaskExecutor executor = checkGameState(gameInstance, setting, context.launchManifest)
.thenComposeAsync(java -> {
javaVersionRef.set(Objects.requireNonNull(java));
launchManifest.set(NativePatcher.patchNative(gameInstance, launchManifest.get(), java, setting, javaArguments));
context.javaRuntime = Objects.requireNonNull(java);
context.javaExecutable = java.getBinary();
if (java.getPlatform().os() == OperatingSystem.WINDOWS
&& scriptFile == null
&& !setting.getInheritable(GameSettings::notUseJavawProperty)
&& FileUtils.getName(java.getBinary()).equalsIgnoreCase("java.exe")) {
Path javawBinary = java.getBinary().resolveSibling("javaw.exe");
if (Files.isRegularFile(javawBinary)) {
context.javaExecutable = javawBinary;
}
}
context.launchManifest = NativePatcher.patchNative(gameInstance, context.launchManifest, java, setting, javaArguments);
if (setting.getInheritable(GameSettings::notCheckGameProperty))
return null;
return Task.allOf(
dependencyManager.checkGameCompletionAsync(gameInstance, launchManifest.get(), integrityCheck),
dependencyManager.checkGameCompletionAsync(gameInstance, context.launchManifest, integrityCheck),
Task.composeAsync(() -> {
try {
@Nullable ModpackConfiguration<?> configuration =
@@ -203,7 +205,7 @@ public final class LauncherHelper {
String agent = FileUtils.getAbsolutePath(file) + "=" + renderer.mesaDriverName();
if (GameLibrariesTask.shouldDownloadLibrary(repository, launchManifest.get(), lib, integrityCheck)) {
if (GameLibrariesTask.shouldDownloadLibrary(repository, context.launchManifest, lib, integrityCheck)) {
return new LibraryDownloadTask(dependencyManager, file, lib)
.thenRunAsync(() -> javaAgents.add(agent));
} else {
@@ -213,13 +215,13 @@ public final class LauncherHelper {
})
);
}).withStage("launch.state.dependencies")
.thenComposeAsync(() -> new GameVerificationFixTask(gameInstance, gameInstance.getVersion(), launchManifest.get()))
.thenComposeAsync(() -> new GameVerificationFixTask(gameInstance, gameInstance.getVersion(), context.launchManifest))
.thenComposeAsync(() -> {
if (setting.getInheritable(GameSettings::allowAutoAgentProperty)
|| setting.getInheritable(GameSettings::noJVMOptionsProperty)
|| setting.getInheritable(GameSettings::noOptimizingJVMOptionsProperty)
|| Boolean.TRUE.equals(state().getShownTips().get(LWJGL_3_4_1_TIP))
|| !NativePatcher.needPatchMemoryUtil(launchManifest.get(), javaVersionRef.get().getParsedVersion())) {
|| !NativePatcher.needPatchMemoryUtil(context.launchManifest, context.javaRuntime.getParsedVersion())) {
return Task.completed(null);
} else {
CompletableFuture<Void> future = new CompletableFuture<>();
@@ -239,7 +241,12 @@ public final class LauncherHelper {
.thenComposeAsync(() -> logIn(account).withStage("launch.state.logging_in"))
.thenComposeAsync(authInfo -> Task.supplyAsync(() -> {
LaunchOptions.Builder launchOptionsBuilder = gameInstance.getLaunchOptions(
javaVersionRef.get(), repository.getBaseDirectory(), javaAgents, javaArguments, scriptFile != null);
context.javaRuntime,
context.javaExecutable,
repository.getBaseDirectory(),
javaAgents,
javaArguments,
scriptFile != null);
if (disableOfflineSkin) {
launchOptionsBuilder.setDaemon(false);
}
@@ -248,7 +255,7 @@ public final class LauncherHelper {
}
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS && setting.getInheritable(GameSettings::highPerformanceProperty)) {
@Nullable String javaPathGpuReg = FileUtils.getAbsolutePath(javaVersionRef.get().getBinary());
@Nullable String javaPathGpuReg = FileUtils.getAbsolutePath(context.javaExecutable);
try {
WinReg reg = WinReg.INSTANCE;
if (reg != null) {
@@ -283,7 +290,7 @@ public final class LauncherHelper {
return new HMCLGameLauncher(
gameInstance,
launchManifest.get(),
context.launchManifest,
authInfo,
launchOptions,
launcherVisibility == LauncherVisibility.CLOSE
@@ -305,10 +312,10 @@ public final class LauncherHelper {
if (launcherVisibility == LauncherVisibility.CLOSE)
Launcher.stopApplication();
else
launchingStepsPane.setCancel(new TaskCancellationAction(it -> {
launchingStepsPane.setCancel(it -> {
process.stop();
it.fireEvent(new DialogCloseEvent());
}));
});
} else {
runLater(() -> {
launchingStepsPane.fireEvent(new DialogCloseEvent());
@@ -746,7 +753,7 @@ public final class LauncherHelper {
}
future.completeExceptionally(new CancellationException());
}
}), i18n("download.java"), new TaskCancellationAction(() -> future.completeExceptionally(new CancellationException())));
}), i18n("download.java"), it -> future.completeExceptionally(new CancellationException()));
}, () -> future.completeExceptionally(new CancellationException())).build());
return future;
@@ -1,29 +1,16 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2022 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2022 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.download.DownloadProvider;
import org.jackhuang.hmcl.addon.RemoteAddon;
import org.jackhuang.hmcl.addon.RemoteAddonRepository;
import org.jackhuang.hmcl.ui.instances.ModTranslations;
import org.jackhuang.hmcl.addon.AddonProjectInfo;
import org.jackhuang.hmcl.addon.AddonProjectInfoRegistry;
import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.nio.file.Path;
@@ -51,15 +38,16 @@ public abstract class LocalizedRemoteAddonRepository implements RemoteAddonRepos
@Override
public SearchResult search(DownloadProvider downloadProvider, RemoteAddon.Type type, String gameVersion, Category category, int pageOffset, int pageSize, String searchFilter, SortType sort, SortOrder sortOrder) throws IOException {
if (!StringUtils.containsChinese(searchFilter)) {
@Nullable AddonProjectInfoRegistry<?> registry = AddonProjectInfoRegistry.getByAddonType(type);
if (registry == null || !StringUtils.containsChinese(searchFilter)) {
return getBackedRemoteModRepository().search(downloadProvider, type, gameVersion, category, pageOffset, pageSize, searchFilter, sort, sortOrder);
}
Set<String> englishSearchFiltersSet = new LinkedHashSet<>(INITIAL_CAPACITY);
int count = 0;
for (ModTranslations.Mod mod : ModTranslations.getTranslationsByAddonType(type).searchMod(searchFilter)) {
String englishSearchFilter = String.join(" ", StringUtils.tokenize(StringUtils.isNotBlank(mod.getSubname()) ? mod.getSubname() : mod.getName()));
for (AddonProjectInfo mod : registry.search(searchFilter)) {
String englishSearchFilter = String.join(" ", StringUtils.tokenize(StringUtils.isNotBlank(mod.subName()) ? mod.subName() : mod.mainName()));
if (StringUtils.isNotBlank(englishSearchFilter)) {
englishSearchFiltersSet.add(englishSearchFilter);
}
@@ -91,8 +79,8 @@ public abstract class LocalizedRemoteAddonRepository implements RemoteAddonRepos
continue;
}
ModTranslations.Mod chineseTranslation = ModTranslations.getTranslationsByAddonType(type).getModByCurseForgeId(remoteAddon.slug());
if (chineseTranslation != null && !StringUtils.isBlank(chineseTranslation.getName()) && StringUtils.containsChinese(chineseTranslation.getName())) {
@Nullable AddonProjectInfo chineseTranslation = registry.getInfoByCurseForgeId(remoteAddon.slug());
if (chineseTranslation != null && !StringUtils.isBlank(chineseTranslation.mainName()) && StringUtils.containsChinese(chineseTranslation.mainName())) {
searchResultArray[chineseIndex++] = remoteAddon;
} else {
searchResultArray[englishIndex--] = remoteAddon;
@@ -103,11 +91,11 @@ public abstract class LocalizedRemoteAddonRepository implements RemoteAddonRepos
StringUtils.LevCalculator levCalculator = new StringUtils.LevCalculator();
return new SearchResult(Stream.concat(Arrays.stream(searchResultArray, 0, chineseIndex).map(remoteMod -> {
ModTranslations.Mod chineseRemoteMod = ModTranslations.getTranslationsByAddonType(type).getModByCurseForgeId(remoteMod.slug());
if (chineseRemoteMod == null || StringUtils.isBlank(chineseRemoteMod.getName()) || !StringUtils.containsChinese(chineseRemoteMod.getName())) {
@Nullable AddonProjectInfo chineseRemoteMod = registry.getInfoByCurseForgeId(remoteMod.slug());
if (chineseRemoteMod == null || StringUtils.isBlank(chineseRemoteMod.mainName()) || !StringUtils.containsChinese(chineseRemoteMod.mainName())) {
return Pair.pair(remoteMod, Integer.MAX_VALUE);
}
String chineseRemoteModName = chineseRemoteMod.getName();
String chineseRemoteModName = chineseRemoteMod.mainName();
if (searchFilter.isEmpty() || chineseRemoteModName.isEmpty()) {
return Pair.pair(remoteMod, Math.max(searchFilter.length(), chineseRemoteModName.length()));
}
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2024 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2024 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.util.Log4jLevel;
@@ -1,20 +1,5 @@
/*
* 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2021 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.util.gson.JsonUtils;
@@ -1,20 +1,5 @@
/*
* 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2021 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import java.nio.file.Path;
@@ -1,20 +1,5 @@
/*
* 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2021 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.task.Task;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2020 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import com.google.gson.JsonParseException;
@@ -76,7 +61,7 @@ public final class ModpackHelper {
);
static {
MultiMCComponents.setImplementation(Metadata.FULL_TITLE);
MultiMCComponents.setImplementation(Metadata.FULL_NAME + " v" + Metadata.VERSION);
}
@Nullable
@@ -1,20 +1,5 @@
/*
* 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2021 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import fi.iki.elonen.NanoHTTPD;
@@ -1,20 +1,5 @@
/*
* 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2021 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.game;
import javafx.beans.InvalidationListener;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2024 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2024 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.java;
import org.jackhuang.hmcl.download.DownloadProvider;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2025 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.java;
import com.google.gson.annotations.SerializedName;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2024 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2024 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.java;
import kala.compress.archivers.ArchiveEntry;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2020 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.java;
import com.google.gson.*;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2024 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2024 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.java;
import com.google.gson.JsonArray;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2024 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2024 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.java;
import com.google.gson.*;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.JsonObject;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.JsonArray;
@@ -1,20 +1,5 @@
/*
* 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2021 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.JsonObject;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.annotations.JsonAdapter;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.JsonParseException;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2020 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.JsonParseException;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2020 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import org.jetbrains.annotations.NotNullByDefault;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
/// @author Glavo
@@ -1,20 +1,5 @@
/*
* 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2021 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import javafx.beans.InvalidationListener;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import org.jetbrains.annotations.NotNullByDefault;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2020 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
public enum EnumCommonDirectory {
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2025 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import javafx.beans.property.ObjectProperty;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.annotations.JsonAdapter;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2020 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.*;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.annotations.JsonAdapter;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2020 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import javafx.beans.property.ObjectProperty;
@@ -1,20 +1,5 @@
/*
* 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2021 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import javafx.scene.image.Image;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.JsonDeserializationContext;
@@ -82,7 +67,7 @@ public sealed abstract class GameSettings extends ObservableSetting {
public static final class Instance extends GameSettings implements JsonSchemaSetting {
/// The JSON schema supported by instance-specific game settings.
public static final JsonSchema CURRENT_SCHEMA =
new JsonSchema("instance-game-settings", new JsonSchema.Version(1, 0, 0));
new JsonSchema("instance-game-settings", new JsonSchema.Version(1, 0, 1));
/// Creates an empty instance setting.
public Instance() {
@@ -388,6 +373,19 @@ public sealed abstract class GameSettings extends ObservableSetting {
return detectedJava;
}
/// Property name for disabling automatic replacement with `javaw.exe` on Windows.
public static final String PROPERTY_NOT_USE_JAVAW = "notUseJavaw";
/// Whether to keep the selected Java executable instead of replacing it with `javaw.exe`; defaults to `false`.
@SerializedName(PROPERTY_NOT_USE_JAVAW)
private final InheritableProperty<Boolean> notUseJavaw = newInheritableProperty(PROPERTY_NOT_USE_JAVAW, false);
/// Returns the property disabling automatic replacement of a Windows Java executable with a sibling `javaw.exe` file.
/// If `true`, the selected executable is used unchanged. This property has no effect on other runtime platforms.
public InheritableProperty<Boolean> notUseJavawProperty() {
return notUseJavaw;
}
/// Property name for customized JVM options.
public static final String PROPERTY_JVM_OPTIONS = "jvmOptions";
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.annotations.JsonAdapter;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.annotations.JsonAdapter;
@@ -44,7 +29,7 @@ import java.util.Objects;
public final class GameSettingsPresets extends ObservableSetting implements JsonSchemaSetting {
/// The JSON schema supported by this game settings preset store.
public static final JsonSchema CURRENT_SCHEMA =
new JsonSchema("game-settings", new JsonSchema.Version(1, 0, 0));
new JsonSchema("game-settings", new JsonSchema.Version(1, 0, 1));
/// Creates an empty game settings preset store.
public GameSettingsPresets() {
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
/// The initial display mode of the game window.
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2024 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2024 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import org.jetbrains.annotations.NotNullByDefault;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import org.jackhuang.hmcl.util.gson.JsonSchema;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.JsonObject;
@@ -1,20 +1,5 @@
/*
* 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2021 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.*;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.annotations.JsonAdapter;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2020 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
/**
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.*;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.JsonElement;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.JsonParseException;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.JsonArray;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2020 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import javafx.beans.InvalidationListener;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import org.jetbrains.annotations.NotNullByDefault;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
public final class SambaException extends RuntimeException {
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import org.jetbrains.annotations.NotNullByDefault;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import org.jetbrains.annotations.NotNullByDefault;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2020 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.JsonParseException;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2025 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import javafx.beans.binding.Bindings;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import org.jetbrains.annotations.NotNullByDefault;
@@ -1,20 +1,5 @@
/*
* 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2021 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.*;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting;
import com.google.gson.JsonParseException;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting.property;
import org.jetbrains.annotations.NotNullByDefault;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting.property;
import javafx.beans.property.Property;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting.property;
import org.jackhuang.hmcl.setting.GameSettings;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.setting.property;
import com.google.gson.JsonElement;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2025 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.terracotta;
import kala.compress.archivers.tar.TarArchiveEntry;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2025 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.terracotta;
import com.google.gson.JsonObject;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2025 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.terracotta;
import com.google.gson.annotations.SerializedName;
@@ -24,9 +9,9 @@ import org.jackhuang.hmcl.task.FileDownloadTask;
import org.jackhuang.hmcl.terracotta.provider.AbstractTerracottaProvider;
import org.jackhuang.hmcl.terracotta.provider.GeneralProvider;
import org.jackhuang.hmcl.terracotta.provider.MacOSProvider;
import org.jackhuang.hmcl.util.RegionUtils;
import org.jackhuang.hmcl.util.gson.JsonSerializable;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.i18n.LocaleUtils;
import org.jackhuang.hmcl.util.i18n.LocalizedText;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.NetworkUtils;
@@ -91,7 +76,7 @@ public final class TerracottaMetadata {
}
Stream<String> stream = downloads.stream(), streamCN = downloadsCN.stream();
@Unmodifiable List<WebURL> links = (LocaleUtils.IS_CHINA_MAINLAND ? Stream.concat(streamCN, stream) : Stream.concat(stream, streamCN))
@Unmodifiable List<WebURL> links = ("CN".equals(RegionUtils.MACHINE_REGION) ? Stream.concat(streamCN, stream) : Stream.concat(stream, streamCN))
.map(link -> WebURL.parse(options.replace(link)))
.toList();
@@ -1,30 +1,15 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 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/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2026 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.terracotta;
import com.google.gson.JsonParseException;
import org.glavo.url.WebURL;
import org.jackhuang.hmcl.util.RegionUtils;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.gson.JsonSerializable;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.gson.TolerableValidationException;
import org.jackhuang.hmcl.util.gson.Validation;
import org.jackhuang.hmcl.util.i18n.LocaleUtils;
import org.jackhuang.hmcl.util.io.HttpRequest;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
@@ -84,7 +69,7 @@ public final class TerracottaNodeList {
return false;
}
return StringUtils.isBlank(node.region) || LocaleUtils.IS_CHINA_MAINLAND == "CN".equalsIgnoreCase(node.region);
return StringUtils.isBlank(node.region) || node.region.equalsIgnoreCase(RegionUtils.MACHINE_REGION);
})
.map(it -> WebURL.parse(it.url()))
.toList();
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2025 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.terracotta;
import com.google.gson.JsonParseException;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2025 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.terracotta.profile;
import com.google.gson.annotations.SerializedName;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2025 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.terracotta.profile;
import com.google.gson.annotations.SerializedName;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2025 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.terracotta.provider;
import javafx.beans.value.ObservableDoubleValue;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2025 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.terracotta.provider;
import org.jackhuang.hmcl.terracotta.TerracottaBundle;
@@ -1,20 +1,5 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// SPDX-FileCopyrightText: Copyright (C) 2025 The HMCL Authors
// SPDX-License-Identifier: GPL-3.0-or-later WITH AdditionRef-HMCL
package org.jackhuang.hmcl.terracotta.provider;
import org.jackhuang.hmcl.Metadata;
Loaded 100 of 992 files, more files were not shown because too many files have changed in this diff. Show more