Compare commits

..
Author SHA1 Message Date
Glavo 24fc436870 将首页联机入口替换为入群链接 (#2900) 2024-03-06 18:29:51 +08:00
Glavo 3a6c23aa9d 将部分 KOOK 入口替换为 QQ 群 (#2902) 2024-03-06 14:38:13 +08:00
Glavo 0ee8b2dd82 指引用户加入 QQ 群 (#2897) 2024-03-05 23:57:25 +08:00
Glavo 7cce90bed8 删除 Mojang 登录支持 (#2889)
* 删除 Mojang 登录支持

* update

* update
2024-03-05 15:07:15 +08:00
Glavo c806a5d412 Update gradle.yml (#2895) 2024-03-05 14:22:45 +08:00
Glavo 14e8b9212f 更新 HMCLauncher 图标 (#2887) 2024-03-05 13:19:29 +08:00
Glavo 67e96fb84f 使用 GitHub 构建 HMCLauncher 后构建 HMCL (#2893)
* update

* update

* test

* update

* update

* update
2024-03-05 06:28:51 +08:00
Glavo c39c19f215 仅在必要时运行 GitHub Action (#2892)
* 仅在必要时运行 GitHub Action

* test

* test

* test

* update
2024-03-05 05:23:34 +08:00
Glavo 88d7493870 更新 GitHub Action 脚本 (#2891)
* update

* update
2024-03-05 05:11:21 +08:00
Glavo 404bc88ec8 使用 GitHub Action 构建 HMCLauncher (#2890)
* 使用 GitHub Action 构建 HMCLauncher

* test

* update

* update

* update

* update
2024-03-05 04:59:30 +08:00
Glavo e2355ca2ff 暂时移除赞助页面 (#2888) 2024-03-05 02:27:16 +08:00
Glavo aab271ac75 添加 GameJavaVersion.JAVA_21 (#2886)
* 将 GameJavaVersion 转换为 enum

* update
2024-03-05 00:35:29 +08:00
Glavo 0da0a1f386 默认不进行降级更新 (#2862)
* 默认不进行降级更新

* update
2024-03-04 16:19:30 +08:00
Glavo 59316a866d Fix #2880: 支持安装带有 NeoForge 的 Modrinth 整合包 (#2881) 2024-03-03 20:37:11 +08:00
zkitefly d3087bd763 更新 README (#2877) 2024-03-03 08:53:20 +08:00
Glavo df7b63c491 更新 README (#2872)
* 更新 README

* 更新 README

* update
2024-03-02 01:29:49 +08:00
Glavo dff893ba4b Fix #2870: 导出脚本时预解析 PreLaunchCommand 与 PostExitCommand (#2871)
* Fix #2870: 导出脚本时预解析 PreLaunchCommand 与 PostExitCommand

* fix checkstyle
2024-03-02 00:01:02 +08:00
Glavo c539702a1b 修复下载 Java 不会尝试备用下载源的问题 (#2869)
* 修复下载 Java 不会尝试备用下载源的问题

* Fix checkstyle

* Fix checkstyle
2024-03-01 21:38:04 +08:00
Glavo 6fad149410 更新 Release Note (#2868)
* 更新 Release Note

* update
2024-03-01 17:01:06 +08:00
42 changed files with 266 additions and 432 deletions

No files matched your search

+4 -6
View File
@@ -8,18 +8,16 @@ body:
attributes:
value: |
提交前请确认:
* 该问题确实是 **HMCL 的错误**,而**不是 Minecraft 非正常退出**,如果你的 Minecraft 非正常退出,请前往 [KOOK 频道](https://kook.top/Kx7n3t) 或 [Discord 频道](https://discord.gg/jVvC7HfM6U) 中获取帮助。
* 该问题确实是 **HMCL 的错误**,而**不是 Minecraft 非正常退出**,如果你的 Minecraft 非正常退出,请前往 [QQ 群](https://docs.hmcl.net/groups.html)/[KOOK 频道](https://kook.top/Kx7n3t)/[Discord 频道](https://discord.gg/jVvC7HfM6U) 中获取帮助。
* 你的启动器版本是**最新的快照版本**,可以点击 [此处](https://github.com/burningtnt/HMCL-Snapshot-Update/raw/master/datas/HMCL-dev.jar) 下载最新快照版本。
如果你的问题并不属于上述两类,你可以选取另一种 Issue 类型,或者直接前往 [KOOK 频道](https://kook.top/Kx7n3t) 或 [Discord 频道](https://discord.gg/jVvC7HfM6U) 中获取帮助。
如果你希望在 QQ 群中反馈问题,请 [赞助 HMCL](https://hmcl.huangyuhui.net/api/redirect/sponsor) 后申请加入群聊,也请将下面的信息表填好直接发在群中,加快我们的沟通速度。
如果你的问题并不属于上述两类,你可以选取另一种 Issue 类型,或者直接前往 [QQ 群](https://docs.hmcl.net/groups.html)/[KOOK 频道](https://kook.top/Kx7n3t)/[Discord 频道](https://discord.gg/jVvC7HfM6U) 中获取帮助。
Before submitting, please confirm:
* The issue is indeed **an error of HMCL**, not **Minecraft abnormal exit**. If your Minecraft exits abnormally, please go to the [KOOK channel](https://kook.top/Kx7n3t) or [Discord channel](https://discord.gg/jVvC7HfM6U) for help.
* The issue is indeed **an error of HMCL**, not **Minecraft abnormal exit**. If your Minecraft exits abnormally, please go to the [QQ group](https://docs.hmcl.net/groups.html) or [KOOK channel](https://kook.top/Kx7n3t) or [Discord channel](https://discord.gg/jVvC7HfM6U) for help.
* Your launcher version is **the latest snapshot version**. You can click [here](https://github.com/burningtnt/HMCL-Snapshot-Update/raw/master/datas/HMCL-dev.jar) to download the latest snapshot version.
If your issue does not fall into the above two categories, you can choose another type of issue or directly go to the [KOOK channel](https://kook.top/Kx7n3t) or [Discord channel](https://discord.gg/jVvC7HfM6U) for help.
If you want to report a problem in the QQ group, please [sponsor HMCL](https://hmcl.huangyuhui.net/api/redirect/sponsor) and apply to join the group chat. Please also fill in the information form below and send it directly in the group to speed up our communication.
If your issue does not fall into the above two categories, you can choose another type of issue or directly go to the [QQ group](https://docs.hmcl.net/groups.html) or [KOOK channel](https://kook.top/Kx7n3t) or [Discord channel](https://discord.gg/jVvC7HfM6U) for help.
- type: input
id: platform
attributes:
+3 -3
View File
@@ -6,9 +6,9 @@ contact_links:
- name: Discord 频道 | Discord Channel
url: https://discord.gg/jVvC7HfM6U
about: Hello Minecraft! Launcher 的官方 Discord 频道。| The official Discord channel of Hello Minecraft! Launcher.
- name: 赞助通道 | Sponsorship channel
url: https://afdian.net/@huanghongxun
about: 前往爱发电赞助 HMCL,赞助后可以申请加入官方 QQ 群反馈问题。| Sponsor Hello Minecraft! Launcher on afdian.net and you can apply to join the official QQ group.
- name: QQ 群 | QQ Groups
url: https://docs.hmcl.net/groups.html
about: Hello Minecraft! Launcher 的官方 QQ 交流群。| The official QQ groups of Hello Minecraft! Laucher.
- name: 其他反馈 | Others
url: https://github.com/HMCL-dev/HMCL/discussions/new/choose
about: 通过 Discussions 反馈其他问题。| Report other problems in Discussions.
+46
View File
@@ -0,0 +1,46 @@
name: Build HMCLauncher
on:
push:
paths:
- 'HMCLauncher/**'
- '.github/workflows/build-launcher.yml'
pull_request:
paths:
- 'HMCLauncher/**'
- '.github/workflows/build-launcher.yml'
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v2
with:
msbuild-architecture: x86
- name: Build HMCLauncher
run: msbuild /p:Configuration=Release /t:Rebuild /verbosity:detailed .\HMCLauncher\
- name: Copy HMCLauncher to assets
run: Copy-Item .\HMCLauncher\Release\HMCLauncher.exe -Destination .\HMCL\src\main\resources\assets\HMCLauncher.exe
- name: Set up JDK 11
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: '11'
java-package: 'jdk+fx'
- name: Build with Gradle
run: .\gradlew makeExecutables --no-daemon
env:
MICROSOFT_AUTH_ID: ${{ secrets.MICROSOFT_AUTH_ID }}
MICROSOFT_AUTH_SECRET: ${{ secrets.MICROSOFT_AUTH_SECRET }}
CURSEFORGE_API_KEY: ${{ secrets.CURSEFORGE_API_KEY }}
- name: Get short SHA
run: echo "SHORT_SHA=$("${{ github.sha }}".SubString(0, 7))" >> $env:GITHUB_ENV
- name: Copy HMCLauncher to libs
run: Copy-Item .\HMCLauncher\Release\HMCLauncher.exe -Destination .\HMCL\build\libs\HMCLauncher.exe
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: HMCLauncher-${{ env.SHORT_SHA }}
path: HMCL/build/libs/*.exe
+11 -7
View File
@@ -1,21 +1,25 @@
name: Check Style
on: [push, pull_request]
on:
push:
paths:
- '**.java'
pull_request:
paths:
- '**.java'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: '11'
java-package: 'jdk+fx'
- name: Check style main
run: ./gradlew checkstyleMain
run: ./gradlew checkstyleMain --no-daemon
- name: Check style test
run: ./gradlew checkstyleTest
run: ./gradlew checkstyleTest --no-daemon
+10 -6
View File
@@ -1,19 +1,23 @@
name: Check Translations
on: [push, pull_request]
on:
push:
paths:
- '**.properties'
pull_request:
paths:
- '**.properties'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: '11'
java-package: 'jdk+fx'
- name: Check style test
run: ./gradlew checkTranslations
run: ./gradlew checkTranslations --no-daemon
+21 -17
View File
@@ -13,7 +13,7 @@ jobs:
if: ${{ github.repository_owner == 'HMCL-dev' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Fetch tags
run: git fetch --all --tags
- name: Install tools
@@ -39,20 +39,24 @@ jobs:
if: ${{ env.continue == 'true' }}
run: |
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.exe"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.exe.sha1"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.exe.sha256"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.jar"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.jar.sha1"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.jar.sha256"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.sh"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.sh.sha1"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.sh.sha256"
env:
DOWNLOAD_BASE_URL: https://ci.huangyuhui.net/job/HMCL/lastSuccessfulBuild/artifact/HMCL/build/libs
- name: Generate release note
if: ${{ env.continue == 'true' }}
run: |
echo "HMCL v$HMCL_VERSION" >> RELEASE_NOTE
echo "" >> RELEASE_NOTE
echo "The full changelogs can be found on the website: https://docs.hmcl.net/changelog/dev.html" >> RELEASE_NOTE
echo "Notice: changelogs are written in Chinese." >> RELEASE_NOTE
echo "" >> RELEASE_NOTE
echo "| File Name | SHA-256 Checksum |" >> RELEASE_NOTE
echo "| --- | --- |" >> RELEASE_NOTE
echo "| HMCL-$HMCL_VERSION.exe | $(cat HMCL-$HMCL_VERSION.exe.sha256) |" >> RELEASE_NOTE
echo "| HMCL-$HMCL_VERSION.jar | $(cat HMCL-$HMCL_VERSION.jar.sha256) |" >> RELEASE_NOTE
echo "| HMCL-$HMCL_VERSION.sh | $(cat HMCL-$HMCL_VERSION.sh.sha256) |" >> RELEASE_NOTE
- name: Create release
if: ${{ env.continue == 'true' }}
uses: softprops/action-gh-release@v1
@@ -60,11 +64,8 @@ jobs:
body_path: RELEASE_NOTE
files: |
HMCL-${{ env.HMCL_VERSION }}.exe
HMCL-${{ env.HMCL_VERSION }}.exe.sha1
HMCL-${{ env.HMCL_VERSION }}.jar
HMCL-${{ env.HMCL_VERSION }}.jar.sha1
HMCL-${{ env.HMCL_VERSION }}.sh
HMCL-${{ env.HMCL_VERSION }}.sh.sha1
target_commitish: ${{ env.HMCL_COMMIT_SHA }}
name: ${{ env.HMCL_TAG_NAME }}
tag_name: ${{ env.HMCL_TAG_NAME }}
@@ -99,21 +100,27 @@ jobs:
if: ${{ env.continue == 'true' }}
run: |
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.exe"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.exe.sha1"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.exe.sha256"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.jar"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.jar.sha1"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.jar.sha256"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.sh"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.sh.sha1"
wget "$DOWNLOAD_BASE_URL/HMCL-$HMCL_VERSION.sh.sha256"
env:
DOWNLOAD_BASE_URL: https://ci.huangyuhui.net/job/HMCL-stable/lastSuccessfulBuild/artifact/HMCL/build/libs
- name: Generate release note
if: ${{ env.continue == 'true' }}
run: |
echo " === **Stable Version** === " >> RELEASE_NOTE
echo "HMCL v$HMCL_VERSION" >> RELEASE_NOTE
echo "**This version is a stable version.**" >> RELEASE_NOTE
echo "" >> RELEASE_NOTE
echo "The full changelogs can be found on the website: https://docs.hmcl.net/changelog/stable.html" >> RELEASE_NOTE
echo "" >> RELEASE_NOTE
echo "Notice: changelogs are written in Chinese." >> RELEASE_NOTE
echo "" >> RELEASE_NOTE
echo "| File Name | SHA-256 Checksum |" >> RELEASE_NOTE
echo "| --- | --- |" >> RELEASE_NOTE
echo "| HMCL-$HMCL_VERSION.exe | $(cat HMCL-$HMCL_VERSION.exe.sha256) |" >> RELEASE_NOTE
echo "| HMCL-$HMCL_VERSION.jar | $(cat HMCL-$HMCL_VERSION.jar.sha256) |" >> RELEASE_NOTE
echo "| HMCL-$HMCL_VERSION.sh | $(cat HMCL-$HMCL_VERSION.sh.sha256) |" >> RELEASE_NOTE
- name: Create release
if: ${{ env.continue == 'true' }}
uses: softprops/action-gh-release@v1
@@ -121,11 +128,8 @@ jobs:
body_path: RELEASE_NOTE
files: |
HMCL-${{ env.HMCL_VERSION }}.exe
HMCL-${{ env.HMCL_VERSION }}.exe.sha1
HMCL-${{ env.HMCL_VERSION }}.jar
HMCL-${{ env.HMCL_VERSION }}.jar.sha1
HMCL-${{ env.HMCL_VERSION }}.sh
HMCL-${{ env.HMCL_VERSION }}.sh.sha1
target_commitish: ${{ env.HMCL_COMMIT_SHA }}
name: ${{ env.HMCL_TAG_NAME }}
tag_name: ${{ env.HMCL_TAG_NAME }}
+10 -5
View File
@@ -1,6 +1,11 @@
name: Java CI
on: [push, pull_request]
on:
push:
pull_request:
paths-ignore:
- '**.md'
- 'HMCLauncher/**'
jobs:
build:
@@ -8,15 +13,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: '11'
java-package: 'jdk+fx'
- name: Build with Gradle
run: ./gradlew build
run: ./gradlew build --no-daemon
env:
MICROSOFT_AUTH_ID: ${{ secrets.MICROSOFT_AUTH_ID }}
MICROSOFT_AUTH_SECRET: ${{ secrets.MICROSOFT_AUTH_SECRET }}
@@ -24,7 +29,7 @@ jobs:
- name: Get short SHA
run: echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
- name: Upload Artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: HMCL-${{ env.SHORT_SHA }}
path: HMCL/build/libs
@@ -33,8 +33,6 @@ import org.jackhuang.hmcl.auth.microsoft.MicrosoftService;
import org.jackhuang.hmcl.auth.offline.OfflineAccount;
import org.jackhuang.hmcl.auth.offline.OfflineAccountFactory;
import org.jackhuang.hmcl.auth.yggdrasil.RemoteAuthenticationException;
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccountFactory;
import org.jackhuang.hmcl.game.OAuthServer;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.util.InvocationDispatcher;
@@ -83,17 +81,15 @@ public final class Accounts {
public static final OAuthServer.Factory OAUTH_CALLBACK = new OAuthServer.Factory();
public static final OfflineAccountFactory FACTORY_OFFLINE = new OfflineAccountFactory(AUTHLIB_INJECTOR_DOWNLOADER);
public static final YggdrasilAccountFactory FACTORY_MOJANG = YggdrasilAccountFactory.MOJANG;
public static final AuthlibInjectorAccountFactory FACTORY_AUTHLIB_INJECTOR = new AuthlibInjectorAccountFactory(AUTHLIB_INJECTOR_DOWNLOADER, Accounts::getOrCreateAuthlibInjectorServer);
public static final MicrosoftAccountFactory FACTORY_MICROSOFT = new MicrosoftAccountFactory(new MicrosoftService(OAUTH_CALLBACK));
public static final List<AccountFactory<?>> FACTORIES = immutableListOf(FACTORY_OFFLINE, FACTORY_MOJANG, FACTORY_MICROSOFT, FACTORY_AUTHLIB_INJECTOR);
public static final List<AccountFactory<?>> FACTORIES = immutableListOf(FACTORY_OFFLINE, FACTORY_MICROSOFT, FACTORY_AUTHLIB_INJECTOR);
// ==== login type / account factory mapping ====
private static final Map<String, AccountFactory<?>> type2factory = new HashMap<>();
private static final Map<AccountFactory<?>, String> factory2type = new HashMap<>();
static {
type2factory.put("offline", FACTORY_OFFLINE);
type2factory.put("yggdrasil", FACTORY_MOJANG);
type2factory.put("authlibInjector", FACTORY_AUTHLIB_INJECTOR);
type2factory.put("microsoft", FACTORY_MICROSOFT);
@@ -126,8 +122,6 @@ public final class Accounts {
return FACTORY_OFFLINE;
else if (account instanceof AuthlibInjectorAccount)
return FACTORY_AUTHLIB_INJECTOR;
else if (account instanceof YggdrasilAccount)
return FACTORY_MOJANG;
else if (account instanceof MicrosoftAccount)
return FACTORY_MICROSOFT;
else
@@ -414,7 +408,6 @@ public final class Accounts {
// ==== Login type name i18n ===
private static final Map<AccountFactory<?>, String> unlocalizedLoginTypeNames = mapOf(
pair(Accounts.FACTORY_OFFLINE, "account.methods.offline"),
pair(Accounts.FACTORY_MOJANG, "account.methods.yggdrasil"),
pair(Accounts.FACTORY_AUTHLIB_INJECTOR, "account.methods.authlib_injector"),
pair(Accounts.FACTORY_MICROSOFT, "account.methods.microsoft"));
@@ -30,6 +30,7 @@ public enum SVG {
GEAR_OUTLINE("M12,8A4,4 0 0,1 16,12A4,4 0 0,1 12,16A4,4 0 0,1 8,12A4,4 0 0,1 12,8M12,10A2,2 0 0,0 10,12A2,2 0 0,0 12,14A2,2 0 0,0 14,12A2,2 0 0,0 12,10M10,22C9.75,22 9.54,21.82 9.5,21.58L9.13,18.93C8.5,18.68 7.96,18.34 7.44,17.94L4.95,18.95C4.73,19.03 4.46,18.95 4.34,18.73L2.34,15.27C2.21,15.05 2.27,14.78 2.46,14.63L4.57,12.97L4.5,12L4.57,11L2.46,9.37C2.27,9.22 2.21,8.95 2.34,8.73L4.34,5.27C4.46,5.05 4.73,4.96 4.95,5.05L7.44,6.05C7.96,5.66 8.5,5.32 9.13,5.07L9.5,2.42C9.54,2.18 9.75,2 10,2H14C14.25,2 14.46,2.18 14.5,2.42L14.87,5.07C15.5,5.32 16.04,5.66 16.56,6.05L19.05,5.05C19.27,4.96 19.54,5.05 19.66,5.27L21.66,8.73C21.79,8.95 21.73,9.22 21.54,9.37L19.43,11L19.5,12L19.43,13L21.54,14.63C21.73,14.78 21.79,15.05 21.66,15.27L19.66,18.73C19.54,18.95 19.27,19.04 19.05,18.95L16.56,17.95C16.04,18.34 15.5,18.68 14.87,18.93L14.5,21.58C14.46,21.82 14.25,22 14,22H10M11.25,4L10.88,6.61C9.68,6.86 8.62,7.5 7.85,8.39L5.44,7.35L4.69,8.65L6.8,10.2C6.4,11.37 6.4,12.64 6.8,13.8L4.68,15.36L5.43,16.66L7.86,15.62C8.63,16.5 9.68,17.14 10.87,17.38L11.24,20H12.76L13.13,17.39C14.32,17.14 15.37,16.5 16.14,15.62L18.57,16.66L19.32,15.36L17.2,13.81C17.6,12.64 17.6,11.37 17.2,10.2L19.31,8.65L18.56,7.35L16.15,8.39C15.38,7.5 14.32,6.86 13.12,6.62L12.75,4H11.25Z"),
BACK("M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z"),
CANCEL("M12 2C17.5 2 22 6.5 22 12S17.5 22 12 22 2 17.5 2 12 6.5 2 12 2M12 4C10.1 4 8.4 4.6 7.1 5.7L18.3 16.9C19.3 15.5 20 13.8 20 12C20 7.6 16.4 4 12 4M16.9 18.3L5.7 7.1C4.6 8.4 4 10.1 4 12C4 16.4 7.6 20 12 20C13.9 20 15.6 19.4 16.9 18.3Z"),
CHAT("M20,2A2,2 0 0,1 22,4V16A2,2 0 0,1 20,18H6L2,22V4C2,2.89 2.9,2 4,2H20M4,4V17.17L5.17,16H20V4H4M6,7H18V9H6V7M6,11H15V13H6V11Z"),
CLOSE("M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z"),
COPY("M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"),
DOTS_VERTICAL("M12,16A2,2 0 0,1 14,18A2,2 0 0,1 12,20A2,2 0 0,1 10,18A2,2 0 0,1 12,16M12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12A2,2 0 0,1 12,10M12,4A2,2 0 0,1 14,6A2,2 0 0,1 12,8A2,2 0 0,1 10,6A2,2 0 0,1 12,4Z"),
@@ -120,19 +120,15 @@ public class AccountListItem extends RadioButton {
}
public ObservableBooleanValue canUploadSkin() {
if (account instanceof YggdrasilAccount) {
if (account instanceof AuthlibInjectorAccount) {
AuthlibInjectorAccount aiAccount = (AuthlibInjectorAccount) account;
ObjectBinding<Optional<CompleteGameProfile>> profile = aiAccount.getYggdrasilService().getProfileRepository().binding(aiAccount.getUUID());
return createBooleanBinding(() -> {
Set<TextureType> uploadableTextures = profile.get()
.map(AuthlibInjectorAccount::getUploadableTextures)
.orElse(emptySet());
return uploadableTextures.contains(TextureType.SKIN);
}, profile);
} else {
return createBooleanBinding(() -> true);
}
if (account instanceof AuthlibInjectorAccount) {
AuthlibInjectorAccount aiAccount = (AuthlibInjectorAccount) account;
ObjectBinding<Optional<CompleteGameProfile>> profile = aiAccount.getYggdrasilService().getProfileRepository().binding(aiAccount.getUUID());
return createBooleanBinding(() -> {
Set<TextureType> uploadableTextures = profile.get()
.map(AuthlibInjectorAccount::getUploadableTextures)
.orElse(emptySet());
return uploadableTextures.contains(TextureType.SKIN);
}, profile);
} else if (account instanceof OfflineAccount || account instanceof MicrosoftAccount) {
return createBooleanBinding(() -> true);
} else {
@@ -107,14 +107,6 @@ public class AccountListPage extends DecoratorAnimatedPage implements DecoratorP
offlineItem.setOnAction(e -> Controllers.dialog(new CreateAccountPane(Accounts.FACTORY_OFFLINE)));
boxMethods.getChildren().add(offlineItem);
AdvancedListItem mojangItem = new AdvancedListItem();
mojangItem.getStyleClass().add("navigation-drawer-item");
mojangItem.setActionButtonVisible(false);
mojangItem.setTitle(i18n("account.methods.yggdrasil"));
mojangItem.setLeftGraphic(wrap(SVG.MOJANG));
mojangItem.setOnAction(e -> Controllers.dialog(new CreateAccountPane(Accounts.FACTORY_MOJANG)));
boxMethods.getChildren().add(mojangItem);
AdvancedListItem microsoftItem = new AdvancedListItem();
microsoftItem.getStyleClass().add("navigation-drawer-item");
microsoftItem.setActionButtonVisible(false);
@@ -24,20 +24,15 @@ import com.jfoenix.controls.JFXProgressBar;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import org.jackhuang.hmcl.auth.AuthInfo;
import org.jackhuang.hmcl.auth.ClassicAccount;
import org.jackhuang.hmcl.auth.NoSelectedCharacterException;
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorAccount;
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilService;
import org.jackhuang.hmcl.setting.Accounts;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
import org.jackhuang.hmcl.ui.construct.JFXHyperlink;
import org.jackhuang.hmcl.ui.construct.RequiredValidator;
import java.util.function.Consumer;
@@ -84,20 +79,6 @@ public class ClassicAccountLoginDialog extends StackPane {
txtPassword.setPromptText(i18n("account.password"));
body.getChildren().setAll(usernameLabel, txtPassword);
if (oldAccount instanceof YggdrasilAccount && !(oldAccount instanceof AuthlibInjectorAccount)) {
HBox linkPane = new HBox(8);
body.getChildren().add(linkPane);
JFXHyperlink migrationLink = new JFXHyperlink(i18n("account.methods.yggdrasil.migration"));
migrationLink.setExternalLink(YggdrasilService.PROFILE_URL);
JFXHyperlink migrationHowLink = new JFXHyperlink(i18n("account.methods.yggdrasil.migration.how"));
migrationHowLink.setExternalLink(YggdrasilService.MIGRATION_FAQ_URL);
linkPane.getChildren().setAll(migrationLink, migrationHowLink);
}
dialogLayout.setBody(body);
}
@@ -44,7 +44,6 @@ import org.jackhuang.hmcl.auth.authlibinjector.BoundAuthlibInjectorAccountFactor
import org.jackhuang.hmcl.auth.microsoft.MicrosoftAccountFactory;
import org.jackhuang.hmcl.auth.offline.OfflineAccountFactory;
import org.jackhuang.hmcl.auth.yggdrasil.GameProfile;
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccountFactory;
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilService;
import org.jackhuang.hmcl.game.OAuthServer;
import org.jackhuang.hmcl.game.TexturesLoader;
@@ -312,7 +311,7 @@ public class CreateAccountPane extends JFXDialogLayout implements DialogAware {
birthLink.setExternalLink("https://support.microsoft.com/account-billing/837badbc-999e-54d2-2617-d19206b9540a");
JFXHyperlink profileLink = new JFXHyperlink(i18n("account.methods.microsoft.profile"));
profileLink.setExternalLink("https://account.live.com/editprof.aspx");
JFXHyperlink purchaseLink = new JFXHyperlink(i18n("account.methods.yggdrasil.purchase"));
JFXHyperlink purchaseLink = new JFXHyperlink(i18n("account.methods.microsoft.purchase"));
purchaseLink.setExternalLink(YggdrasilService.PURCHASE_URL);
JFXHyperlink deauthorizeLink = new JFXHyperlink(i18n("account.methods.microsoft.deauthorize"));
deauthorizeLink.setExternalLink("https://account.live.com/consent/Edit?client_id=000000004C794E0A");
@@ -344,24 +343,6 @@ public class CreateAccountPane extends JFXDialogLayout implements DialogAware {
}
detailsPane = vbox;
} else if (factory == Accounts.FACTORY_MOJANG) {
VBox vbox = new VBox(8);
HintPane hintPane = new HintPane(MessageDialogPane.MessageType.WARNING);
hintPane.setText(i18n("account.methods.yggdrasil.migration.hint"));
HBox linkPane = new HBox(8);
JFXHyperlink migrationLink = new JFXHyperlink(i18n("account.methods.yggdrasil.migration"));
migrationLink.setOnAction(e -> FXUtils.openLink(YggdrasilService.PROFILE_URL));
JFXHyperlink migrationHowLink = new JFXHyperlink(i18n("account.methods.yggdrasil.migration.how"));
migrationHowLink.setOnAction(e -> FXUtils.openLink(YggdrasilService.MIGRATION_FAQ_URL));
linkPane.getChildren().setAll(migrationLink, migrationHowLink);
vbox.getChildren().setAll(hintPane, linkPane);
detailsPane = vbox;
btnAccept.setDisable(true);
} else {
detailsPane = new AccountDetailsInputPane(factory, btnAccept::fire);
btnAccept.disableProperty().bind(((AccountDetailsInputPane) detailsPane).validProperty().not());
@@ -526,30 +507,11 @@ public class CreateAccountPane extends JFXDialogLayout implements DialogAware {
rowIndex++;
}
if (factory instanceof YggdrasilAccountFactory) {
HBox box = new HBox();
GridPane.setColumnSpan(box, 2);
JFXHyperlink migrationLink = new JFXHyperlink(i18n("account.methods.yggdrasil.migration"));
migrationLink.setExternalLink("https://aka.ms/MinecraftMigration");
JFXHyperlink migrationHowLink = new JFXHyperlink(i18n("account.methods.yggdrasil.migration.how"));
migrationHowLink.setExternalLink("https://help.minecraft.net/hc/articles/4411173197709");
JFXHyperlink purchaseLink = new JFXHyperlink(i18n("account.methods.yggdrasil.purchase"));
purchaseLink.setExternalLink(YggdrasilService.PURCHASE_URL);
box.getChildren().setAll(migrationLink, migrationHowLink, purchaseLink);
add(box, 0, rowIndex);
rowIndex++;
}
if (factory instanceof OfflineAccountFactory) {
txtUsername.setPromptText(i18n("account.methods.offline.name.special_characters"));
runInFX(() -> FXUtils.installFastTooltip(txtUsername, i18n("account.methods.offline.name.special_characters")));
JFXHyperlink purchaseLink = new JFXHyperlink(i18n("account.methods.yggdrasil.purchase"));
JFXHyperlink purchaseLink = new JFXHyperlink(i18n("account.methods.microsoft.purchase"));
purchaseLink.setExternalLink(YggdrasilService.PURCHASE_URL);
HBox linkPane = new HBox(purchaseLink);
GridPane.setColumnSpan(linkPane, 2);
@@ -620,9 +582,7 @@ public class CreateAccountPane extends JFXDialogLayout implements DialogAware {
}
private boolean requiresEmailAsUsername() {
if (factory instanceof YggdrasilAccountFactory) {
return true;
} else if ((factory instanceof AuthlibInjectorAccountFactory) && this.server != null) {
if ((factory instanceof AuthlibInjectorAccountFactory) && this.server != null) {
return !server.isNonEmailLogin();
}
return false;
@@ -70,7 +70,7 @@ public class OAuthAccountLoginDialog extends DialogPane {
birthLink.setOnAction(e -> FXUtils.openLink("https://support.microsoft.com/account-billing/how-to-change-a-birth-date-on-a-microsoft-account-837badbc-999e-54d2-2617-d19206b9540a"));
JFXHyperlink profileLink = new JFXHyperlink(i18n("account.methods.microsoft.profile"));
profileLink.setOnAction(e -> FXUtils.openLink("https://account.live.com/editprof.aspx"));
JFXHyperlink purchaseLink = new JFXHyperlink(i18n("account.methods.yggdrasil.purchase"));
JFXHyperlink purchaseLink = new JFXHyperlink(i18n("account.methods.microsoft.purchase"));
purchaseLink.setOnAction(e -> FXUtils.openLink(YggdrasilService.PURCHASE_URL));
box.getChildren().setAll(profileLink, birthLink, purchaseLink);
GridPane.setColumnSpan(box, 2);
@@ -42,10 +42,10 @@ public class FeedbackPage extends SpinnerPane {
ComponentList community = new ComponentList();
{
IconedTwoLineListItem users = new IconedTwoLineListItem();
users.setImage(FXUtils.newBuiltinImage("/assets/img/craft_table.png"));
users.setImage(FXUtils.newBuiltinImage("/assets/img/icon.png"));
users.setTitle(i18n("feedback.qq_group"));
users.setSubtitle(i18n("feedback.qq_group.statement"));
users.setExternalLink("https://hmcl.huangyuhui.net/api/redirect/sponsor");
users.setExternalLink("https://docs.hmcl.net/groups.html");
IconedTwoLineListItem github = new IconedTwoLineListItem();
github.setImage(FXUtils.newBuiltinImage("/assets/img/github.png"));
@@ -46,7 +46,6 @@ public class LauncherSettingsPage extends DecoratorAnimatedPage implements Decor
private final TabHeader.Tab<HelpPage> helpTab = new TabHeader.Tab<>("helpPage");
private final TabHeader.Tab<AboutPage> aboutTab = new TabHeader.Tab<>("aboutPage");
private final TabHeader.Tab<FeedbackPage> feedbackTab = new TabHeader.Tab<>("feedbackPage");
private final TabHeader.Tab<SponsorPage> sponsorTab = new TabHeader.Tab<>("sponsorPage");
private final TransitionPane transitionPane = new TransitionPane();
public LauncherSettingsPage() {
@@ -56,9 +55,8 @@ public class LauncherSettingsPage extends DecoratorAnimatedPage implements Decor
downloadTab.setNodeSupplier(DownloadSettingsPage::new);
helpTab.setNodeSupplier(HelpPage::new);
feedbackTab.setNodeSupplier(FeedbackPage::new);
sponsorTab.setNodeSupplier(SponsorPage::new);
aboutTab.setNodeSupplier(AboutPage::new);
tab = new TabHeader(gameTab, settingsTab, personalizationTab, downloadTab, helpTab, feedbackTab, sponsorTab, aboutTab);
tab = new TabHeader(gameTab, settingsTab, personalizationTab, downloadTab, helpTab, feedbackTab, aboutTab);
tab.select(gameTab);
gameTab.initializeIfNeeded();
@@ -108,12 +106,6 @@ public class LauncherSettingsPage extends DecoratorAnimatedPage implements Decor
feedbackItem.activeProperty().bind(tab.getSelectionModel().selectedItemProperty().isEqualTo(feedbackTab));
feedbackItem.setOnAction(e -> tab.select(feedbackTab));
})
.addNavigationDrawerItem(sponsorItem -> {
sponsorItem.setTitle(i18n("sponsor"));
sponsorItem.setLeftGraphic(wrap(SVG.HAND_HEAR_OUTLINE));
sponsorItem.activeProperty().bind(tab.getSelectionModel().selectedItemProperty().isEqualTo(sponsorTab));
sponsorItem.setOnAction(e -> tab.select(sponsorTab));
})
.addNavigationDrawerItem(aboutItem -> {
aboutItem.setTitle(i18n("about"));
aboutItem.setLeftGraphic(wrap(SVG.INFORMATION_OUTLINE));
@@ -34,7 +34,6 @@ import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.account.AccountAdvancedListItem;
import org.jackhuang.hmcl.ui.construct.AdvancedListBox;
import org.jackhuang.hmcl.ui.construct.AdvancedListItem;
import org.jackhuang.hmcl.ui.construct.JFXHyperlink;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
import org.jackhuang.hmcl.ui.decorator.DecoratorAnimatedPage;
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
@@ -170,25 +169,19 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
runInFX(() -> FXUtils.installFastTooltip(downloadItem, i18n("download.hint")));
// fifth item in left sidebar
AdvancedListItem multiplayerItem = new AdvancedListItem();
multiplayerItem.setLeftGraphic(wrap(SVG.LAN));
multiplayerItem.setActionButtonVisible(false);
multiplayerItem.setTitle(i18n("multiplayer"));
JFXHyperlink link = new JFXHyperlink(i18n("multiplayer.hint.details"));
link.setExternalLink("https://hmcl.huangyuhui.net/api/redirect/multiplayer-migrate");
multiplayerItem.setOnAction(e -> Controllers.dialog(
new MessageDialogPane.Builder(i18n("multiplayer.hint"), null, MessageDialogPane.MessageType.INFO)
.addAction(link)
.ok(null)
.build()));
// sixth item in left sidebar
AdvancedListItem launcherSettingsItem = new AdvancedListItem();
launcherSettingsItem.setLeftGraphic(wrap(SVG.GEAR_OUTLINE));
launcherSettingsItem.setActionButtonVisible(false);
launcherSettingsItem.setTitle(i18n("settings"));
launcherSettingsItem.setOnAction(e -> Controllers.navigate(Controllers.getSettingsPage()));
// sixth item in left sidebar
AdvancedListItem chatItem = new AdvancedListItem();
chatItem.setLeftGraphic(wrap(SVG.CHAT));
chatItem.setActionButtonVisible(false);
chatItem.setTitle(i18n("chat"));
chatItem.setOnAction(e -> FXUtils.openLink("https://docs.hmcl.net/groups.html"));
// the left sidebar
AdvancedListBox sideBar = new AdvancedListBox()
.startCategory(i18n("account").toUpperCase(Locale.ROOT))
@@ -198,8 +191,9 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
.add(gameItem)
.add(downloadItem)
.startCategory(i18n("settings.launcher.general").toUpperCase(Locale.ROOT))
.add(multiplayerItem)
.add(launcherSettingsItem);
.add(launcherSettingsItem)
.add(chatItem)
;
// the root page, with the sidebar in left, navigator in center.
setLeft(sideBar);
@@ -38,10 +38,11 @@ public class RemoteVersion {
String jarHash = Optional.ofNullable(response.get("jarsha1")).map(JsonElement::getAsString).orElse(null);
String packXZUrl = Optional.ofNullable(response.get("packxz")).map(JsonElement::getAsString).orElse(null);
String packXZHash = Optional.ofNullable(response.get("packxzsha1")).map(JsonElement::getAsString).orElse(null);
boolean force = Optional.ofNullable(response.get("force")).map(JsonElement::getAsBoolean).orElse(false);
if (Pack200Utils.isSupported() && packXZUrl != null && packXZHash != null) {
return new RemoteVersion(channel, version, packXZUrl, Type.PACK_XZ, new IntegrityCheck("SHA-1", packXZHash));
return new RemoteVersion(channel, version, packXZUrl, Type.PACK_XZ, new IntegrityCheck("SHA-1", packXZHash), force);
} else if (jarUrl != null && jarHash != null) {
return new RemoteVersion(channel, version, jarUrl, Type.JAR, new IntegrityCheck("SHA-1", jarHash));
return new RemoteVersion(channel, version, jarUrl, Type.JAR, new IntegrityCheck("SHA-1", jarHash), force);
} else {
throw new IOException("No download url is available");
}
@@ -55,13 +56,15 @@ public class RemoteVersion {
private final String url;
private final Type type;
private final IntegrityCheck integrityCheck;
private final boolean force;
public RemoteVersion(UpdateChannel channel, String version, String url, Type type, IntegrityCheck integrityCheck) {
public RemoteVersion(UpdateChannel channel, String version, String url, Type type, IntegrityCheck integrityCheck, boolean force) {
this.channel = channel;
this.version = version;
this.url = url;
this.type = type;
this.integrityCheck = integrityCheck;
this.force = force;
}
public UpdateChannel getChannel() {
@@ -84,6 +87,10 @@ public class RemoteVersion {
return integrityCheck;
}
public boolean isForce() {
return force;
}
@Override
public String toString() {
return "[" + version + " from " + url + "]";
@@ -24,6 +24,7 @@ import javafx.beans.property.*;
import javafx.beans.value.ObservableBooleanValue;
import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.util.io.NetworkUtils;
import org.jackhuang.hmcl.util.versioning.VersionNumber;
import java.io.IOException;
import java.util.logging.Level;
@@ -42,10 +43,13 @@ public final class UpdateChecker {
RemoteVersion latest = latestVersion.get();
if (latest == null || isDevelopmentVersion(Metadata.VERSION)) {
return false;
} else {
// We can update from development version to stable version,
// which can be downgrading.
} else if (latest.isForce()
|| Metadata.isNightly()
|| latest.getChannel() == UpdateChannel.NIGHTLY
|| latest.getChannel() != UpdateChannel.getChannel()) {
return !latest.getVersion().equals(Metadata.VERSION);
} else {
return VersionNumber.compare(Metadata.VERSION, latest.getVersion()) < 0;
}
},
latestVersion);
@@ -53,7 +53,6 @@ account.character=character
account.choose=Choose a Character
account.create=Add an account
account.create.microsoft=Add a Microsoft account
account.create.yggdrasil=Add a Mojang account
account.create.offline=Add an offline account
account.create.authlibInjector=Create an authlib-injector account
account.email=Email
@@ -117,6 +116,7 @@ If the token used to log in to the Microsoft account is leaked, you can click on
If you encounter any problems, you can click the help button in the upper right corner for help.
account.methods.microsoft.makegameidsettings=Create Profile / Edit Profile Name
account.methods.microsoft.profile=Account Profile
account.methods.microsoft.purchase=Buy Minecraft
account.methods.microsoft.snapshot=You are using an unofficial build of HMCL. Please download the official build for login.
account.methods.microsoft.snapshot.website=Official Website
account.methods.offline=Offline
@@ -130,14 +130,7 @@ account.methods.offline.uuid.hint=UUID is the unique identifier for the game cha
\n\
This option is for advanced users only. We do not recommend modifying this option unless you know what you are doing.
account.methods.offline.uuid.malformed=Invalid Format
account.methods.yggdrasil=Mojang
account.methods.forgot_password=Forgot Password
account.methods.yggdrasil.migration=Migrate to Microsoft Account
account.methods.yggdrasil.migration.how=How to migrate to Microsoft Account?
account.methods.yggdrasil.migration.hint=Since March 10, 2022, Mojang accounts are no longer supported, and you are required to migrate to a Microsoft account in order to play Minecraft.\n\
\n\
The link down below will guide you to migrate your Mojang account to a Microsoft account.
account.methods.yggdrasil.purchase=Buy Minecraft
account.missing=No Accounts
account.missing.add=Click here to add one.
account.move_to_global=Convert to global account
@@ -190,6 +183,8 @@ button.save_as=Save As
button.select_all=Select All
button.yes=Yes
chat=QQ Groups
color.recent=Recommended
color.custom=Custom Color
crash.NoClassDefFound=Please verify the integrity of this software, or try updating your Java.
@@ -404,7 +399,7 @@ feedback.github.statement=Creating an issue on GitHub.
feedback.kookapp=KOOK
feedback.kookapp.statement=Join our KOOK community.
feedback.qq_group=HMCL User Group
feedback.qq_group.statement=Join HMCL user QQ group through donation.
feedback.qq_group.statement=Join HMCL user QQ group.
file=File
@@ -575,7 +570,7 @@ If you still encounter these problems, you may need a better computer.
game.crash.reason.resolution_too_high=The game crashed because you are using a resource pack whose texture resolution was too high.\n\
\n\
You should switch to a resource pack with lower resolution, or consider buying a better graphics card with more VRAM.
game.crash.reason.processing_of_javaagent_failed=The current game crashed because processing of -javaagent failed.\nIf you add relevant parameters to the Java virtual machine parameters, please check whether they are legal and correct.\nIf you do not add relevant parameters or confirm that they are legal and correct, Please try:\nOpen the control panel -- Clock and region classification (this option is only available if the option is category display, and it will be skipped if not) -- Region -- the upper management tab -- the lower change system regional setting button -- turn off the "Use Unicode UTF-8 to provide global language support" option in the pop-up window, restart the device, and then try to start the game.\nYou can be accessed in <a href="https://discord.gg/jVvC7HfM6U">Discard</a> or <a href="https://kook.top/Kx7n3t">KOOK</a> ask for help.
game.crash.reason.processing_of_javaagent_failed=The current game crashed because processing of -javaagent failed.\nIf you add relevant parameters to the Java virtual machine parameters, please check whether they are legal and correct.\nIf you do not add relevant parameters or confirm that they are legal and correct, Please try:\nOpen the control panel -- Clock and region classification (this option is only available if the option is category display, and it will be skipped if not) -- Region -- the upper management tab -- the lower change system regional setting button -- turn off the "Use Unicode UTF-8 to provide global language support" option in the pop-up window, restart the device, and then try to start the game.\nYou can be accessed in <a href="https://discord.gg/jVvC7HfM6U">Discard</a> or <a href="https://docs.hmcl.net/groups.html">QQ</a> ask for help.
game.crash.reason.stacktrace=The crash reason is unknown. You can view its details by clicking the "Logs" button.\n\
\n\
There are some keywords that might contain some Mod Names. You can search them online to figure out the issue yourself.\n\
@@ -735,7 +730,7 @@ logwindow.export_game_crash_logs=Export Crash Logs
logwindow.export_dump.dependency_ok.button=Export Game Stack Dump
logwindow.export_dump.dependency_ok.doing_button=Exporting Game Stack Dump (May take up to 15 seconds)
logwindow.export_dump.no_dependency.button=Export Game Stack Dump (Not compatible)
logwindow.export_dump.no_dependency.tooltip=Your Java does not contain the dependencies to create the stack dump. Please turn to HMCL KOOK or HMCL Discord for help.
logwindow.export_dump.no_dependency.tooltip=Your Java does not contain the dependencies to create the stack dump. Please turn to HMCL QQ group or HMCL Discord for help.
main_page=Home
@@ -913,10 +908,6 @@ mods.restore=Rollback
mods.url=Official Page
mods.update_modpack_mod.warning=Updating mods in a modpack can lead to irreparable results, possibly corrupting the modpack so that it cannot start. Are you sure you want to update?
multiplayer=Multiplayer online
multiplayer.hint=Multiplayer online function is under maintenance.
multiplayer.hint.details=View details
nbt.entries=%s entries
nbt.open.failed=Fail to open file
nbt.save.failed=Fail to save file
@@ -1184,14 +1175,14 @@ update.changelog=Changelog
update.channel.dev=Beta
update.channel.dev.hint=You are currently using a beta build of the launcher, which may include some extra features, but is also sometimes more unstable than the release versions.\n\
\n\
If you encounter any bug or issue, you can go to <a href="hmcl://settings/feedback">the feedback page</a> to report it, or tell us in our <a href="https://discord.gg/jVvC7HfM6U">Discord</a> or <a href="https://kook.top/Kx7n3t">KOOK</a> community.\n\
If you encounter any bug or issue, you can go to <a href="hmcl://settings/feedback">the feedback page</a> to report it, or tell us in our <a href="https://discord.gg/jVvC7HfM6U">Discord</a> or <a href="https://docs.hmcl.net/groups.html">QQ</a> community.\n\
\n\
<a href="hmcl://hide-announcement">Click here</a> to hide this tooltip for the current version.
update.channel.dev.title=Beta Version Notice
update.channel.nightly=Nightly
update.channel.nightly.hint=You are currently using a nightly build of the launcher, which may include some extra features, but is also always more unstable than the other versions.\n\
\n\
If you encounter any bug or issue, you can go to <a href="hmcl://settings/feedback">the feedback page</a> to report it, or tell us in our <a href="https://discord.gg/jVvC7HfM6U">Discord</a> or <a href="https://kook.top/Kx7n3t">KOOK</a> community.
If you encounter any bug or issue, you can go to <a href="hmcl://settings/feedback">the feedback page</a> to report it, or tell us in our <a href="https://discord.gg/jVvC7HfM6U">Discord</a> or <a href="https://docs.hmcl.net/groups.html">QQ</a> community.
update.channel.nightly.title=Nightly Version Notice
update.channel.stable=Release
update.checking=Checking for Updates
@@ -53,7 +53,6 @@ account.character=personaje
account.choose=Elige un personaje
account.create=Añadir una cuenta
account.create.microsoft=Añadir una cuenta Microsoft
account.create.yggdrasil=Añadir una cuenta de Mojang
account.create.offline=Añadir una cuenta offline
account.create.authlibInjector=Crear una cuenta authlib-injector
account.email=Correo electrónico
@@ -109,6 +108,7 @@ account.methods.microsoft.manual=El código de su dispositivo es <b>%1$s</b>, po
Si el token utilizado para acceder a la cuenta de Microsoft se ha filtrado, puedes hacer clic en "Desautorizar la cuenta" para desautorizarla.\n\
Si encuentra algún problema, puede hacer clic en el botón de ayuda en la esquina superior derecha para obtener ayuda.
account.methods.microsoft.profile=Perfil de la cuenta
account.methods.microsoft.purchase=Comprar Minecraft
account.methods.microsoft.snapshot=Estás usando una construcción no oficial de hmcls, por favor descargue la construcción oficial para iniciar sesión en microsoft.
account.methods.offline=Sin conexión
account.methods.offline.uuid=UUID
@@ -117,14 +117,7 @@ account.methods.offline.uuid.hint=UUID es el identificador único del personaje
Esta opción es sólo para usuarios avanzados. No recomendamos modificar esta opción a menos que sepas lo que estás haciendo.\n\
Esta opción no es necesaria para unirse a servidores.
account.methods.offline.uuid.malformed=Formato no válido
account.methods.yggdrasil=Mojang
account.methods.forgot_password=OLVIDÉ MI CONTRASEÑA
account.methods.yggdrasil.migration=Migrar a cuenta Microsoft
account.methods.yggdrasil.migration.how=¿Cómo migrar a la Cuenta Microsoft?
account.methods.yggdrasil.migration.hint=Desde el 10 de marzo de 2022, las cuentas de Mojang ya no son compatibles, y es necesario migrar a una cuenta de Microsoft para poder jugar a Minecraft.\n
\n\
El enlace de abajo te guiará para migrar tu cuenta de Mojang a una cuenta de Microsoft.
account.methods.yggdrasil.purchase=Comprar Minecraft
account.missing=No hay cuentas
account.missing.add=Haz clic aquí para añadir una.
account.not_logged_in=No ha iniciado sesión
@@ -696,7 +689,7 @@ logwindow.export_game_crash_logs=Exportar registros de errores
logwindow.export_dump.dependency_ok.button=Exportar volcado de pila de juegos
logwindow.export_dump.dependency_ok.doing_button=Exportación de volcado de pila de juego (puede tardar hasta 15 segundos)
logwindow.export_dump.no_dependency.button=Exportar volcado de pila de juegos (no compatible)
logwindow.export_dump.no_dependency.tooltip=Su Java no contiene las dependencias para crear el volcado de pila. Dirígete a HMCL KOOK o HMCL Discord para obtener ayuda.
logwindow.export_dump.no_dependency.tooltip=Su Java no contiene las dependencias para crear el volcado de pila. Dirígete a HMCL QQ o HMCL Discord para obtener ayuda.
main_page=Inicio
@@ -845,8 +838,6 @@ mods.restore=Restaurar
mods.url=Página oficial
mods.update_modpack_mod.warning=Actualizar mods en un modpack puede generar resultados irreparables, posiblemente corrompiendo el modpack para que no pueda iniciarse. ¿Seguro que quieres actualizar?
multiplayer=Multijugador
datapack=Datapacks
datapack.add=Instalar datapacks
datapack.choose_datapack=Seleccionar un paquet de datos para importar
@@ -1061,14 +1052,14 @@ update.changelog=Registro de cambios
update.channel.dev=Beta
update.channel.dev.hint=Actualmente está utilizando una versión beta del launcher, que puede incluir algunas características adicionales, pero también es más inestable que las versiones de lanzamiento.\n\
\n\
Si encuentra algún error o problema, puede ir a la <a href="hmcl://settings/feedback">página de comentarios</a> para informar de ello, o bien para decírnoslo en nuestro <a href="https://discord.gg/jVvC7HfM6U">Discord</a> o en la comunidad <a href="https://kookapp.co/Kx7n3t">KOOK</a>.\n\
Si encuentra algún error o problema, puede ir a la <a href="hmcl://settings/feedback">página de comentarios</a> para informar de ello, o bien para decírnoslo en nuestro <a href="https://discord.gg/jVvC7HfM6U">Discord</a> o en la comunidad <a href="https://docs.hmcl.net/groups.html">QQ</a>.\n\
\n\
<a href="hmcl://hide-announcement">Haga clic aquí</a> para ocultar el recordatorio para la versión de prueba actual.
update.channel.dev.title=Aviso de versión beta
update.channel.nightly=Nocturna
update.channel.nightly.hint=Estás utilizando una versión nocturna del launcher, que puede incluir algunas características adicionales, pero también es siempre más inestable que las otras versiones.\n\
\n\
Si encuentra algún error o problema, puede ir a la <a href="hmcl://settings/feedback">página de comentarios</a> para informar de ello, o bien para decírnoslo en nuestro <a href="https://discord.gg/jVvC7HfM6U">Discord</a> o en la comunidad <a href="https://kookapp.co/Kx7n3t">KOOK</a> community.
Si encuentra algún error o problema, puede ir a la <a href="hmcl://settings/feedback">página de comentarios</a> para informar de ello, o bien para decírnoslo en nuestro <a href="https://discord.gg/jVvC7HfM6U">Discord</a> o en la comunidad <a href="https://docs.hmcl.net/groups.html">QQ</a> community.
update.channel.nightly.title=Aviso de versión nocturna
update.channel.stable=Estable
update.checking=Buscando actualizaciones
@@ -51,7 +51,6 @@ account.character=キャラクター
account.choose=キャラクターを選択する
account.create=アカウントを追加
account.create.microsoft=Microsoft Login
account.create.yggdrasil=Mojang Login
account.create.offline=Offline
account.create.authlibInjector=サードパーティーアカウントを追加
account.email=メールアドレス
@@ -100,15 +99,12 @@ account.methods.microsoft.makegameidsettings=プロファイルを作成/プロ
account.methods.microsoft.hint=「ログイン」ボタンをクリックして、新しく開いたブラウザウィンドウでログインプロセスを続行する必要があります。\nMicrosoftアカウントへのログインに使用されたトークンが誤って漏洩した場合は、下の[アカウントのバインドを解除]をクリックして、ログイン認証をキャンセルできます。\n問題が発生した場合は、右上隅にあるヘルプ ボタンをクリックするとヘルプが表示されます。
account.methods.microsoft.manual=「ログイン」ボタンをクリックした後、新しく開いたブラウザウィンドウで認証を完了する必要があります。ブラウザウィンドウが表示されない場合は、ここをクリックしてURLをコピーし、ブラウザで手動で開くことができます。\nMicrosoftアカウントへのログインに使用されたトークンが誤って漏洩した場合は、下の[アカウントのバインドを解除]をクリックして、ログイン認証をキャンセルできます。\n問題が発生した場合は、右上隅にあるヘルプ ボタンをクリックするとヘルプが表示されます。
account.methods.microsoft.profile=アカウントプロファイル..
account.methods.microsoft.purchase=Minecraftを購入する
account.methods.microsoft.snapshot=非公式構築 HMCL を使用しているので、公式構築をダウンロードしてマイクロソフトにログインしてください。
account.methods.offline=オフライン
account.methods.offline.uuid=UUID
account.methods.offline.uuid.hint=UUIDは、Minecraftのゲームキャラクターの一意の識別子です。UUIDの生成方法は、ゲームランチャーによって異なります。UUIDを他のランチャーによって生成されたものに変更すると、オフラインアカウントのバックパック内のゲームブロック/アイテムが残ることが約束されます。このオプションは専門家向けです。何をしているのかわからない限り、このオプションを変更することはお勧めしません。\nこのオプションはサーバーに参加する場合には必要ありません。
account.methods.offline.uuid.malformed=Malformed
account.methods.yggdrasil=Mojang
account.methods.yggdrasil.migration=Microsoftアカウントに移行する
account.methods.yggdrasil.migration.how=Microsoftアカウントに移行する方法は?
account.methods.yggdrasil.purchase=Minecraftを購入する
account.missing=アカウントなし
account.missing.add=追加するにはここをクリック
account.not_logged_in=ログインしていません
@@ -664,8 +660,6 @@ mods.restore=Restore
mods.url=公式ページ
mods.update_modpack_mod.warning=modpack 内の mod を更新すると、修復不可能な結果につながる可能性があり、modpack が破損して起動できなくなる可能性があります。更新してもよろしいですか?
multiplayer=マルチプレイ
datapack=Datapacks
datapack.add=データパックをインストールします
datapack.choose_datapack=インポートするデータパックのzipを選択してください
@@ -873,7 +867,7 @@ update.changelog=変更
update.channel.dev=ベータ
update.channel.dev.hint=ベータ版を使用しています。ベータ版には、リリースバージョンと比較していくつかの追加機能が含まれている可能性があり、テストにのみ使用されます。\n\
ベータ版は不安定なはずです!\n\
問題が発生した場合は、<a href="hmcl://settings/feedback">フィードバックページ</a>にアクセスして報告するか、チャット <a href="https://discord.gg/jVvC7HfM6U">Discord</a>または<a href="https://kook.top/Kx7n3t">KOOK</a>で問題を報告します。\n\n\
問題が発生した場合は、<a href="hmcl://settings/feedback">フィードバックページ</a>にアクセスして報告するか、チャット <a href="https://discord.gg/jVvC7HfM6U">Discord</a>または<a href="https://docs.hmcl.net/groups.html">QQ</a>で問題を報告します。\n\n\
現在のテスト版のヒントを非表示にするには、<a href="hmcl://hide-announcement">ここをクリックしてください</a>。
update.channel.dev.title=ベータ版のヒント
update.channel.nightly=アルファ
@@ -53,7 +53,6 @@ account.character=Персонаж
account.choose=Выберите персонажа
account.create=Добавить аккаунт
account.create.microsoft=Добавить аккаунт Microsoft
account.create.yggdrasil=Добавить аккаунт Mojang
account.create.offline=Добавить автономный аккаунт
account.create.authlibInjector=Создайте аккаунт authlib-injector
account.email=Почта
@@ -106,21 +105,14 @@ account.methods.microsoft.logging_in=Авторизация...
account.methods.microsoft.makegameidsettings=Создать архив / изменение имени профиля
account.methods.microsoft.hint=Вам необходимо нажать кнопку «Войти» и продолжить процесс авторизации во вновь открывшемся окне браузера.\nЕсли токен, используемый для входа в аккаунт Microsoft случайно утёк, вы можете нажать «Отменить авторизацию аккаунта» ниже, чтобы отменить авторизацию.\nЕсли у вас возникнут какие-либо проблемы, вы можете нажать кнопку справки в правом верхнем углу для получения помощи.
account.methods.microsoft.manual=После нажатия кнопки «Войти», вы должны завершить авторизацию во вновь открывшемся окне браузера. Если окно браузера не открылось, вы можете щёлкнуть здесь, чтобы скопировать ссылку и вручную открыть её в браузере.\nЕсли токен, используемый для входа в аккаунт Microsoft случайно утёк, вы можете нажать «Отменить авторизацию аккаунта» ниже, чтобы отменить авторизацию.\n問題が発生した場合は、右上隅にあるヘルプ ボタンをクリックするとヘルプが表示されます。
account.methods.microsoft.profile=Профиль аккаунта...
account.methods.microsoft.profile=Профиль аккаунта...
account.methods.microsoft.purchase=Купить Minecraft
account.methods.forgot_password=ЗАБЫЛ ПАРОЛЬ
account.methods.microsoft.snapshot=Вы используете неофициальное построение HMCL, загрузите официальное построение для входа в Microsoft.
account.methods.offline=Офлайн
account.methods.offline.uuid=UUID
account.methods.offline.uuid.hint=UUID - это уникальный идентификатор игрового персонажа в Minecraft. Способ генерации UUID различается в разных лаунчерах игр. Изменение UUID на тот, который генерируется другим лаунчером гарантирует, что игровые блоки/предметы в рюкзаке вашего офлайн аккаунта останутся. Этот параметр предназначен для экспертов. Если вы не знаете что делаете, мы не советуем вам изменять этот параметр.\nЭта опция не требуется для присоединения к серверам.
account.methods.offline.uuid.malformed=Malformed
account.methods.yggdrasil=Mojang
account.methods.forgot_password=Забыли пароль
account.methods.yggdrasil.migration=Перейти на аккаунт Microsoft
account.methods.yggdrasil.migration.how=Как перейти на аккаунт Microsoft?
account.methods.yggdrasil.migration.hint=С 10 марта 2022 года аккаунты Mojang больше не поддерживаются, и для игры в Minecraft необходимо перейти на аккаунт Microsoft.\n\
\n\
Ссылка ниже поможет перенести ваш аккаунт Mojang на Microsoft.
account.methods.yggdrasil.purchase=Купить Minecraft
account.missing=Нет аккаунтов
account.missing.add=Нажмите здесь, чтобы добавить.
account.not_logged_in=Вход не произведён
@@ -701,8 +693,6 @@ mods.restore=Откат
mods.url=Официальная страница
mods.update_modpack_mod.warning=Обновление модов в пакете модов может привести к непоправимым результатам, возможно, повредить пакет модов так, что он не сможет запуститься. Вы уверены, что хотите обновить?
multiplayer=Сетевая игра
datapack=Датапаки
datapack.add=Установить
datapack.choose_datapack=Выберите датапак для импорта
@@ -948,13 +938,13 @@ update.changelog=Изменения
update.channel.dev=Бета
update.channel.dev.hint=Вы используете бета-версию, которая может включать некоторые дополнительные функции по сравнению с релизной версией, используемой только для тестирования.\n\
Бета-версия может быть нестабильной!\n\
Если вы встретили какие-то проблемы, вы можете зайти на <a href="hmcl://settings/feedback">страницу обратной связи</a>, чтобы сообщить о них, или присоединиться к чату <a href="https://discord.gg/jVvC7HfM6U">Discord</a> или <a href="https://kook.top/Kx7n3t">KOOK</a>, чтобы сообщить о проблемах.\n\n\
Если вы встретили какие-то проблемы, вы можете зайти на <a href="hmcl://settings/feedback">страницу обратной связи</a>, чтобы сообщить о них, или присоединиться к чату <a href="https://discord.gg/jVvC7HfM6U">Discord</a> или <a href="https://docs.hmcl.net/groups.html">QQ</a>, чтобы сообщить о проблемах.\n\n\
<a href="hmcl://hide-announcement">Нажмите здесь</a>, чтобы скрыть подсказку для текущей тестовой версии.
update.channel.dev.title=Подсказки для бета-версии
update.channel.nightly=Альфа
update.channel.nightly.hint=Вы используете альфа-версию, которая может включать некоторые дополнительные функциональные возможности по сравнению с бета-версией и версией релиза, используемой только для тестирования.\n\
Альфа-версия может быть нестабильной!\n\
Если вы встретили какие-то проблемы, вы можете зайти на <a href="hmcl://settings/feedback">страницу обратной связи</a>, чтобы сообщить о них, или присоединиться к чату <a href="https://discord.gg/jVvC7HfM6U">Discord</a> или <a href="https://kook.top/Kx7n3t">KOOK</a>, чтобы сообщить о проблемах.
Если вы встретили какие-то проблемы, вы можете зайти на <a href="hmcl://settings/feedback">страницу обратной связи</a>, чтобы сообщить о них, или присоединиться к чату <a href="https://discord.gg/jVvC7HfM6U">Discord</a> или <a href="https://docs.hmcl.net/groups.html">QQ</a>, чтобы сообщить о проблемах.
update.channel.nightly.title=Подсказки для альфа-версии
update.channel.stable=Релиз
update.checking=Проверка наличия обновлений
@@ -51,7 +51,6 @@ account.character=角色
account.choose=請選擇角色
account.create=建立帳戶
account.create.microsoft=添加微軟帳戶
account.create.yggdrasil=添加 Mojang 帳戶
account.create.offline=添加離線模式帳戶
account.create.authlibInjector=添加外置登入帳戶 (authlib-injector)
account.email=電子信箱
@@ -115,7 +114,7 @@ account.methods.microsoft.hint=你需要按照以下步驟添加賬戶:\n\
5.在網站提示“大功告成”後,只需等待帳戶完成添加即可\n\
若網站提示“出现错误”的標識,請嘗試重新按照以上步驟登入\n\
-若賬戶添加失敗,請嘗試重新按照以上步驟登入\n\
-若登入微軟賬號的 Token 洩露,可點擊下方“解除帳戶授權”解除登入授權,然後等待 Token 過期
-若登入微軟賬號的 Token 洩露,可點擊下方“解除帳戶授權”解除登入授權,然後等待 Token 過期\n\
如遇到問題,你可以點擊右上角幫助按鈕進行求助。
account.methods.microsoft.manual=你需要按照以下步驟添加账户:\n\
1.點擊“登入”按鈕\n\
@@ -125,9 +124,10 @@ account.methods.microsoft.manual=你需要按照以下步驟添加账户:\n\
5.在網站提示“大功告成”後,只需等待帳戶完成添加即可\n\
-若網站提示“出现错误”的標識或賬戶添加失敗時,請嘗試重新按照以上步驟登入\n\
-若網站未能打開,請手動在網頁瀏覽器中打開:%2$s\n\
-若登入微軟賬號的 Token 洩露,可點擊下方“解除帳戶授權”解除登入授權,然後等待 Token 過期
-若登入微軟賬號的 Token 洩露,可點擊下方“解除帳戶授權”解除登入授權,然後等待 Token 過期\n\
如遇到問題,你可以點擊右上角幫助按鈕進行求助。
account.methods.microsoft.profile=帳戶設置頁
account.methods.microsoft.purchase=購買 Minecraft
account.methods.forgot_password=忘記密碼
account.methods.microsoft.snapshot=你正在使用非官方構建的 HMCL,請下載官方構建進行微軟登入。
account.methods.microsoft.snapshot.website=官方網站
@@ -140,11 +140,6 @@ account.methods.offline.name.invalid=正常情況下,遊戲用戶名只能包
account.methods.offline.uuid=UUID
account.methods.offline.uuid.hint=UUID 是 Minecraft 對玩家角色的唯一標識符,每個啟動器生成 UUID 的方式可能不同。通過修改 UUID 選項至原啟動器所生成的 UUID,你可以保證在切換啟動器後,遊戲還能將你的遊戲角色識別為給定 UUID 所對應的角色,從而保留原來角色的背包物品。UUID 選項為高級選項,除非你知道你在做什麼,否則你不需要調整該選項。
account.methods.offline.uuid.malformed=格式錯誤
account.methods.yggdrasil=Mojang 登入
account.methods.yggdrasil.migration=遷移至微軟帳戶
account.methods.yggdrasil.migration.how=如何遷移至微軟帳戶?
account.methods.yggdrasil.migration.hint=自 2022 年 3 月 10 日起,Mojang 帳戶不再受支持,您必須遷移至微軟帳戶才能登入 Minecraft。\n下方連結將指引您將 Mojang 帳戶遷移至微軟帳戶。
account.methods.yggdrasil.purchase=購買 Minecraft
account.missing=沒有遊戲帳戶
account.missing.add=按一下此處加入帳戶
account.move_to_global=轉換為全域帳戶
@@ -197,6 +192,8 @@ button.save_as=另存為
button.select_all=全選
button.yes=是
chat=官方群組
color.recent=建議
color.custom=自訂顏色
@@ -389,7 +386,7 @@ feedback.github.statement=打開一個 GitHub Issue。
feedback.kookapp=KOOK
feedback.kookapp.statement=歡迎加入 KOOK 討論區,加入後請遵守討論區規定。
feedback.qq_group=HMCL 用戶群
feedback.qq_group.statement=通過捐贈支持加入 HMCL 用戶 QQ 群。
feedback.qq_group.statement=歡迎加入 HMCL 用戶群,加入後請遵守群規。
file=檔案
@@ -470,14 +467,13 @@ game.crash.reason.no_such_method_error=當前遊戲因為代碼不完整,無
game.crash.reason.opengl_not_supported=當前遊戲因為你的顯示卡驅動存在問題,無法繼續運行。\n原因是 OpenGL 不受支援,你現在是否在遠程桌面或者串流模式下?如果是,請直接使用原電腦啟動遊戲。\n或者嘗試升級你的顯示卡驅動到最新版本後再嘗試啟動遊戲。如果你的電腦存在獨立顯示卡,你需要檢查遊戲是否使用集成/核心顯示卡啟動,如果是,請嘗試使用獨立顯示卡啟動 HMCL 與遊戲。如果仍有問題,你可能需要考慮換一個新顯示卡或新電腦。
game.crash.reason.openj9=當前遊戲無法運行在 OpenJ9 虛擬機上,請你在遊戲設置中更換 Hotspot Java 虛擬機,並重新啟動遊戲。如果沒有下載安裝,你可以在網路上自行下載。
game.crash.reason.out_of_memory=當前遊戲因為記憶體不足,無法繼續運行。\n這可能是記憶體分配太小,或者 Mod 數量過多導致的。\n你可以在遊戲設置中調大遊戲記憶體分配值以允許遊戲在更大的記憶體下運行。\n如果仍然出現該錯誤,你可能需要換一台更好的電腦。
game.crash.reason.processing_of_javaagent_failed=當前遊戲因為加載 -javaagent 參數失敗,無法繼續運行。\n如果你在 Java 虛擬機參數 中添加了相關參數,請檢查是否正確。\n如果你沒有添加相關參數或參數確認正確, 請嘗試:\n打開 控制面板 -- 時鐘和區域 分類(選項為類別顯示才有此選項,沒有就跳過)-- 區域 -- 上方的 管理 選項卡 -- 下方的 更改系統區域設置 按鈕 -- 在彈出的視窗中將 “使用Unicode UTF-8提供全球語言支持” 選項關閉,重啓設備後再嘗試啟動遊戲。\n可在<a href="https://discord.gg/jVvC7HfM6U">Discord</a>或<a href="https://kook.top/Kx7n3t">KOOK群</a>尋求幫助
game.crash.reason.processing_of_javaagent_failed=當前遊戲因為加載 -javaagent 參數失敗,無法繼續運行。\n如果你在 Java 虛擬機參數 中添加了相關參數,請檢查是否正確。\n如果你沒有添加相關參數或參數確認正確, 請嘗試:\n打開 控制面板 -- 時鐘和區域 分類(選項為類別顯示才有此選項,沒有就跳過)-- 區域 -- 上方的 管理 選項卡 -- 下方的 更改系統區域設置 按鈕 -- 在彈出的視窗中將 “使用Unicode UTF-8提供全球語言支持” 選項關閉,重啓設備後再嘗試啟動遊戲。\n可在 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://docs.hmcl.net/groups.html">QQ 群</a>尋求幫助
game.crash.reason.resolution_too_high=當前遊戲因為材質包解析度過高,無法繼續運行\n你可以更換一個解析度更低的材質,或者更換一個視訊記憶體更大的顯示卡。
game.crash.reason.stacktrace=原因未知,請點擊日誌按鈕查看詳細訊息。\n下面是一些關鍵字,其中可能包含 Mod 名稱,你可以透過搜索的方式查找有關訊息。\n%s
game.crash.reason.too_old_java=當前遊戲因為 Java 虛擬機版本過低,無法繼續運行。\n你需要在遊戲設置中更換 %1$s 或更新版本的 Java 虛擬機,並重新啟動遊戲。如果沒有下載安裝,你可以點擊 <a href="https://docs.microsoft.com/java/openjdk/download">此處</a> 下載微軟 JDK。
game.crash.reason.unknown=原因未知,請點擊日誌按鈕查看詳細訊息。
game.crash.reason.unsatisfied_link_error=當前遊戲因為缺少本地庫,無法繼續運行。\n這些本地庫缺失:%1$s。\n如果你在全局(特定)遊戲設置中修改了本地庫路徑選項,請你修改回預設模式。\n如果已經在預設模式下,請檢查本地庫缺失是否是 Mod 引起的,或由 HMCL 引起的。如果你確定是 HMCL 引起的,建議你向我們反饋。\n<b>或將游戲路徑中的所有非英文字符的名稱修改為英文字符(例如中文,空格等)</b>\n如果你確實需要自定義本地庫路徑,你需要保證其中包含缺失的本地庫!
game.crash.reason.failed_to_load_a_library=當前遊戲因為加載本地庫失敗,無法繼續運行。\n如果你在全局(特定)遊戲設置中修改了本地庫路徑選項,請你修改回預設模式。\n如果已經在預設模式下,請檢查本地庫缺失是否是 Mod 引起的,或由 HMCL 引起的。如果你確定是 HMCL 引起的,建議你向我們反饋。\n<b>或將游戲路徑中的所有非英文字符的名稱修改為英文字符(例如中文,空格等)</b>\n如果你確實需要自定義本地庫路徑,你需要保證其中包含缺失的本地庫!
game.crash.reason.unsatisfied_link_error=當前遊戲因為缺少本地庫,無法繼續運行。\n這些本地庫缺失:%1$s。\n如果你在遊戲設置中修改了本地庫路徑選項,請你修改回預設模式。\n如果您正在使用預設模式,請檢查遊戲路徑是否僅包含英文字母(大寫和小寫)、數字和底線。\n如果是,則請調查是由於 Mod 或者 HMCL 導致了本地庫缺失的問題。如果你確定是 HMCL 引起的,建議你向我們回饋。\n如果你確實需要自訂本地庫路徑,你需要保證其中包含缺失的本地庫。
game.crash.title=遊戲意外退出
game.directory=遊戲路徑
game.version=遊戲版本
@@ -613,7 +609,7 @@ logwindow.export_game_crash_logs=導出遊戲崩潰訊息
logwindow.export_dump.dependency_ok.button=導出遊戲運行棧
logwindow.export_dump.dependency_ok.doing_button=正在導出遊戲運行棧(可能需要 15 秒)
logwindow.export_dump.no_dependency.button=導出遊戲運行棧(不兼容)
logwindow.export_dump.no_dependency.tooltip=你的 Java 不包含用於創建遊戲運行棧的依賴。請前往 HMCL KOOK 或 HMCL Discord 尋求幫助。
logwindow.export_dump.no_dependency.tooltip=你的 Java 不包含用於創建遊戲運行棧的依賴。請前往 HMCL QQ 群或 Discord 频道尋求幫助。
main_page=首頁
@@ -788,10 +784,6 @@ mods.restore=回退
mods.url=官方頁面
mods.update_modpack_mod.warning=更新模組包中的 Mod 可能導致綜合包損壞,使模組包無法正常啟動。該操作不可逆,確定要更新嗎?
multiplayer=多人聯機
multiplayer.hint=多人聯機服務正在維護中。
multiplayer.hint.details=查看詳情
nbt.entries=%s 個條目
nbt.open.failed=打開檔案失敗
nbt.save.failed=保存檔案失敗
@@ -1049,13 +1041,13 @@ update.changelog=更新日誌
update.channel.dev=測試版
update.channel.dev.hint=你正在使用測試版。測試版包含一些未在正式版中包含的測試性功能,僅用於體驗新功能。\n\
測試版功能未受充分驗證,使用起來可能不穩定!\n\
如果你遇到了使用問題,可以在設置的 <a href="hmcl://settings/feedback">回饋頁面</a> 中進行回饋,或加入回饋頁面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kook.top/Kx7n3t">KOOK 群</a>以回饋問題。\n\n\
如果你遇到了使用問題,可以在設置的 <a href="hmcl://settings/feedback">回饋頁面</a> 中進行回饋,或加入回饋頁面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://docs.hmcl.net/groups.html">QQ 群</a>以回饋問題。\n\n\
<a href="hmcl://hide-announcement">點擊此處</a>為當前版本隱藏該提示。
update.channel.dev.title=測試版提示
update.channel.nightly=預覽版
update.channel.nightly.hint=你正在使用預覽版。預覽版可能會每天更新一次,包含一些未在正式版和測試版中包含的測試性功能,僅用於體驗新功能\n\
測試版功能未受充分驗證,使用起來可能不穩定!\n\
如果你遇到了使用問題,可以在設置的 <a href="hmcl://settings/feedback">回饋頁面</a> 中進行回饋,或加入回饋頁面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kook.top/Kx7n3t">KOOK 群</a>以回饋問題。
如果你遇到了使用問題,可以在設置的 <a href="hmcl://settings/feedback">回饋頁面</a> 中進行回饋,或加入 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://docs.hmcl.net/groups.html">QQ 群</a>以回饋問題。
update.channel.nightly.title=預覽版提示
update.channel.stable=建議版本
update.checking=正在檢查更新
@@ -51,7 +51,6 @@ account.character=角色
account.choose=选择一个角色
account.create=添加账户
account.create.microsoft=添加微软账户
account.create.yggdrasil=添加 Mojang 账户
account.create.offline=添加离线模式账户
account.create.authlibInjector=添加外置登录账户 (authlib-injector)
account.email=邮箱
@@ -128,6 +127,7 @@ account.methods.microsoft.manual=你需要按照以下步骤添加:\n\
<b>-若设备网络环境不佳,可能登录网站加载很慢甚至无法加载,此时请使用网络代理并重试</b>\n\
如遇到问题,你可以点击右上角帮助按钮进行求助。
account.methods.microsoft.profile=账户设置页
account.methods.microsoft.purchase=购买 Minecraft
account.methods.forgot_password=忘记密码
account.methods.microsoft.snapshot=你正在使用非官方构建的 HMCL,请下载官方构建进行微软登录。
account.methods.microsoft.snapshot.website=官方网站
@@ -141,11 +141,6 @@ account.methods.offline.name.invalid=正常情况下,游戏用户名只能包
account.methods.offline.uuid=UUID
account.methods.offline.uuid.hint=UUID 是 Minecraft 对玩家角色的唯一标识符,每个启动器生成 UUID 的方式可能不同。通过修改 UUID 选项至原启动器所生成的 UUID,你可以保证在切换启动器后,游戏还能将你的游戏角色识别为给定 UUID 所对应的角色,从而保留原来角色的背包物品。UUID 选项为高级选项,除非你知道你在做什么,否则你不需要调整该选项。
account.methods.offline.uuid.malformed=格式错误
account.methods.yggdrasil=Mojang 账户
account.methods.yggdrasil.migration=迁移至微软账户
account.methods.yggdrasil.migration.how=如何迁移至微软账户?
account.methods.yggdrasil.migration.hint=自 2022 年 3 月 10 日起,Mojang 账户不再受支持,您必须迁移至微软账户才能登录 Minecraft。\n下方链接将指引您将Mojang账户迁移至微软账户。
account.methods.yggdrasil.purchase=购买 Minecraft
account.missing=没有游戏账户
account.missing.add=点击此处添加账户
account.move_to_global=转换为全局账户\n该账户的信息会保存至用户目录的配置文件中
@@ -198,6 +193,8 @@ button.save_as=另存为
button.select_all=全选
button.yes=是
chat=官方群组
color.recent=推荐
color.custom=自定义颜色
@@ -391,7 +388,7 @@ feedback.github.statement=打开一个 GitHub Issue。
feedback.kookapp=KOOK
feedback.kookapp.statement=欢迎加入 KOOK 讨论区,加入后请遵守讨论区规定。
feedback.qq_group=HMCL 用户群
feedback.qq_group.statement=通过捐赠支持加入 HMCL 用户 QQ 群。
feedback.qq_group.statement=欢迎加入 HMCL 用户群,加入后请遵守群规。
file=文件
@@ -620,7 +617,7 @@ logwindow.export_game_crash_logs=导出游戏崩溃信息
logwindow.export_dump.dependency_ok.button=导出游戏运行栈
logwindow.export_dump.dependency_ok.doing_button=正在导出游戏运行栈(可能需要 15 秒)
logwindow.export_dump.no_dependency.button=导出游戏运行栈(不兼容)
logwindow.export_dump.no_dependency.tooltip=你的 Java 不包含用于创建游戏运行栈的依赖。请前往 HMCL KOOK 或 HMCL Discord 寻求帮助。
logwindow.export_dump.no_dependency.tooltip=你的 Java 不包含用于创建游戏运行栈的依赖。请前往 HMCL QQ 群或 Discord 频道寻求帮助。
main_page=主页
@@ -795,10 +792,6 @@ mods.restore=回退
mods.url=官方页面
mods.update_modpack_mod.warning=更新整合包中的模组可能导致整合包损坏,使整合包无法正常启动。该操作不可逆,确定要更新吗?
multiplayer=多人联机
multiplayer.hint=多人联机服务正在维护中。
multiplayer.hint.details=查看详情
nbt.entries=%s 个条目
nbt.open.failed=打开文件失败
nbt.save.failed=保存文件失败
@@ -1056,13 +1049,13 @@ update.changelog=更新日志
update.channel.dev=测试版
update.channel.dev.hint=你正在使用测试版。测试版包含一些未在正式版中包含的测试性功能,仅用于体验新功能。\n\
测试版功能未受充分验证,使用起来可能不稳定!<a href="https://hmcl.huangyuhui.net/download">下载稳定版</a>\n\
如果你遇到了使用问题,可以在设置的 <a href="hmcl://settings/feedback">反馈页面</a> 中进行反馈,或加入反馈页面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kook.top/Kx7n3t">KOOK</a>群以反馈问题。欢迎关注 B 站账号 <a href="https://space.bilibili.com/1445341">huanghongxun</a> 以关注 HMCL 的开发进展。\n\n\
如果你遇到了使用问题,可以在设置的 <a href="hmcl://settings/feedback">反馈页面</a> 中进行反馈,或加入反馈页面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://docs.hmcl.net/groups.html">QQ 群</a>以反馈问题。欢迎关注 B 站账号 <a href="https://space.bilibili.com/1445341">huanghongxun</a> 以关注 HMCL 的开发进展。\n\n\
<a href="hmcl://hide-announcement">点击此处</a>为当前版本隐藏该提示。
update.channel.dev.title=测试版提示
update.channel.nightly=预览版
update.channel.nightly.hint=你正在使用预览版。预览版可能会每天更新一次,包含一些未在正式版和测试版中包含的测试性功能,仅用于体验新功能。\n\
测试版功能未受充分验证,使用起来可能不稳定!<a href="https://hmcl.huangyuhui.net/download">下载稳定版</a>\n\
如果你遇到了使用问题,可以在设置的 <a href="hmcl://settings/feedback">反馈页面</a> 中进行反馈,或加入反馈页面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://kook.top/Kx7n3t">KOOK</a>群以反馈问题。欢迎关注 B 站账号 <a href="https://space.bilibili.com/1445341">huanghongxun</a> 以关注 HMCL 的开发进展。
如果你遇到了使用问题,可以在设置的 <a href="hmcl://settings/feedback">反馈页面</a> 中进行反馈,或加入反馈页面中提供的 <a href="https://discord.gg/jVvC7HfM6U">Discord</a> 或 <a href="https://docs.hmcl.net/groups.html">QQ 群</a>以反馈问题。欢迎关注 B 站账号 <a href="https://space.bilibili.com/1445341">huanghongxun</a> 以关注 HMCL 的开发进展。
update.channel.nightly.title=预览版提示
update.channel.stable=推荐版本
update.checking=正在检查更新
@@ -1,62 +0,0 @@
/*
* 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/>.
*/
package org.jackhuang.hmcl.auth.yggdrasil;
import org.jackhuang.hmcl.util.gson.UUIDTypeAdapter;
import org.jackhuang.hmcl.util.io.NetworkUtils;
import java.net.URL;
import java.util.*;
public class MojangYggdrasilProvider implements YggdrasilProvider {
@Override
public URL getAuthenticationURL() {
return NetworkUtils.toURL("https://authserver.mojang.com/authenticate");
}
@Override
public URL getRefreshmentURL() {
return NetworkUtils.toURL("https://authserver.mojang.com/refresh");
}
@Override
public URL getValidationURL() {
return NetworkUtils.toURL("https://authserver.mojang.com/validate");
}
@Override
public URL getInvalidationURL() {
return NetworkUtils.toURL("https://authserver.mojang.com/invalidate");
}
@Override
public URL getSkinUploadURL(UUID uuid) throws UnsupportedOperationException {
return NetworkUtils.toURL("https://api.mojang.com/user/profile/" + UUIDTypeAdapter.fromUUID(uuid) + "/skin");
}
@Override
public URL getProfilePropertiesURL(UUID uuid) {
return NetworkUtils.toURL("https://sessionserver.mojang.com/session/minecraft/profile/" + UUIDTypeAdapter.fromUUID(uuid));
}
@Override
public String toString() {
return "mojang";
}
}
@@ -29,7 +29,7 @@ import java.util.logging.Level;
import static java.util.Objects.requireNonNull;
import static org.jackhuang.hmcl.util.Logging.LOG;
public class YggdrasilAccount extends ClassicAccount {
public abstract class YggdrasilAccount extends ClassicAccount {
protected final YggdrasilService service;
protected final UUID characterUUID;
@@ -1,80 +0,0 @@
/*
* 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/>.
*/
package org.jackhuang.hmcl.auth.yggdrasil;
import org.jackhuang.hmcl.auth.AccountFactory;
import org.jackhuang.hmcl.auth.AuthenticationException;
import org.jackhuang.hmcl.auth.CharacterSelector;
import org.jackhuang.hmcl.util.javafx.ObservableOptionalCache;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import static org.jackhuang.hmcl.util.Lang.tryCast;
/**
*
* @author huangyuhui
*/
public class YggdrasilAccountFactory extends AccountFactory<YggdrasilAccount> {
public static final YggdrasilAccountFactory MOJANG = new YggdrasilAccountFactory(YggdrasilService.MOJANG);
private final YggdrasilService service;
public YggdrasilAccountFactory(YggdrasilService service) {
this.service = service;
}
@Override
public AccountLoginType getLoginType() {
return AccountLoginType.USERNAME_PASSWORD;
}
@Override
public YggdrasilAccount create(CharacterSelector selector, String username, String password, ProgressCallback progressCallback, Object additionalData) throws AuthenticationException {
Objects.requireNonNull(selector);
Objects.requireNonNull(username);
Objects.requireNonNull(password);
return new YggdrasilAccount(service, username, password, selector);
}
@Override
public YggdrasilAccount fromStorage(Map<Object, Object> storage) {
Objects.requireNonNull(storage);
YggdrasilSession session = YggdrasilSession.fromStorage(storage);
String username = tryCast(storage.get("username"), String.class)
.orElseThrow(() -> new IllegalArgumentException("storage does not have username"));
tryCast(storage.get("profileProperties"), Map.class).ifPresent(
it -> {
@SuppressWarnings("unchecked")
Map<String, String> properties = it;
GameProfile selected = session.getSelectedProfile();
ObservableOptionalCache<UUID, CompleteGameProfile, AuthenticationException> profileRepository = service.getProfileRepository();
profileRepository.put(selected.getId(), new CompleteGameProfile(selected, properties));
profileRepository.invalidate(selected.getId());
});
return new YggdrasilAccount(service, username, session);
}
}
@@ -53,8 +53,6 @@ public class YggdrasilService {
private static final ThreadPoolExecutor POOL = threadPool("YggdrasilProfileProperties", true, 2, 10, TimeUnit.SECONDS);
public static final YggdrasilService MOJANG = new YggdrasilService(new MojangYggdrasilProvider());
private final YggdrasilProvider provider;
private final ObservableOptionalCache<UUID, CompleteGameProfile, AuthenticationException> profileRepository;
@@ -272,7 +270,5 @@ public class YggdrasilService {
.registerTypeAdapterFactory(ValidationTypeAdapterFactory.INSTANCE)
.create();
public static final String PROFILE_URL = "https://aka.ms/MinecraftMigration";
public static final String MIGRATION_FAQ_URL = "https://help.minecraft.net/articles/360050865492";
public static final String PURCHASE_URL = "https://www.microsoft.com/store/productId/9NXP44L49SHJ";
}
@@ -68,7 +68,7 @@ public final class FabricVersionList extends VersionList<FabricRemoteVersion> {
private static final String GAME_META_URL = "https://meta.fabricmc.net/v2/versions/game";
private List<String> getGameVersions(String metaUrl) throws IOException {
String json = NetworkUtils.doGet(NetworkUtils.toURL(downloadProvider.injectURL(metaUrl)));
String json = NetworkUtils.doGet(downloadProvider.injectURLWithCandidates(metaUrl));
return JsonUtils.GSON.<ArrayList<GameVersion>>fromJson(json, new TypeToken<ArrayList<GameVersion>>() {
}.getType()).stream().map(GameVersion::getVersion).collect(Collectors.toList());
}
@@ -27,7 +27,6 @@ import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.ChecksumMismatchException;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.NetworkUtils;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.versioning.VersionNumber;
import org.tukaani.xz.LZMAInputStream;
@@ -58,8 +57,8 @@ public class JavaDownloadTask extends Task<Void> {
this.javaVersion = javaVersion;
this.rootDir = rootDir;
this.downloadProvider = downloadProvider;
this.javaDownloadsTask = new GetTask(NetworkUtils.toURL(downloadProvider.injectURL(
"https://piston-meta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json")))
this.javaDownloadsTask = new GetTask(downloadProvider.injectURLWithCandidates(
"https://piston-meta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"))
.thenComposeAsync(javaDownloadsJson -> {
JavaDownloads allDownloads = JsonUtils.fromNonNullJson(javaDownloadsJson, JavaDownloads.class);
if (!allDownloads.getDownloads().containsKey(platform)) throw new UnsupportedPlatformException();
@@ -69,7 +68,7 @@ public class JavaDownloadTask extends Task<Void> {
for (JavaDownloads.JavaDownload download : candidates) {
if (VersionNumber.compare(download.getVersion().getName(), Integer.toString(javaVersion.getMajorVersion())) >= 0) {
this.download = download;
return new GetTask(NetworkUtils.toURL(downloadProvider.injectURL(download.getManifest().getUrl())));
return new GetTask(downloadProvider.injectURLWithCandidates(download.getManifest().getUrl()));
}
}
throw new UnsupportedPlatformException();
@@ -117,7 +116,7 @@ public class JavaDownloadTask extends Task<Void> {
if (file.getDownloads().containsKey("lzma")) {
DownloadInfo download = file.getDownloads().get("lzma");
File tempFile = jvmDir.resolve(entry.getKey() + ".lzma").toFile();
FileDownloadTask task = new FileDownloadTask(NetworkUtils.toURL(downloadProvider.injectURL(download.getUrl())), tempFile, new FileDownloadTask.IntegrityCheck("SHA-1", download.getSha1()));
FileDownloadTask task = new FileDownloadTask(downloadProvider.injectURLWithCandidates(download.getUrl()), tempFile, new FileDownloadTask.IntegrityCheck("SHA-1", download.getSha1()));
task.setName(entry.getKey());
dependencies.add(task.thenRunAsync(() -> {
Path decompressed = jvmDir.resolve(entry.getKey() + ".tmp");
@@ -135,7 +134,7 @@ public class JavaDownloadTask extends Task<Void> {
}));
} else if (file.getDownloads().containsKey("raw")) {
DownloadInfo download = file.getDownloads().get("raw");
FileDownloadTask task = new FileDownloadTask(NetworkUtils.toURL(downloadProvider.injectURL(download.getUrl())), dest.toFile(), new FileDownloadTask.IntegrityCheck("SHA-1", download.getSha1()));
FileDownloadTask task = new FileDownloadTask(downloadProvider.injectURLWithCandidates(download.getUrl()), dest.toFile(), new FileDownloadTask.IntegrityCheck("SHA-1", download.getSha1()));
task.setName(entry.getKey());
if (file.isExecutable()) {
dependencies.add(task.thenRunAsync(() -> dest.toFile().setExecutable(true)));
@@ -22,12 +22,12 @@ import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.VersionList;
import org.jackhuang.hmcl.util.Immutable;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.gson.Validation;
import org.jackhuang.hmcl.util.io.HttpRequest;
import org.jackhuang.hmcl.util.versioning.VersionNumber;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@@ -86,7 +86,7 @@ public final class NeoForgeBMCLVersionList extends VersionList<NeoForgeRemoteVer
versions.put(gameVersion, new NeoForgeRemoteVersion(
neoForgeVersion.mcVersion,
nf,
Lang.immutableListOf(
Collections.singletonList(
apiRoot + "/neoforge/version/" + neoForgeVersion.version + "/download/installer.jar"
)
));
@@ -2,10 +2,10 @@ package org.jackhuang.hmcl.download.neoforge;
import org.jackhuang.hmcl.download.DownloadProvider;
import org.jackhuang.hmcl.download.VersionList;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.HttpRequest;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@@ -53,8 +53,8 @@ public final class NeoForgeOfficialVersionList extends VersionList<NeoForgeRemot
for (String version : results[0].versions) {
versions.put("1.20.1", new NeoForgeRemoteVersion(
"1.20.1", StringUtils.removePrefix(version, "1.20.1-"),
Lang.immutableListOf(
downloadProvider.injectURL("https://maven.neoforged.net/releases/net/neoforged/forge/" + version + "/forge-" + version + "-installer.jar")
Collections.singletonList(
"https://maven.neoforged.net/releases/net/neoforged/forge/" + version + "/forge-" + version + "-installer.jar"
)
));
}
@@ -63,8 +63,8 @@ public final class NeoForgeOfficialVersionList extends VersionList<NeoForgeRemot
String mcVersion = "1." + version.substring(0, version.indexOf('.', version.indexOf('.') + 1));
versions.put(mcVersion, new NeoForgeRemoteVersion(
mcVersion, version,
Lang.immutableListOf(
downloadProvider.injectURL("https://maven.neoforged.net/releases/net/neoforged/neoforge/" + version + "/neoforge-" + version + "-installer.jar")
Collections.singletonList(
"https://maven.neoforged.net/releases/net/neoforged/neoforge/" + version + "/neoforge-" + version + "-installer.jar"
)
));
}
@@ -68,7 +68,7 @@ public final class QuiltVersionList extends VersionList<QuiltRemoteVersion> {
private static final String GAME_META_URL = "https://meta.quiltmc.org/v3/versions/game";
private List<String> getGameVersions(String metaUrl) throws IOException {
String json = NetworkUtils.doGet(NetworkUtils.toURL(downloadProvider.injectURL(metaUrl)));
String json = NetworkUtils.doGet(downloadProvider.injectURLWithCandidates(metaUrl));
return JsonUtils.GSON.<ArrayList<GameVersion>>fromJson(json, new TypeToken<ArrayList<GameVersion>>() {
}.getType()).stream().map(GameVersion::getVersion).collect(Collectors.toList());
}
@@ -38,6 +38,7 @@ public class GameJavaVersion {
return majorVersion;
}
public static final GameJavaVersion JAVA_21 = new GameJavaVersion("java-runtime-delta", 21);
public static final GameJavaVersion JAVA_17 = new GameJavaVersion("java-runtime-beta", 17);
public static final GameJavaVersion JAVA_16 = new GameJavaVersion("java-runtime-alpha", 16);
public static final GameJavaVersion JAVA_8 = new GameJavaVersion("jre-legacy", 8);
@@ -560,6 +560,7 @@ public class DefaultLauncher extends Launcher {
final Command commandLine = generateCommandLine(nativeFolder);
final String command = usePowerShell ? null : commandLine.commandLine.toString();
Map<String, String> envVars = getEnvVars();
if (!usePowerShell && isWindows) {
if (command.length() > 8192) { // maximum length of the command in cmd
@@ -596,7 +597,7 @@ public class DefaultLauncher extends Launcher {
writer.write(CommandBuilder.pwshString(options.getGameDir().getAbsoluteFile().getParent()));
writer.newLine();
}
for (Map.Entry<String, String> entry : getEnvVars().entrySet()) {
for (Map.Entry<String, String> entry : envVars.entrySet()) {
writer.write("$Env:" + entry.getKey() + "=");
writer.write(CommandBuilder.pwshString(entry.getValue()));
writer.newLine();
@@ -605,19 +606,38 @@ public class DefaultLauncher extends Launcher {
writer.write(CommandBuilder.pwshString(repository.getRunDirectory(version.getId()).getAbsolutePath()));
writer.newLine();
if (StringUtils.isNotBlank(options.getPreLaunchCommand())) {
writer.write('&');
for (String rawCommand : StringUtils.tokenize(options.getPreLaunchCommand(), envVars)) {
writer.write(' ');
writer.write(CommandBuilder.pwshString(rawCommand));
}
writer.newLine();
}
writer.write('&');
for (String rawCommand : commandLine.commandLine.asList()) {
writer.write(' ');
writer.write(CommandBuilder.pwshString(rawCommand));
}
writer.newLine();
if (StringUtils.isNotBlank(options.getPostExitCommand())) {
writer.write('&');
for (String rawCommand : StringUtils.tokenize(options.getPostExitCommand(), envVars)) {
writer.write(' ');
writer.write(CommandBuilder.pwshString(rawCommand));
}
writer.newLine();
}
} else {
if (isWindows) {
writer.write("@echo off");
writer.newLine();
writer.write("set APPDATA=" + options.getGameDir().getAbsoluteFile().getParent());
writer.newLine();
for (Map.Entry<String, String> entry : getEnvVars().entrySet()) {
for (Map.Entry<String, String> entry : envVars.entrySet()) {
writer.write("set " + entry.getKey() + "=" + CommandBuilder.toBatchStringLiteral(entry.getValue()));
writer.newLine();
}
@@ -626,7 +646,7 @@ public class DefaultLauncher extends Launcher {
} else {
writer.write("#!/usr/bin/env bash");
writer.newLine();
for (Map.Entry<String, String> entry : getEnvVars().entrySet()) {
for (Map.Entry<String, String> entry : envVars.entrySet()) {
writer.write("export " + entry.getKey() + "=" + CommandBuilder.toShellStringLiteral(entry.getValue()));
writer.newLine();
}
@@ -638,13 +658,14 @@ public class DefaultLauncher extends Launcher {
}
writer.newLine();
if (StringUtils.isNotBlank(options.getPreLaunchCommand())) {
writer.write(options.getPreLaunchCommand());
writer.write(new CommandBuilder().addAll(StringUtils.tokenize(options.getPreLaunchCommand(), envVars)).toString());
writer.newLine();
}
writer.write(command);
writer.newLine();
if (StringUtils.isNotBlank(options.getPostExitCommand())) {
writer.write(options.getPostExitCommand());
writer.write(new CommandBuilder().addAll(StringUtils.tokenize(options.getPostExitCommand(), envVars)).toString());
writer.newLine();
}
@@ -68,6 +68,9 @@ public class ModrinthInstallTask extends Task<Void> {
case "forge":
builder.version("forge", modLoader.getValue());
break;
case "neoforge":
builder.version("neoforge", modLoader.getValue());
break;
case "fabric-loader":
builder.version("fabric", modLoader.getValue());
break;
@@ -178,6 +178,34 @@ public final class NetworkUtils {
return IOUtils.readFullyAsString(con.getInputStream());
}
public static String doGet(List<URL> urls) throws IOException {
List<IOException> exceptions = null;
for (URL url : urls) {
try {
HttpURLConnection con = createHttpConnection(url);
con = resolveConnection(con);
return IOUtils.readFullyAsString(con.getInputStream());
} catch (IOException e) {
if (exceptions == null) {
exceptions = new ArrayList<>(1);
}
exceptions.add(e);
}
}
if (exceptions == null) {
throw new IOException("No candidate URL");
} else if (exceptions.size() == 1) {
throw exceptions.get(0);
} else {
IOException exception = new IOException("Failed to doGet");
for (IOException e : exceptions) {
exception.addSuppressed(e);
}
throw exception;
}
}
public static String doPost(URL u, Map<String, String> params) throws IOException {
StringBuilder sb = new StringBuilder();
if (params != null) {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 49 KiB

-6
View File
@@ -7,18 +7,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HMCL", "HMCL\HMCL.vcxproj",
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{672B1019-E741-4C0D-A986-627E2ACE157B}.Debug|x64.ActiveCfg = Debug|x64
{672B1019-E741-4C0D-A986-627E2ACE157B}.Debug|x64.Build.0 = Debug|x64
{672B1019-E741-4C0D-A986-627E2ACE157B}.Debug|x86.ActiveCfg = Debug|Win32
{672B1019-E741-4C0D-A986-627E2ACE157B}.Debug|x86.Build.0 = Debug|Win32
{672B1019-E741-4C0D-A986-627E2ACE157B}.Release|x64.ActiveCfg = Release|x64
{672B1019-E741-4C0D-A986-627E2ACE157B}.Release|x64.Build.0 = Release|x64
{672B1019-E741-4C0D-A986-627E2ACE157B}.Release|x86.ActiveCfg = Release|Win32
{672B1019-E741-4C0D-A986-627E2ACE157B}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
+4 -3
View File
@@ -5,12 +5,13 @@
![Stars](https://img.shields.io/github/stars/huanghongxun/HMCL)
[![Discord](https://img.shields.io/discord/995291757799538688.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/jVvC7HfM6U)
[![KOOK](https://img.shields.io/badge/KOOK-HMCL-brightgreen)](https://kook.top/Kx7n3t)
[![QQ Group](https://img.shields.io/badge/QQ-HMCL-brightgreen)](https://docs.hmcl.net/groups.html)
English | [中文](README_cn.md)
## Introduction
HMCL is a cross-platform Minecraft launcher which supports Mod Management, Game Customizing, Auto Installing (Forge, Fabric, Quilt, LiteLoader and OptiFine), Modpack Creating, UI Customization, and more.
HMCL is a cross-platform Minecraft launcher which supports Mod Management, Game Customizing, Auto Installing (Forge, NeoForge, Fabric, Quilt, LiteLoader and OptiFine), Modpack Creating, UI Customization, and more.
HMCL has amazing cross-platform capabilities.
It can not only run on different operating systems such as Windows, Linux, and macOS,
@@ -44,7 +45,7 @@ The software is distributed under [GPLv3](https://www.gnu.org/licenses/gpl-3.0.h
If you want to submit a pull request, there are some requirements:
* IDE: Intellij IDEA
* Compiler: Java 1.8
* Compiler: Java 1.8 or Java 11+
* Do NOT modify `gradle` files
### Compilation
@@ -63,7 +64,7 @@ Make sure you have Java installed with JavaFX 8 at least. Liberica Full JDK 8 or
|----------------------------------------------|------------------------------------------------------------------------------------------------|
| `-Dhmcl.home=<path>` | Override HMCL directory. |
| `-Dhmcl.self_integrity_check.disable=true` | Bypass the self integrity check when checking for update. |
| `-Dhmcl.bmclapi.override=<version>` | Override API Root of BMCLAPI download provider, defaults to `https://bmclapi2.bangbang93.com`. |
| `-Dhmcl.bmclapi.override=<url>` | Override API Root of BMCLAPI download provider, defaults to `https://bmclapi2.bangbang93.com`. |
| `-Dhmcl.font.override=<font family>` | Override font family. |
| `-Dhmcl.version.override=<version>` | Override the version number. |
| `-Dhmcl.update_source.override=<url>` | Override the update source for HMCL itself. |
+4 -3
View File
@@ -5,12 +5,13 @@
![Stars](https://img.shields.io/github/stars/huanghongxun/HMCL)
[![Discord](https://img.shields.io/discord/995291757799538688.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/jVvC7HfM6U)
[![KOOK](https://img.shields.io/badge/KOOK-HMCL-brightgreen)](https://kook.top/Kx7n3t)
[![QQ Group](https://img.shields.io/badge/QQ-HMCL-brightgreen)](https://docs.hmcl.net/groups.html)
[English](README.md) | 中文
## 简介
HMCL 是一款跨平台 Minecraft 启动器, 支持 Mod 管理, 游戏自定义, 游戏自动安装 (Forge, Fabric, Quilt, LiteLoader 与 OptiFine), 模组包创建, 界面自定义等功能.
HMCL 是一款跨平台 Minecraft 启动器, 支持 Mod 管理, 游戏自定义, 游戏自动安装 (Forge, NeoForge, Fabric, Quilt, LiteLoader 与 OptiFine), 整合包创建, 界面自定义等功能.
HMCL 有着强大的跨平台能力. 它不仅支持 Windows、Linux、macOS 等常见的操作系统,同时也支持 x86、ARM、MIPS 和 LoongArch 等不同的 CPU 架构.
您可以使用 HMCL 在不同平台上轻松的游玩 Minecraft.
@@ -42,7 +43,7 @@ HMCL 有着强大的跨平台能力. 它不仅支持 Windows、Linux、macOS 等
如果您想提交一个 Pull Request, 必须遵守如下要求:
* IDE: Intellij IDEA
* 编译器: Java 1.8
* 编译器: Java 1.8 或 Java 11+
* **不要**修改 `gradle` 相关文件
### 编译
@@ -61,7 +62,7 @@ HMCL 有着强大的跨平台能力. 它不仅支持 Windows、Linux、macOS 等
|----------------------------------------------|----------------------------------------------------------------|
| `-Dhmcl.home=<path>` | 覆盖 HMCL 数据文件夹. |
| `-Dhmcl.self_integrity_check.disable=true` | 检查更新时绕过本体完整性检查. |
| `-Dhmcl.bmclapi.override=<version>` | 覆盖 BMCLAPI 的 API Root, 默认值为 `https://bmclapi2.bangbang93.com`. |
| `-Dhmcl.bmclapi.override=<url>` | 覆盖 BMCLAPI 的 API Root, 默认值为 `https://bmclapi2.bangbang93.com`. |
| `-Dhmcl.font.override=<font family>` | 覆盖字族. |
| `-Dhmcl.version.override=<version>` | 覆盖版本号. |
| `-Dhmcl.update_source.override=<url>` | 覆盖 HMCL 更新源. |