Compare commits
31
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d9e2d92e0 | ||
|
|
9f754e78e8 | ||
|
|
cecd28791b | ||
|
|
5e42652e75 | ||
|
|
9f682e0c39 | ||
|
|
eac12efafb | ||
|
|
d3d46f6a29 | ||
|
|
6f1db67e9a | ||
|
|
0d7ece819d | ||
|
|
7f852080cd | ||
|
|
e0360c2b38 | ||
|
|
3bf0eb2a16 | ||
|
|
84b428b57c | ||
|
|
41895e97e1 | ||
|
|
f839dc192c | ||
|
|
24250a6239 | ||
|
|
a3ab2b52b6 | ||
|
|
c4d4c6fcf3 | ||
|
|
f77f005f88 | ||
|
|
9ec494664c | ||
|
|
dc7c883962 | ||
|
|
567bd15997 | ||
|
|
25c9ef0f27 | ||
|
|
d45d994307 | ||
|
|
01b7a6b95a | ||
|
|
a0593c03c6 | ||
|
|
91f05315aa | ||
|
|
84b8fff37b | ||
|
|
3a9cc2b9bb | ||
|
|
056f30f6f5 | ||
|
|
2d6e01fcf9 |
No files matched your search
@@ -0,0 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: QQ 群
|
||||
url: https://docs.hmcl.net/groups.html
|
||||
about: Hello Minecraft! Launcher 的官方 QQ 交流群。
|
||||
- name: Discord 服务器
|
||||
url: https://discord.gg/jVvC7HfM6U
|
||||
about: Hello Minecraft! Launcher 的官方 Discord 服务器。
|
||||
@@ -1,79 +0,0 @@
|
||||
name: Check Update
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# schedule:
|
||||
# - cron: '30 * * * *'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
check-update:
|
||||
if: ${{ github.repository_owner == 'HMCL-dev' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
include:
|
||||
- channel: dev
|
||||
task: checkUpdateDev
|
||||
- channel: stable
|
||||
task: checkUpdateStable
|
||||
runs-on: ubuntu-latest
|
||||
name: check-update-${{ matrix.channel }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '25'
|
||||
- name: Fetch last version
|
||||
run: ./gradlew ${{ matrix.task }} --no-daemon --info --stacktrace
|
||||
- name: Check for existing tags
|
||||
run: if [ -z "$(git tag -l "$HMCL_TAG_NAME")" ]; then echo "continue=true" >> $GITHUB_ENV; fi
|
||||
- name: Download artifacts
|
||||
if: ${{ env.continue == 'true' }}
|
||||
run: |
|
||||
wget "$HMCL_CI_DOWNLOAD_BASE_URI/HMCL-$HMCL_VERSION.exe"
|
||||
wget "$HMCL_CI_DOWNLOAD_BASE_URI/HMCL-$HMCL_VERSION.exe.sha256"
|
||||
wget "$HMCL_CI_DOWNLOAD_BASE_URI/HMCL-$HMCL_VERSION.jar"
|
||||
wget "$HMCL_CI_DOWNLOAD_BASE_URI/HMCL-$HMCL_VERSION.jar.sha256"
|
||||
wget "$HMCL_CI_DOWNLOAD_BASE_URI/HMCL-$HMCL_VERSION.sh"
|
||||
wget "$HMCL_CI_DOWNLOAD_BASE_URI/HMCL-$HMCL_VERSION.sh.sha256"
|
||||
- name: Generate release note
|
||||
if: ${{ env.continue == 'true' }}
|
||||
run: |
|
||||
if [ "${{ matrix.channel }}" = "stable" ]; then
|
||||
echo "**This version is a stable version.**" >> RELEASE_NOTE
|
||||
echo "" >> RELEASE_NOTE
|
||||
fi
|
||||
echo "The full changelogs can be found on the website: https://docs.hmcl.net/changelog/${{ matrix.channel }}.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]($GH_DOWNLOAD_BASE_URL/v$HMCL_VERSION/HMCL-$HMCL_VERSION.exe) | \`$(cat HMCL-$HMCL_VERSION.exe.sha256)\` |" >> RELEASE_NOTE
|
||||
echo "| [HMCL-$HMCL_VERSION.jar]($GH_DOWNLOAD_BASE_URL/v$HMCL_VERSION/HMCL-$HMCL_VERSION.jar) | \`$(cat HMCL-$HMCL_VERSION.jar.sha256)\` |" >> RELEASE_NOTE
|
||||
echo "| [HMCL-$HMCL_VERSION.sh]($GH_DOWNLOAD_BASE_URL/v$HMCL_VERSION/HMCL-$HMCL_VERSION.sh) | \`$(cat HMCL-$HMCL_VERSION.sh.sha256)\` |" >> RELEASE_NOTE
|
||||
env:
|
||||
GH_DOWNLOAD_BASE_URL: https://github.com/${{ github.repository }}/releases/download
|
||||
- name: Create release
|
||||
if: ${{ env.continue == 'true' }}
|
||||
run: |
|
||||
gh release create "${{ env.HMCL_TAG_NAME }}" \
|
||||
"HMCL-${{ env.HMCL_VERSION }}.exe" \
|
||||
"HMCL-${{ env.HMCL_VERSION }}.jar" \
|
||||
"HMCL-${{ env.HMCL_VERSION }}.sh" \
|
||||
--target "${{ env.HMCL_COMMIT_SHA }}" \
|
||||
--title "${{ env.HMCL_TAG_NAME }}" \
|
||||
--notes-file RELEASE_NOTE \
|
||||
--prerelease
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -1,21 +0,0 @@
|
||||
name: Sync to Gitee
|
||||
|
||||
on:
|
||||
push
|
||||
|
||||
jobs:
|
||||
run:
|
||||
if: ${{ github.repository_owner == 'HMCL-dev' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Mirror GitHub to Gitee
|
||||
uses: Yikun/[email protected]
|
||||
with:
|
||||
src: github/HMCL-dev
|
||||
dst: gitee/huanghongxun
|
||||
static_list: 'HMCL'
|
||||
force_update: true
|
||||
debug: true
|
||||
dst_key: ${{ secrets.GITEE_SYNC_BOT_PRIVATE_KEY }}
|
||||
dst_token: ${{ secrets.GITEE_SYNC_BOT_TOKEN }}
|
||||
cache_path: /github/workspace/hub-mirror-cache
|
||||
@@ -0,0 +1,32 @@
|
||||
name: Mirror Repository
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
|
||||
concurrency:
|
||||
group: mirror-repository
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
mirror:
|
||||
strategy:
|
||||
matrix:
|
||||
target:
|
||||
- name: Gitee
|
||||
repo: gitee.com/huanghongxun/HMCL
|
||||
user: 'hmcl-sync'
|
||||
token: 'GITEE_SYNC_TOKEN'
|
||||
- name: CNB
|
||||
repo: cnb.cool/HMCL-dev/HMCL
|
||||
user: 'cnb'
|
||||
token: 'CNB_SYNC_TOKEN'
|
||||
name: Mirror to ${{ matrix.target.name }}
|
||||
if: ${{ github.repository == 'HMCL-dev/HMCL' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Mirror GitHub to ${{ matrix.target.name }}
|
||||
run: |
|
||||
git clone --mirror "https://github.com/$GITHUB_REPOSITORY.git" -- repo
|
||||
cd repo
|
||||
git push -f --prune "https://${{ matrix.target.user }}:${{ secrets[matrix.target.token] }}@${{ matrix.target.repo }}.git" "refs/heads/*:refs/heads/*" "refs/tags/*:refs/tags/*"
|
||||
@@ -0,0 +1,125 @@
|
||||
name: Create Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# schedule:
|
||||
# - cron: '30 * * * *'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
check-update:
|
||||
if: ${{ github.repository_owner == 'HMCL-dev' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
include:
|
||||
- channel: dev
|
||||
task: checkUpdateDev
|
||||
- channel: stable
|
||||
task: checkUpdateStable
|
||||
runs-on: ubuntu-latest
|
||||
name: check-update-${{ matrix.channel }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '25'
|
||||
- name: Fetch last version
|
||||
run: ./gradlew ${{ matrix.task }} --no-daemon --info --stacktrace
|
||||
- name: Check for existing tags
|
||||
run: if [ -z "$(git tag -l "$HMCL_TAG_NAME")" ]; then echo "continue=true" >> $GITHUB_ENV; fi
|
||||
- name: Download artifacts
|
||||
if: ${{ env.continue == 'true' }}
|
||||
run: |
|
||||
wget "$HMCL_CI_DOWNLOAD_BASE_URI/HMCL-$HMCL_VERSION.exe"
|
||||
wget "$HMCL_CI_DOWNLOAD_BASE_URI/HMCL-$HMCL_VERSION.exe.sha256"
|
||||
wget "$HMCL_CI_DOWNLOAD_BASE_URI/HMCL-$HMCL_VERSION.jar"
|
||||
wget "$HMCL_CI_DOWNLOAD_BASE_URI/HMCL-$HMCL_VERSION.jar.sha256"
|
||||
wget "$HMCL_CI_DOWNLOAD_BASE_URI/HMCL-$HMCL_VERSION.sh"
|
||||
wget "$HMCL_CI_DOWNLOAD_BASE_URI/HMCL-$HMCL_VERSION.sh.sha256"
|
||||
- name: Verify artifacts
|
||||
if: ${{ env.continue == 'true' }}
|
||||
run: |
|
||||
export JAR_SHA256=$(cat HMCL-$HMCL_VERSION.jar.sha256 | tr -d '\n')
|
||||
export EXE_SHA256=$(cat HMCL-$HMCL_VERSION.exe.sha256 | tr -d '\n')
|
||||
export SH_SHA256=$(cat HMCL-$HMCL_VERSION.sh.sha256 | tr -d '\n')
|
||||
|
||||
echo "$JAR_SHA256 HMCL-$HMCL_VERSION.jar" | sha256sum -c
|
||||
echo "$EXE_SHA256 HMCL-$HMCL_VERSION.exe" | sha256sum -c
|
||||
echo "$SH_SHA256 HMCL-$HMCL_VERSION.sh" | sha256sum -c
|
||||
- name: Generate release note
|
||||
if: ${{ env.continue == 'true' }}
|
||||
run: |
|
||||
# GitHub Release Note
|
||||
echo " **[Changelog](https://docs.hmcl.net/changelog/${{ matrix.channel }}.html#HMCL-$HMCL_VERSION)** (Chinese)" >> RELEASE_NOTE
|
||||
echo "" >> RELEASE_NOTE
|
||||
echo "| File | SHA-256 Checksum |" >> RELEASE_NOTE
|
||||
echo "| --- | --- |" >> RELEASE_NOTE
|
||||
echo "| [HMCL-$HMCL_VERSION.exe]($GH_DOWNLOAD_BASE_URL/v$HMCL_VERSION/HMCL-$HMCL_VERSION.exe) | \`$(cat HMCL-$HMCL_VERSION.exe.sha256)\` |" >> RELEASE_NOTE
|
||||
echo "| [HMCL-$HMCL_VERSION.jar]($GH_DOWNLOAD_BASE_URL/v$HMCL_VERSION/HMCL-$HMCL_VERSION.jar) | \`$(cat HMCL-$HMCL_VERSION.jar.sha256)\` |" >> RELEASE_NOTE
|
||||
echo "| [HMCL-$HMCL_VERSION.sh]($GH_DOWNLOAD_BASE_URL/v$HMCL_VERSION/HMCL-$HMCL_VERSION.sh) | \`$(cat HMCL-$HMCL_VERSION.sh.sha256)\` |" >> RELEASE_NOTE
|
||||
|
||||
# CNB Release Note
|
||||
echo "[更新日志](https://docs.hmcl.net/changelog/${{ matrix.channel }}.html#HMCL-$HMCL_VERSION)" >> CNB_RELEASE_NOTE
|
||||
echo "" >> CNB_RELEASE_NOTE
|
||||
echo "| 文件 | SHA-256 校验码 |" >> CNB_RELEASE_NOTE
|
||||
echo "| :--- | --- |" >> CNB_RELEASE_NOTE
|
||||
echo "| [HMCL-$HMCL_VERSION.exe]($CNB_DOWNLOAD_BASE_URL/v$HMCL_VERSION/HMCL-$HMCL_VERSION.exe) | \`$(cat HMCL-$HMCL_VERSION.exe.sha256)\` |" >> CNB_RELEASE_NOTE
|
||||
echo "| [HMCL-$HMCL_VERSION.jar]($CNB_DOWNLOAD_BASE_URL/v$HMCL_VERSION/HMCL-$HMCL_VERSION.jar) | \`$(cat HMCL-$HMCL_VERSION.jar.sha256)\` |" >> CNB_RELEASE_NOTE
|
||||
echo "| [HMCL-$HMCL_VERSION.sh]($CNB_DOWNLOAD_BASE_URL/v$HMCL_VERSION/HMCL-$HMCL_VERSION.sh) | \`$(cat HMCL-$HMCL_VERSION.sh.sha256)\` |" >> CNB_RELEASE_NOTE
|
||||
env:
|
||||
GH_DOWNLOAD_BASE_URL: https://github.com/${{ github.repository }}/releases/download
|
||||
CNB_DOWNLOAD_BASE_URL: https://cnb.cool/HMCL-dev/HMCL/-/releases/download
|
||||
- name: Create GitHub release
|
||||
if: ${{ env.continue == 'true' }}
|
||||
run: |
|
||||
gh release create "${{ env.HMCL_TAG_NAME }}" \
|
||||
"HMCL-${{ env.HMCL_VERSION }}.exe" \
|
||||
"HMCL-${{ env.HMCL_VERSION }}.jar" \
|
||||
"HMCL-${{ env.HMCL_VERSION }}.sh" \
|
||||
--target "${{ env.HMCL_COMMIT_SHA }}" \
|
||||
--title "${{ env.HMCL_TAG_NAME }}" \
|
||||
--notes-file RELEASE_NOTE \
|
||||
--prerelease
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Install git-cnb
|
||||
if: ${{ env.continue == 'true' }}
|
||||
run: go install "cnb.cool/looc/git-cnb@$GIT_CNB_VERSION"
|
||||
env:
|
||||
GIT_CNB_VERSION: '1.1.2'
|
||||
- name: Create CNB release
|
||||
if: ${{ env.continue == 'true' }}
|
||||
run: |
|
||||
echo "Uploading tags to CNB"
|
||||
git fetch --tags
|
||||
git push "https://cnb:${{ secrets.CNB_SYNC_TOKEN }}@cnb.cool/$CNB_REPO.git" "$HMCL_TAG_NAME"
|
||||
|
||||
echo "Creating CNB release"
|
||||
~/go/bin/git-cnb release create \
|
||||
--repo "$CNB_REPO" \
|
||||
--tag "$HMCL_TAG_NAME" \
|
||||
--name "HMCL $HMCL_VERSION" \
|
||||
--body "$(cat CNB_RELEASE_NOTE)" \
|
||||
--prerelease true
|
||||
|
||||
echo "Uploading HMCL-$HMCL_VERSION.jar"
|
||||
~/go/bin/git-cnb release asset-upload --repo="$CNB_REPO" --tag-name "$HMCL_TAG_NAME" --file-name "HMCL-$HMCL_VERSION.jar"
|
||||
|
||||
echo "Uploading HMCL-$HMCL_VERSION.exe"
|
||||
~/go/bin/git-cnb release asset-upload --repo="$CNB_REPO" --tag-name "$HMCL_TAG_NAME" --file-name "HMCL-$HMCL_VERSION.exe"
|
||||
|
||||
echo "Uploading HMCL-$HMCL_VERSION.sh"
|
||||
~/go/bin/git-cnb release asset-upload --repo="$CNB_REPO" --tag-name "$HMCL_TAG_NAME" --file-name "HMCL-$HMCL_VERSION.sh"
|
||||
env:
|
||||
CNB_TOKEN: ${{ secrets.CNB_SYNC_TOKEN }}
|
||||
CNB_REPO: HMCL-dev/HMCL
|
||||
@@ -116,9 +116,9 @@ public class JFXCustomColorPickerDialog extends StackPane {
|
||||
Tab hexTab = new Tab("HEX");
|
||||
hexTab.setContent(hexField);
|
||||
|
||||
tabs.getTabs().add(hexTab);
|
||||
tabs.getTabs().add(rgbTab);
|
||||
tabs.getTabs().add(hsbTab);
|
||||
tabs.getTabs().add(hexTab);
|
||||
|
||||
curvedColorPicker.selectedPath.addListener((o, oldVal, newVal) -> {
|
||||
if (paraTransition != null) {
|
||||
|
||||
@@ -39,7 +39,10 @@ public class JFXListViewSkin<T> extends ListViewSkin<T> {
|
||||
flow = (VirtualFlow<ListCell<T>>) getChildren().get(0);
|
||||
JFXDepthManager.setDepth(flow, listView.depthProperty().get());
|
||||
listView.depthProperty().addListener((o, oldVal, newVal) -> JFXDepthManager.setDepth(flow, newVal));
|
||||
FXUtils.smoothScrolling(flow);
|
||||
|
||||
if (!Boolean.TRUE.equals(listView.getProperties().get("no-smooth-scrolling"))) {
|
||||
FXUtils.smoothScrolling(flow);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,20 +25,20 @@ import org.jackhuang.hmcl.Metadata;
|
||||
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||
import org.jackhuang.hmcl.event.Event;
|
||||
import org.jackhuang.hmcl.event.EventManager;
|
||||
import org.jackhuang.hmcl.java.JavaRuntime;
|
||||
import org.jackhuang.hmcl.mod.ModAdviser;
|
||||
import org.jackhuang.hmcl.mod.Modpack;
|
||||
import org.jackhuang.hmcl.mod.ModpackConfiguration;
|
||||
import org.jackhuang.hmcl.mod.ModpackProvider;
|
||||
import org.jackhuang.hmcl.setting.Profile;
|
||||
import org.jackhuang.hmcl.util.FileSaver;
|
||||
import org.jackhuang.hmcl.setting.VersionIconType;
|
||||
import org.jackhuang.hmcl.setting.VersionSetting;
|
||||
import org.jackhuang.hmcl.ui.FXUtils;
|
||||
import org.jackhuang.hmcl.util.FileSaver;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.java.JavaRuntime;
|
||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||
import org.jackhuang.hmcl.util.platform.SystemInfo;
|
||||
import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
|
||||
@@ -55,8 +55,8 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
import static org.jackhuang.hmcl.util.Pair.pair;
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
|
||||
public final class HMCLGameRepository extends DefaultGameRepository {
|
||||
private final Profile profile;
|
||||
@@ -387,7 +387,7 @@ public final class HMCLGameRepository extends DefaultGameRepository {
|
||||
vs.setUsesGlobal(true);
|
||||
}
|
||||
|
||||
public LaunchOptions getLaunchOptions(String version, JavaRuntime javaVersion, Path gameDir, List<String> javaAgents, List<String> javaArguments, boolean makeLaunchScript) {
|
||||
public LaunchOptions.Builder getLaunchOptions(String version, JavaRuntime javaVersion, Path gameDir, List<String> javaAgents, List<String> javaArguments, boolean makeLaunchScript) {
|
||||
VersionSetting vs = getVersionSetting(version);
|
||||
|
||||
LaunchOptions.Builder builder = new LaunchOptions.Builder()
|
||||
@@ -418,7 +418,6 @@ public final class HMCLGameRepository extends DefaultGameRepository {
|
||||
.setWidth(vs.getWidth())
|
||||
.setHeight(vs.getHeight())
|
||||
.setFullscreen(vs.isFullscreen())
|
||||
.setServerIp(vs.getServerIp())
|
||||
.setWrapper(vs.getWrapper())
|
||||
.setPreLaunchCommand(vs.getPreLaunchCommand())
|
||||
.setPostExitCommand(vs.getPostExitCommand())
|
||||
@@ -428,12 +427,17 @@ public final class HMCLGameRepository extends DefaultGameRepository {
|
||||
.setNativesDir(vs.getNativesDir())
|
||||
.setProcessPriority(vs.getProcessPriority())
|
||||
.setRenderer(vs.getRenderer())
|
||||
.setEnableDebugLogOutput(vs.isEnableDebugLogOutput())
|
||||
.setUseNativeGLFW(vs.isUseNativeGLFW())
|
||||
.setUseNativeOpenAL(vs.isUseNativeOpenAL())
|
||||
.setDaemon(!makeLaunchScript && vs.getLauncherVisibility().isDaemon())
|
||||
.setJavaAgents(javaAgents)
|
||||
.setJavaArguments(javaArguments);
|
||||
|
||||
if (StringUtils.isNotBlank(vs.getServerIp())) {
|
||||
builder.setQuickPlayOption(new QuickPlayOption.MultiPlayer(vs.getServerIp()));
|
||||
}
|
||||
|
||||
if (config().hasProxy()) {
|
||||
builder.setProxyType(config().getProxyType());
|
||||
builder.setProxyHost(config().getProxyHost());
|
||||
@@ -460,7 +464,7 @@ public final class HMCLGameRepository extends DefaultGameRepository {
|
||||
if (vs.isAutoMemory() && builder.getJavaArguments().stream().anyMatch(it -> it.startsWith("-Xmx")))
|
||||
builder.setMaxMemory(null);
|
||||
|
||||
return builder.create();
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,6 +22,7 @@ import javafx.stage.Stage;
|
||||
import org.jackhuang.hmcl.Launcher;
|
||||
import org.jackhuang.hmcl.auth.*;
|
||||
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorDownloadException;
|
||||
import org.jackhuang.hmcl.auth.offline.OfflineAccount;
|
||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||
@@ -51,6 +52,7 @@ import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.AccessDeniedException;
|
||||
@@ -60,7 +62,6 @@ import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Collectors;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import static javafx.application.Platform.runLater;
|
||||
import static javafx.application.Platform.setImplicitExit;
|
||||
@@ -81,6 +82,8 @@ public final class LauncherHelper {
|
||||
private final VersionSetting setting;
|
||||
private LauncherVisibility launcherVisibility;
|
||||
private boolean showLogs;
|
||||
private QuickPlayOption quickPlayOption;
|
||||
private boolean disableOfflineSkin = false;
|
||||
|
||||
public LauncherHelper(Profile profile, Account account, String selectedVersion) {
|
||||
this.profile = Objects.requireNonNull(profile);
|
||||
@@ -111,6 +114,14 @@ public final class LauncherHelper {
|
||||
launcherVisibility = LauncherVisibility.KEEP;
|
||||
}
|
||||
|
||||
public void setQuickPlayOption(QuickPlayOption quickPlayOption) {
|
||||
this.quickPlayOption = quickPlayOption;
|
||||
}
|
||||
|
||||
public void setDisableOfflineSkin() {
|
||||
disableOfflineSkin = true;
|
||||
}
|
||||
|
||||
public void launch() {
|
||||
FXUtils.checkFxUserThread();
|
||||
|
||||
@@ -188,8 +199,15 @@ public final class LauncherHelper {
|
||||
.thenComposeAsync(() -> gameVersion.map(s -> new GameVerificationFixTask(dependencyManager, s, version.get())).orElse(null))
|
||||
.thenComposeAsync(() -> logIn(account).withStage("launch.state.logging_in"))
|
||||
.thenComposeAsync(authInfo -> Task.supplyAsync(() -> {
|
||||
LaunchOptions launchOptions = repository.getLaunchOptions(
|
||||
LaunchOptions.Builder launchOptionsBuilder = repository.getLaunchOptions(
|
||||
selectedVersion, javaVersionRef.get(), profile.getGameDir(), javaAgents, javaArguments, scriptFile != null);
|
||||
if (disableOfflineSkin) {
|
||||
launchOptionsBuilder.setDaemon(false);
|
||||
}
|
||||
if (quickPlayOption != null) {
|
||||
launchOptionsBuilder.setQuickPlayOption(quickPlayOption);
|
||||
}
|
||||
LaunchOptions launchOptions = launchOptionsBuilder.create();
|
||||
|
||||
LOG.info("Here's the structure of game mod directory:\n" + FileUtils.printFileStructure(repository.getModsDirectory(selectedVersion), 10));
|
||||
|
||||
@@ -639,10 +657,13 @@ public final class LauncherHelper {
|
||||
return future;
|
||||
}
|
||||
|
||||
private static Task<AuthInfo> logIn(Account account) {
|
||||
private Task<AuthInfo> logIn(Account account) {
|
||||
return Task.composeAsync(() -> {
|
||||
try {
|
||||
return Task.completed(account.logIn());
|
||||
if (disableOfflineSkin && account instanceof OfflineAccount offlineAccount)
|
||||
return Task.completed(offlineAccount.logInWithoutSkin());
|
||||
else
|
||||
return Task.completed(account.logIn());
|
||||
} catch (CredentialExpiredException e) {
|
||||
LOG.info("Credential has expired", e);
|
||||
|
||||
|
||||
@@ -459,6 +459,20 @@ public final class VersionSetting implements Cloneable, Observable {
|
||||
showLogsProperty.set(showLogs);
|
||||
}
|
||||
|
||||
private final BooleanProperty enableDebugLogOutputProperty = new SimpleBooleanProperty(this, "enableDebugLogOutput", false);
|
||||
|
||||
public BooleanProperty enableDebugLogOutputProperty() {
|
||||
return enableDebugLogOutputProperty;
|
||||
}
|
||||
|
||||
public boolean isEnableDebugLogOutput() {
|
||||
return enableDebugLogOutputProperty.get();
|
||||
}
|
||||
|
||||
public void setEnableDebugLogOutput(boolean u) {
|
||||
this.enableDebugLogOutputProperty.set(u);
|
||||
}
|
||||
|
||||
// Minecraft settings.
|
||||
|
||||
private final StringProperty serverIpProperty = new SimpleStringProperty(this, "serverIp", "");
|
||||
@@ -776,6 +790,7 @@ public final class VersionSetting implements Cloneable, Observable {
|
||||
obj.addProperty("notCheckJVM", src.isNotCheckJVM());
|
||||
obj.addProperty("notPatchNatives", src.isNotPatchNatives());
|
||||
obj.addProperty("showLogs", src.isShowLogs());
|
||||
obj.addProperty("enableDebugLogOutput", src.isEnableDebugLogOutput());
|
||||
obj.addProperty("gameDir", src.getGameDir());
|
||||
obj.addProperty("launcherVisibility", src.getLauncherVisibility().ordinal());
|
||||
obj.addProperty("processPriority", src.getProcessPriority().ordinal());
|
||||
@@ -847,6 +862,7 @@ public final class VersionSetting implements Cloneable, Observable {
|
||||
vs.setNotCheckJVM(Optional.ofNullable(obj.get("notCheckJVM")).map(JsonElement::getAsBoolean).orElse(false));
|
||||
vs.setNotPatchNatives(Optional.ofNullable(obj.get("notPatchNatives")).map(JsonElement::getAsBoolean).orElse(false));
|
||||
vs.setShowLogs(Optional.ofNullable(obj.get("showLogs")).map(JsonElement::getAsBoolean).orElse(false));
|
||||
vs.setEnableDebugLogOutput(Optional.ofNullable(obj.get("enableDebugLogOutput")).map(JsonElement::getAsBoolean).orElse(false));
|
||||
vs.setLauncherVisibility(parseJsonPrimitive(obj.getAsJsonPrimitive("launcherVisibility"), LauncherVisibility.class, LauncherVisibility.HIDE));
|
||||
vs.setProcessPriority(parseJsonPrimitive(obj.getAsJsonPrimitive("processPriority"), ProcessPriority.class, ProcessPriority.NORMAL));
|
||||
vs.setUseNativeGLFW(Optional.ofNullable(obj.get("useNativeGLFW")).map(JsonElement::getAsBoolean).orElse(false));
|
||||
|
||||
@@ -400,6 +400,8 @@ public class GameCrashWindow extends Stage {
|
||||
reasonPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
||||
reasonPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
|
||||
|
||||
feedbackTextFlow.getStyleClass().add("crash-reason-text-flow");
|
||||
|
||||
gameDirPane.setPadding(new Insets(8));
|
||||
VBox.setVgrow(gameDirPane, Priority.ALWAYS);
|
||||
FXUtils.onChangeAndOperate(feedbackTextFlow.visibleProperty(), visible -> {
|
||||
|
||||
@@ -204,6 +204,7 @@ public final class LogWindow extends Stage {
|
||||
LogWindowImpl() {
|
||||
getStyleClass().add("log-window");
|
||||
|
||||
listView.getProperties().put("no-smooth-scrolling", true);
|
||||
listView.setItems(FXCollections.observableList(new CircularArrayList<>(logs.size())));
|
||||
|
||||
for (int i = 0; i < LEVELS.length; i++) {
|
||||
|
||||
@@ -25,7 +25,6 @@ import javafx.animation.Animation.Status;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.scene.control.IndexedCell;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.skin.VirtualFlow;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
@@ -226,7 +225,6 @@ final class ScrollUtils {
|
||||
final double[] derivatives = new double[FRICTIONS.length];
|
||||
|
||||
Timeline timeline = new Timeline();
|
||||
Holder<ScrollDirection> scrollDirectionHolder = new Holder<>();
|
||||
final EventHandler<MouseEvent> mouseHandler = event -> timeline.stop();
|
||||
final EventHandler<ScrollEvent> scrollHandler = event -> {
|
||||
if (event.getEventType() == ScrollEvent.SCROLL) {
|
||||
@@ -234,7 +232,6 @@ final class ScrollUtils {
|
||||
if (scrollDirection == ScrollDirection.LEFT || scrollDirection == ScrollDirection.RIGHT) {
|
||||
return;
|
||||
}
|
||||
scrollDirectionHolder.value = scrollDirection;
|
||||
double currentSpeed = isTrackPad(event, scrollDirection) ? speed / trackPadAdjustment : speed;
|
||||
|
||||
derivatives[0] += scrollDirection.intDirection * currentSpeed;
|
||||
@@ -256,15 +253,7 @@ final class ScrollUtils {
|
||||
}
|
||||
|
||||
double dy = derivatives[derivatives.length - 1];
|
||||
|
||||
int cellCount = virtualFlow.getCellCount();
|
||||
IndexedCell<?> firstVisibleCell = virtualFlow.getFirstVisibleCell();
|
||||
double height = firstVisibleCell != null ? firstVisibleCell.getHeight() * cellCount : 0.0;
|
||||
|
||||
double delta = height > 0.0
|
||||
? dy / height
|
||||
: (scrollDirectionHolder.value == ScrollDirection.DOWN ? 0.001 : -0.001);
|
||||
virtualFlow.setPosition(Math.min(Math.max(virtualFlow.getPosition() + delta, 0), 1));
|
||||
virtualFlow.scrollPixels(dy);
|
||||
|
||||
if (Math.abs(dy) < 0.001) {
|
||||
timeline.stop();
|
||||
|
||||
@@ -68,6 +68,10 @@ public class AccountAdvancedListItem extends AdvancedListItem {
|
||||
};
|
||||
|
||||
public AccountAdvancedListItem() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public AccountAdvancedListItem(Account account) {
|
||||
tooltip = new Tooltip();
|
||||
FXUtils.installFastTooltip(this, tooltip);
|
||||
|
||||
@@ -76,9 +80,13 @@ public class AccountAdvancedListItem extends AdvancedListItem {
|
||||
|
||||
setActionButtonVisible(false);
|
||||
|
||||
FXUtils.onScroll(this, Accounts.getAccounts(),
|
||||
accounts -> accounts.indexOf(account.get()),
|
||||
Accounts::setSelectedAccount);
|
||||
if (account != null) {
|
||||
this.accountProperty().set(account);
|
||||
} else {
|
||||
FXUtils.onScroll(this, Accounts.getAccounts(),
|
||||
accounts -> accounts.indexOf(accountProperty().get()),
|
||||
Accounts::setSelectedAccount);
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectProperty<Account> accountProperty() {
|
||||
|
||||
@@ -31,7 +31,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
public class TransitionPane extends StackPane {
|
||||
|
||||
private Node currentNode;
|
||||
private Animation oldAnimation;
|
||||
|
||||
public TransitionPane() {
|
||||
FXUtils.setOverflowHidden(this);
|
||||
@@ -51,11 +50,6 @@ public class TransitionPane extends StackPane {
|
||||
|
||||
public void setContent(Node newView, AnimationProducer transition,
|
||||
Duration duration, Interpolator interpolator) {
|
||||
if (oldAnimation != null) {
|
||||
oldAnimation.stop();
|
||||
oldAnimation = null;
|
||||
}
|
||||
|
||||
Node previousNode = currentNode != newView && getWidth() > 0 && getHeight() > 0 ? currentNode : null;
|
||||
currentNode = newView;
|
||||
|
||||
@@ -86,19 +80,15 @@ public class TransitionPane extends StackPane {
|
||||
previousNode,
|
||||
newView,
|
||||
duration, interpolator);
|
||||
newAnimation.statusProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (oldValue == Animation.Status.RUNNING && newValue != Animation.Status.RUNNING) {
|
||||
setMouseTransparent(false);
|
||||
getChildren().remove(previousNode);
|
||||
newAnimation.setOnFinished(e -> {
|
||||
setMouseTransparent(false);
|
||||
getChildren().remove(previousNode);
|
||||
|
||||
if (cacheHint != null) {
|
||||
newView.setCache(false);
|
||||
}
|
||||
if (cacheHint != null) {
|
||||
newView.setCache(false);
|
||||
}
|
||||
});
|
||||
|
||||
oldAnimation = newAnimation;
|
||||
newAnimation.play();
|
||||
FXUtils.playAnimation(this, "transition_pane", newAnimation);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -51,8 +51,9 @@ public class OptionToggleButton extends StackPane {
|
||||
Label titleLabel = new Label();
|
||||
titleLabel.textProperty().bind(title);
|
||||
Label subtitleLabel = new Label();
|
||||
subtitleLabel.setMouseTransparent(true);
|
||||
subtitleLabel.setWrapText(true);
|
||||
subtitleLabel.setMouseTransparent(true);
|
||||
subtitleLabel.getStyleClass().add("subtitle");
|
||||
subtitleLabel.textProperty().bind(subtitle);
|
||||
pane.setCenter(left);
|
||||
left.setAlignment(Pos.CENTER_LEFT);
|
||||
|
||||
@@ -373,9 +373,8 @@ public class DecoratorController {
|
||||
if (navigator.getCurrentPage() instanceof DecoratorPage) {
|
||||
DecoratorPage page = (DecoratorPage) navigator.getCurrentPage();
|
||||
|
||||
// FIXME: Get WorldPage working first, and revisit this later
|
||||
page.closePage();
|
||||
if (page.isPageCloseable()) {
|
||||
page.closePage();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,34 +43,41 @@ public class FeedbackPage extends SpinnerPane {
|
||||
FXUtils.smoothScrolling(scrollPane);
|
||||
setContent(scrollPane);
|
||||
|
||||
ComponentList community = new ComponentList();
|
||||
ComponentList groups = new ComponentList();
|
||||
{
|
||||
IconedTwoLineListItem users = new IconedTwoLineListItem();
|
||||
users.setImage(FXUtils.newBuiltinImage("/assets/img/icon.png"));
|
||||
users.setTitle(i18n("feedback.qq_group"));
|
||||
users.setSubtitle(i18n("feedback.qq_group.statement"));
|
||||
users.setTitle(i18n("contact.chat.qq_group"));
|
||||
users.setSubtitle(i18n("contact.chat.qq_group.statement"));
|
||||
users.setExternalLink(Metadata.GROUPS_URL);
|
||||
|
||||
IconedTwoLineListItem discord = new IconedTwoLineListItem();
|
||||
discord.setImage(FXUtils.newBuiltinImage("/assets/img/discord.png"));
|
||||
discord.setTitle(i18n("contact.chat.discord"));
|
||||
discord.setSubtitle(i18n("contact.chat.discord.statement"));
|
||||
discord.setExternalLink("https://discord.gg/jVvC7HfM6U");
|
||||
|
||||
groups.getContent().setAll(users, discord);
|
||||
}
|
||||
|
||||
ComponentList feedback = new ComponentList();
|
||||
{
|
||||
IconedTwoLineListItem github = new IconedTwoLineListItem();
|
||||
github.imageProperty().bind(Bindings.when(Themes.darkModeProperty())
|
||||
.then(FXUtils.newBuiltinImage("/assets/img/github-white.png"))
|
||||
.otherwise(FXUtils.newBuiltinImage("/assets/img/github.png")));
|
||||
github.setTitle(i18n("feedback.github"));
|
||||
github.setSubtitle(i18n("feedback.github.statement"));
|
||||
github.setTitle(i18n("contact.feedback.github"));
|
||||
github.setSubtitle(i18n("contact.feedback.github.statement"));
|
||||
github.setExternalLink("https://github.com/HMCL-dev/HMCL/issues/new/choose");
|
||||
|
||||
IconedTwoLineListItem discord = new IconedTwoLineListItem();
|
||||
discord.setImage(FXUtils.newBuiltinImage("/assets/img/discord.png"));
|
||||
discord.setTitle(i18n("feedback.discord"));
|
||||
discord.setSubtitle(i18n("feedback.discord.statement"));
|
||||
discord.setExternalLink("https://discord.gg/jVvC7HfM6U");
|
||||
|
||||
community.getContent().setAll(users, github, discord);
|
||||
feedback.getContent().setAll(github);
|
||||
}
|
||||
|
||||
content.getChildren().addAll(
|
||||
ComponentList.createComponentListTitle(i18n("feedback.channel")),
|
||||
community
|
||||
ComponentList.createComponentListTitle(i18n("contact.chat")),
|
||||
groups,
|
||||
ComponentList.createComponentListTitle(i18n("contact.feedback")),
|
||||
feedback
|
||||
);
|
||||
|
||||
this.setContent(content);
|
||||
|
||||
@@ -69,7 +69,7 @@ public class LauncherSettingsPage extends DecoratorAnimatedPage implements Decor
|
||||
.addNavigationDrawerTab(tab, downloadTab, i18n("download"), SVG.DOWNLOAD)
|
||||
.startCategory(i18n("help").toUpperCase(Locale.ROOT))
|
||||
.addNavigationDrawerTab(tab, helpTab, i18n("help"), SVG.HELP, SVG.HELP_FILL)
|
||||
.addNavigationDrawerTab(tab, feedbackTab, i18n("feedback"), SVG.FEEDBACK, SVG.FEEDBACK_FILL)
|
||||
.addNavigationDrawerTab(tab, feedbackTab, i18n("contact"), SVG.FEEDBACK, SVG.FEEDBACK_FILL)
|
||||
.addNavigationDrawerTab(tab, aboutTab, i18n("about"), SVG.INFO, SVG.INFO_FILL);
|
||||
FXUtils.setLimitWidth(sideBar, 200);
|
||||
setLeft(sideBar);
|
||||
|
||||
@@ -346,7 +346,7 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
|
||||
private void launch() {
|
||||
Profile profile = Profiles.getSelectedProfile();
|
||||
Versions.launch(profile, profile.getSelectedVersion(), null);
|
||||
Versions.launch(profile, profile.getSelectedVersion());
|
||||
}
|
||||
|
||||
private void launchNoGame() {
|
||||
|
||||
@@ -44,6 +44,7 @@ import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.javafx.SafeStringConverter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -86,8 +87,11 @@ public class PersonalizationPage extends StackPane {
|
||||
|
||||
brightnessPane.setLeft(left);
|
||||
|
||||
JFXComboBox<String> cboBrightness = new JFXComboBox<>(
|
||||
FXCollections.observableArrayList("auto", "light", "dark"));
|
||||
JFXComboBox<String> cboBrightness = new JFXComboBox<>(FXCollections.observableArrayList(
|
||||
FXUtils.DARK_MODE != null
|
||||
? List.of("auto", "light", "dark")
|
||||
: List.of("light", "dark")
|
||||
));
|
||||
cboBrightness.setConverter(FXUtils.stringConverter(name -> i18n("settings.launcher.brightness." + name)));
|
||||
cboBrightness.valueProperty().bindBidirectional(config().themeBrightnessProperty());
|
||||
brightnessPane.setRight(cboBrightness);
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.ui.main;
|
||||
|
||||
import com.jfoenix.controls.JFXPopup;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
|
||||
import javafx.scene.input.MouseButton;
|
||||
import org.jackhuang.hmcl.Metadata;
|
||||
import org.jackhuang.hmcl.auth.Account;
|
||||
import org.jackhuang.hmcl.event.EventBus;
|
||||
import org.jackhuang.hmcl.event.RefreshedVersionsEvent;
|
||||
import org.jackhuang.hmcl.game.HMCLGameRepository;
|
||||
@@ -39,6 +41,7 @@ import org.jackhuang.hmcl.ui.animation.AnimationUtils;
|
||||
import org.jackhuang.hmcl.ui.construct.AdvancedListBox;
|
||||
import org.jackhuang.hmcl.ui.construct.AdvancedListItem;
|
||||
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
|
||||
import org.jackhuang.hmcl.ui.construct.PopupMenu;
|
||||
import org.jackhuang.hmcl.ui.decorator.DecoratorAnimatedPage;
|
||||
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
|
||||
import org.jackhuang.hmcl.ui.download.ModpackInstallWizardProvider;
|
||||
@@ -64,8 +67,8 @@ import java.util.stream.Collectors;
|
||||
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
|
||||
import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap;
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
|
||||
public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
|
||||
private MainPage mainPage = null;
|
||||
@@ -144,6 +147,13 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
|
||||
// first item in left sidebar
|
||||
AccountAdvancedListItem accountListItem = new AccountAdvancedListItem();
|
||||
accountListItem.setOnAction(e -> Controllers.navigate(Controllers.getAccountListPage()));
|
||||
accountListItem.setOnMouseClicked(e -> {
|
||||
if (e.getButton() == MouseButton.SECONDARY) {
|
||||
if (!Accounts.getAccounts().isEmpty())
|
||||
showAccountListPopupMenu(accountListItem);
|
||||
e.consume();
|
||||
}
|
||||
});
|
||||
accountListItem.accountProperty().bind(Accounts.selectedAccountProperty());
|
||||
|
||||
// second item in left sidebar
|
||||
@@ -234,13 +244,39 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
|
||||
.startCategory(i18n("settings.launcher.general").toUpperCase(Locale.ROOT))
|
||||
.add(launcherSettingsItem)
|
||||
.add(terracottaItem)
|
||||
.addNavigationDrawerItem(i18n("chat"), SVG.CHAT, () -> FXUtils.openLink(Metadata.GROUPS_URL));
|
||||
.addNavigationDrawerItem(i18n("contact.chat"), SVG.CHAT, () -> {
|
||||
Controllers.getSettingsPage().showFeedback();
|
||||
Controllers.navigate(Controllers.getSettingsPage());
|
||||
});
|
||||
|
||||
// the root page, with the sidebar in left, navigator in center.
|
||||
setLeft(sideBar);
|
||||
setCenter(getSkinnable().getMainPage());
|
||||
}
|
||||
|
||||
public void showAccountListPopupMenu(
|
||||
AccountAdvancedListItem accountListItem
|
||||
) {
|
||||
PopupMenu popupMenu = new PopupMenu();
|
||||
JFXPopup popup = new JFXPopup(popupMenu);
|
||||
AdvancedListBox scrollPane = new AdvancedListBox();
|
||||
scrollPane.getStyleClass().add("no-padding");
|
||||
scrollPane.setPrefWidth(220);
|
||||
scrollPane.setPrefHeight(-1);
|
||||
scrollPane.setMaxHeight(260);
|
||||
|
||||
for (Account account : Accounts.getAccounts()) {
|
||||
AccountAdvancedListItem item = new AccountAdvancedListItem(account);
|
||||
item.setOnAction(e -> {
|
||||
Accounts.setSelectedAccount(account);
|
||||
popup.hide();
|
||||
});
|
||||
scrollPane.add(item);
|
||||
}
|
||||
|
||||
popupMenu.getContent().add(scrollPane);
|
||||
popup.show(accountListItem, JFXPopup.PopupVPosition.TOP, JFXPopup.PopupHPosition.LEFT, accountListItem.getWidth(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkedModpack = false;
|
||||
|
||||
@@ -210,8 +210,8 @@ public final class SettingsPage extends ScrollPane {
|
||||
{
|
||||
OptionToggleButton previewPane = new OptionToggleButton();
|
||||
previewPane.setTitle(i18n("update.preview"));
|
||||
previewPane.setSubtitle(i18n("update.preview.subtitle"));
|
||||
previewPane.selectedProperty().bindBidirectional(config().acceptPreviewUpdateProperty());
|
||||
FXUtils.installFastTooltip(previewPane, i18n("update.preview.tooltip"));
|
||||
|
||||
ObjectProperty<UpdateChannel> updateChannel = selectedItemPropertyFor(updateChannelGroup, UpdateChannel.class);
|
||||
updateChannel.set(UpdateChannel.getChannel());
|
||||
|
||||
@@ -167,7 +167,7 @@ public class TerracottaControllerPage extends StackPane {
|
||||
progressProperty.set(0);
|
||||
|
||||
TextFlow body = FXUtils.segmentToTextFlow(i18n("terracotta.confirm.desc"), Controllers::onHyperlinkAction);
|
||||
body.getStyleClass().add("terracotta-license");
|
||||
body.getStyleClass().add("terracotta-hint");
|
||||
body.setLineSpacing(4);
|
||||
|
||||
LineButton download = LineButton.of();
|
||||
@@ -211,7 +211,7 @@ public class TerracottaControllerPage extends StackPane {
|
||||
progressProperty.set(1);
|
||||
|
||||
TextFlow flow = FXUtils.segmentToTextFlow(i18n("terracotta.confirm.desc"), Controllers::onHyperlinkAction);
|
||||
flow.getStyleClass().add("terracotta-license");
|
||||
flow.getStyleClass().add("terracotta-hint");
|
||||
flow.setLineSpacing(4);
|
||||
|
||||
LineButton host = LineButton.of();
|
||||
@@ -232,7 +232,10 @@ public class TerracottaControllerPage extends StackPane {
|
||||
MessageDialogPane.MessageType.QUESTION
|
||||
).addAction(i18n("version.launch"), () -> {
|
||||
Profile profile = Profiles.getSelectedProfile();
|
||||
Versions.launch(profile, profile.getSelectedVersion(), LauncherHelper::setKeep);
|
||||
Versions.launch(profile, profile.getSelectedVersion(), launcherHelper -> {
|
||||
launcherHelper.setKeep();
|
||||
launcherHelper.setDisableOfflineSkin();
|
||||
});
|
||||
}).addCancel(i18n("terracotta.status.waiting.host.launch.skip"), () -> {
|
||||
TerracottaState.HostScanning s1 = TerracottaManager.setScanning();
|
||||
if (s1 != null) {
|
||||
@@ -283,6 +286,7 @@ public class TerracottaControllerPage extends StackPane {
|
||||
progressProperty.set(-1);
|
||||
|
||||
TextFlow body = FXUtils.segmentToTextFlow(i18n("terracotta.status.scanning.desc"), Controllers::onHyperlinkAction);
|
||||
body.getStyleClass().add("terracotta-hint");
|
||||
body.setLineSpacing(4);
|
||||
|
||||
LineButton room = LineButton.of();
|
||||
|
||||
@@ -24,7 +24,6 @@ import javafx.geometry.Insets;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
import org.jackhuang.hmcl.game.LauncherHelper;
|
||||
import org.jackhuang.hmcl.setting.Profile;
|
||||
import org.jackhuang.hmcl.setting.Profiles;
|
||||
import org.jackhuang.hmcl.terracotta.TerracottaMetadata;
|
||||
@@ -71,7 +70,10 @@ public class TerracottaPage extends DecoratorAnimatedPage implements DecoratorPa
|
||||
AdvancedListBox toolbar = new AdvancedListBox()
|
||||
.addNavigationDrawerItem(i18n("version.launch"), SVG.ROCKET_LAUNCH, () -> {
|
||||
Profile profile = Profiles.getSelectedProfile();
|
||||
Versions.launch(profile, profile.getSelectedVersion(), LauncherHelper::setKeep);
|
||||
Versions.launch(profile, profile.getSelectedVersion(), launcherHelper -> {
|
||||
launcherHelper.setKeep();
|
||||
launcherHelper.setDisableOfflineSkin();
|
||||
});
|
||||
}, item -> {
|
||||
instanceChangeListenerHolder = FXUtils.onWeakChangeAndOperate(Profiles.selectedVersionProperty(),
|
||||
instanceName -> item.setSubtitle(StringUtils.isNotBlank(instanceName) ? instanceName : i18n("version.empty"))
|
||||
|
||||
@@ -85,10 +85,14 @@ public class GameListItem extends Control {
|
||||
Versions.openFolder(profile, version);
|
||||
}
|
||||
|
||||
public void launch() {
|
||||
public void testGame() {
|
||||
Versions.testGame(profile, version);
|
||||
}
|
||||
|
||||
public void launch() {
|
||||
Versions.launch(profile, version);
|
||||
}
|
||||
|
||||
public void modifyGameSettings() {
|
||||
Versions.modifyGameSettings(profile, version);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class GameListItemSkin extends SkinBase<GameListItem> {
|
||||
JFXPopup popup = new JFXPopup(menu);
|
||||
|
||||
menu.getContent().setAll(
|
||||
new IconedMenuItem(SVG.ROCKET_LAUNCH, i18n("version.launch.test"), () -> currentSkinnable.launch(), popup),
|
||||
new IconedMenuItem(SVG.ROCKET_LAUNCH, i18n("version.launch.test"), () -> currentSkinnable.testGame(), popup),
|
||||
new IconedMenuItem(SVG.SCRIPT, i18n("version.launch_script"), () -> currentSkinnable.generateLaunchScript(), popup),
|
||||
new MenuSeparator(),
|
||||
new IconedMenuItem(SVG.SETTINGS, i18n("version.manage.manage"), () -> currentSkinnable.modifyGameSettings(), popup),
|
||||
@@ -87,7 +87,7 @@ public class GameListItemSkin extends SkinBase<GameListItem> {
|
||||
|
||||
{
|
||||
JFXButton btnLaunch = new JFXButton();
|
||||
btnLaunch.setOnAction(e -> skinnable.launch());
|
||||
btnLaunch.setOnAction(e -> skinnable.testGame());
|
||||
btnLaunch.getStyleClass().add("toggle-icon4");
|
||||
BorderPane.setAlignment(btnLaunch, Pos.CENTER);
|
||||
btnLaunch.setGraphic(FXUtils.limitingSize(SVG.ROCKET_LAUNCH.createIcon(24), 24, 24));
|
||||
|
||||
@@ -111,6 +111,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
private final MultiFileItem.FileOption<GameDirectoryType> gameDirCustomOption;
|
||||
private final JFXComboBox<ProcessPriority> cboProcessPriority;
|
||||
private final OptionToggleButton showLogsPane;
|
||||
private final OptionToggleButton enableDebugLogOutputPane;
|
||||
private final ImagePickerItem iconPickerItem;
|
||||
|
||||
private final ChangeListener<Collection<JavaRuntime>> javaListChangeListener;
|
||||
@@ -410,6 +411,9 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
showLogsPane = new OptionToggleButton();
|
||||
showLogsPane.setTitle(i18n("settings.show_log"));
|
||||
|
||||
enableDebugLogOutputPane = new OptionToggleButton();
|
||||
enableDebugLogOutputPane.setTitle(i18n("settings.enable_debug_log_output"));
|
||||
|
||||
BorderPane processPriorityPane = new BorderPane();
|
||||
{
|
||||
Label label = new Label(i18n("settings.advanced.process_priority"));
|
||||
@@ -474,6 +478,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
launcherVisibilityPane,
|
||||
dimensionPane,
|
||||
showLogsPane,
|
||||
enableDebugLogOutputPane,
|
||||
processPriorityPane,
|
||||
serverPane,
|
||||
showAdvancedSettingPane
|
||||
@@ -551,6 +556,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
chkAutoAllocate.selectedProperty().unbindBidirectional(lastVersionSetting.autoMemoryProperty());
|
||||
chkFullscreen.selectedProperty().unbindBidirectional(lastVersionSetting.fullscreenProperty());
|
||||
showLogsPane.selectedProperty().unbindBidirectional(lastVersionSetting.showLogsProperty());
|
||||
enableDebugLogOutputPane.selectedProperty().unbindBidirectional(lastVersionSetting.enableDebugLogOutputProperty());
|
||||
FXUtils.unbindEnum(cboLauncherVisibility, lastVersionSetting.launcherVisibilityProperty());
|
||||
FXUtils.unbindEnum(cboProcessPriority, lastVersionSetting.processPriorityProperty());
|
||||
|
||||
@@ -585,6 +591,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
||||
chkAutoAllocate.selectedProperty().bindBidirectional(versionSetting.autoMemoryProperty());
|
||||
chkFullscreen.selectedProperty().bindBidirectional(versionSetting.fullscreenProperty());
|
||||
showLogsPane.selectedProperty().bindBidirectional(versionSetting.showLogsProperty());
|
||||
enableDebugLogOutputPane.selectedProperty().bindBidirectional(versionSetting.enableDebugLogOutputProperty());
|
||||
FXUtils.bindEnum(cboLauncherVisibility, versionSetting.launcherVisibilityProperty());
|
||||
FXUtils.bindEnum(cboProcessPriority, versionSetting.processPriorityProperty());
|
||||
|
||||
|
||||
@@ -23,10 +23,7 @@ import javafx.stage.FileChooser;
|
||||
import org.jackhuang.hmcl.auth.Account;
|
||||
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorAccount;
|
||||
import org.jackhuang.hmcl.download.game.GameAssetDownloadTask;
|
||||
import org.jackhuang.hmcl.game.GameDirectoryType;
|
||||
import org.jackhuang.hmcl.game.GameRepository;
|
||||
import org.jackhuang.hmcl.game.HMCLGameRepository;
|
||||
import org.jackhuang.hmcl.game.LauncherHelper;
|
||||
import org.jackhuang.hmcl.game.*;
|
||||
import org.jackhuang.hmcl.mod.RemoteMod;
|
||||
import org.jackhuang.hmcl.setting.*;
|
||||
import org.jackhuang.hmcl.task.*;
|
||||
@@ -200,7 +197,8 @@ public final class Versions {
|
||||
}
|
||||
}
|
||||
|
||||
public static void generateLaunchScript(Profile profile, String id) {
|
||||
@SafeVarargs
|
||||
public static void generateLaunchScript(Profile profile, String id, Consumer<LauncherHelper>... injecters) {
|
||||
if (!checkVersionForLaunching(profile, id))
|
||||
return;
|
||||
ensureSelectedAccount(account -> {
|
||||
@@ -209,23 +207,35 @@ public final class Versions {
|
||||
if (Files.isDirectory(repository.getRunDirectory(id)))
|
||||
chooser.setInitialDirectory(repository.getRunDirectory(id).toFile());
|
||||
chooser.setTitle(i18n("version.launch_script.save"));
|
||||
if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS) {
|
||||
chooser.getExtensionFilters().add(
|
||||
new FileChooser.ExtensionFilter(i18n("extension.command"), "*.command")
|
||||
);
|
||||
}
|
||||
chooser.getExtensionFilters().add(OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS
|
||||
? new FileChooser.ExtensionFilter(i18n("extension.bat"), "*.bat")
|
||||
: new FileChooser.ExtensionFilter(i18n("extension.sh"), "*.sh"));
|
||||
chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("extension.ps1"), "*.ps1"));
|
||||
Path file = FileUtils.toPath(chooser.showSaveDialog(Controllers.getStage()));
|
||||
if (file != null)
|
||||
new LauncherHelper(profile, account, id).makeLaunchScript(file);
|
||||
if (file != null) {
|
||||
LauncherHelper launcherHelper = new LauncherHelper(profile, account, id);
|
||||
for (Consumer<LauncherHelper> injecter : injecters) {
|
||||
injecter.accept(launcherHelper);
|
||||
}
|
||||
launcherHelper.makeLaunchScript(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void launch(Profile profile, String id, Consumer<LauncherHelper> injecter) {
|
||||
@SafeVarargs
|
||||
public static void launch(Profile profile, String id, Consumer<LauncherHelper>... injecters) {
|
||||
if (!checkVersionForLaunching(profile, id))
|
||||
return;
|
||||
ensureSelectedAccount(account -> {
|
||||
LauncherHelper launcherHelper = new LauncherHelper(profile, account, id);
|
||||
if (injecter != null)
|
||||
for (Consumer<LauncherHelper> injecter : injecters) {
|
||||
injecter.accept(launcherHelper);
|
||||
}
|
||||
launcherHelper.launch();
|
||||
});
|
||||
}
|
||||
@@ -234,6 +244,16 @@ public final class Versions {
|
||||
launch(profile, id, LauncherHelper::setTestMode);
|
||||
}
|
||||
|
||||
public static void launchAndEnterWorld(Profile profile, String id, String worldFolderName) {
|
||||
launch(profile, id, launcherHelper ->
|
||||
launcherHelper.setQuickPlayOption(new QuickPlayOption.SinglePlayer(worldFolderName)));
|
||||
}
|
||||
|
||||
public static void generateLaunchScriptForQuickEnterWorld(Profile profile, String id, String worldFolderName) {
|
||||
generateLaunchScript(profile, id, launcherHelper ->
|
||||
launcherHelper.setQuickPlayOption(new QuickPlayOption.SinglePlayer(worldFolderName)));
|
||||
}
|
||||
|
||||
private static boolean checkVersionForLaunching(Profile profile, String id) {
|
||||
if (id == null || !profile.getRepository().isLoaded() || !profile.getRepository().hasVersion(id)) {
|
||||
JFXButton gotoDownload = new JFXButton(i18n("version.empty.launch.goto_download"));
|
||||
|
||||
@@ -22,6 +22,7 @@ import javafx.scene.control.Skin;
|
||||
import javafx.stage.FileChooser;
|
||||
import org.jackhuang.hmcl.game.World;
|
||||
import org.jackhuang.hmcl.game.WorldLockedException;
|
||||
import org.jackhuang.hmcl.setting.Profile;
|
||||
import org.jackhuang.hmcl.task.Schedulers;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.ui.Controllers;
|
||||
@@ -39,11 +40,15 @@ public final class WorldListItem extends Control {
|
||||
private final World world;
|
||||
private final Path backupsDir;
|
||||
private final WorldListPage parent;
|
||||
private final Profile profile;
|
||||
private final String id;
|
||||
|
||||
public WorldListItem(WorldListPage parent, World world, Path backupsDir) {
|
||||
public WorldListItem(WorldListPage parent, World world, Path backupsDir, Profile profile, String id) {
|
||||
this.world = world;
|
||||
this.backupsDir = backupsDir;
|
||||
this.parent = parent;
|
||||
this.profile = profile;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -91,6 +96,14 @@ public final class WorldListItem extends Control {
|
||||
}
|
||||
|
||||
public void showManagePage() {
|
||||
Controllers.navigate(new WorldManagePage(world, backupsDir));
|
||||
Controllers.navigate(new WorldManagePage(world, backupsDir, profile, id));
|
||||
}
|
||||
|
||||
public void launch() {
|
||||
Versions.launchAndEnterWorld(profile, id, world.getFileName());
|
||||
}
|
||||
|
||||
public void generateLaunchScript() {
|
||||
Versions.generateLaunchScriptForQuickEnterWorld(profile, id, world.getFileName());
|
||||
}
|
||||
}
|
||||
@@ -115,8 +115,19 @@ public final class WorldListItemSkin extends SkinBase<WorldListItem> {
|
||||
WorldListItem item = getSkinnable();
|
||||
World world = item.getWorld();
|
||||
|
||||
popupMenu.getContent().addAll(
|
||||
new IconedMenuItem(SVG.SETTINGS, i18n("world.manage.button"), item::showManagePage, popup));
|
||||
if (world.getGameVersion() != null && world.getGameVersion().isAtLeast("1.20", "23w14a")) {
|
||||
|
||||
IconedMenuItem launchItem = new IconedMenuItem(SVG.ROCKET_LAUNCH, i18n("version.launch_and_enter_world"), item::launch, popup);
|
||||
launchItem.setDisable(world.isLocked());
|
||||
popupMenu.getContent().add(launchItem);
|
||||
|
||||
popupMenu.getContent().addAll(
|
||||
new IconedMenuItem(SVG.SCRIPT, i18n("version.launch_script"), item::generateLaunchScript, popup),
|
||||
new MenuSeparator()
|
||||
);
|
||||
}
|
||||
|
||||
popupMenu.getContent().add(new IconedMenuItem(SVG.SETTINGS, i18n("world.manage.button"), item::showManagePage, popup));
|
||||
|
||||
if (ChunkBaseApp.isSupported(world)) {
|
||||
popupMenu.getContent().addAll(
|
||||
|
||||
@@ -61,7 +61,7 @@ public final class WorldListPage extends ListPageBase<WorldListItem> implements
|
||||
if (worlds != null)
|
||||
itemsProperty().setAll(worlds.stream()
|
||||
.filter(world -> isShowAll() || world.getGameVersion() == null || world.getGameVersion().equals(gameVersion))
|
||||
.map(world -> new WorldListItem(this, world, backupsDir)).toList());
|
||||
.map(world -> new WorldListItem(this, world, backupsDir, profile, id)).toList());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ public final class WorldListPage extends ListPageBase<WorldListItem> implements
|
||||
if (exception == null) {
|
||||
itemsProperty().setAll(result.stream()
|
||||
.filter(world -> isShowAll() || world.getGameVersion() == null || world.getGameVersion().equals(gameVersion))
|
||||
.map(world -> new WorldListItem(this, world, backupsDir))
|
||||
.map(world -> new WorldListItem(this, world, backupsDir, profile, id))
|
||||
.collect(Collectors.toList()));
|
||||
} else {
|
||||
LOG.warning("Failed to load world list page", exception);
|
||||
@@ -131,7 +131,7 @@ public final class WorldListPage extends ListPageBase<WorldListItem> implements
|
||||
Controllers.prompt(i18n("world.name.enter"), (name, resolve, reject) -> {
|
||||
Task.runAsync(() -> world.install(savesDir, name))
|
||||
.whenComplete(Schedulers.javafx(), () -> {
|
||||
itemsProperty().add(new WorldListItem(this, new World(savesDir.resolve(name)), backupsDir));
|
||||
itemsProperty().add(new WorldListItem(this, new World(savesDir.resolve(name)), backupsDir, profile, id));
|
||||
resolve.run();
|
||||
}, e -> {
|
||||
if (e instanceof FileAlreadyExistsException)
|
||||
|
||||
@@ -26,6 +26,7 @@ import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
import org.jackhuang.hmcl.game.World;
|
||||
import org.jackhuang.hmcl.setting.Profile;
|
||||
import org.jackhuang.hmcl.ui.FXUtils;
|
||||
import org.jackhuang.hmcl.ui.SVG;
|
||||
import org.jackhuang.hmcl.ui.animation.TransitionPane;
|
||||
@@ -49,6 +50,8 @@ public final class WorldManagePage extends DecoratorAnimatedPage implements Deco
|
||||
private final ObjectProperty<State> state;
|
||||
private final World world;
|
||||
private final Path backupsDir;
|
||||
private final Profile profile;
|
||||
private final String id;
|
||||
|
||||
private final TabHeader header;
|
||||
private final TabHeader.Tab<WorldInfoPage> worldInfoTab = new TabHeader.Tab<>("worldInfoPage");
|
||||
@@ -59,10 +62,13 @@ public final class WorldManagePage extends DecoratorAnimatedPage implements Deco
|
||||
|
||||
private FileChannel sessionLockChannel;
|
||||
|
||||
public WorldManagePage(World world, Path backupsDir) {
|
||||
public WorldManagePage(World world, Path backupsDir, Profile profile, String id) {
|
||||
this.world = world;
|
||||
this.backupsDir = backupsDir;
|
||||
|
||||
this.profile = profile;
|
||||
this.id = id;
|
||||
|
||||
this.worldInfoTab.setNodeSupplier(() -> new WorldInfoPage(this));
|
||||
this.worldBackupsTab.setNodeSupplier(() -> new WorldBackupsPage(this));
|
||||
this.datapackTab.setNodeSupplier(() -> new DatapackListPage(this));
|
||||
@@ -71,6 +77,13 @@ public final class WorldManagePage extends DecoratorAnimatedPage implements Deco
|
||||
this.header = new TabHeader(transitionPane, worldInfoTab, worldBackupsTab);
|
||||
header.select(worldInfoTab);
|
||||
|
||||
// Does it need to be done in the background?
|
||||
try {
|
||||
sessionLockChannel = world.lock();
|
||||
LOG.info("Acquired lock on world " + world.getFileName());
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
|
||||
setCenter(transitionPane);
|
||||
|
||||
BorderPane left = new BorderPane();
|
||||
@@ -91,6 +104,12 @@ public final class WorldManagePage extends DecoratorAnimatedPage implements Deco
|
||||
left.setTop(sideBar);
|
||||
|
||||
AdvancedListBox toolbar = new AdvancedListBox();
|
||||
|
||||
if (world.getGameVersion() != null && world.getGameVersion().isAtLeast("1.20", "23w14a")) {
|
||||
toolbar.addNavigationDrawerItem(i18n("version.launch"), SVG.ROCKET_LAUNCH, this::launch, null);
|
||||
toolbar.addNavigationDrawerItem(i18n("version.launch_script"), SVG.SCRIPT, this::generateLaunchScript, null);
|
||||
}
|
||||
|
||||
if (ChunkBaseApp.isSupported(world)) {
|
||||
PopupMenu popupMenu = new PopupMenu();
|
||||
JFXPopup popup = new JFXPopup(popupMenu);
|
||||
@@ -117,12 +136,7 @@ public final class WorldManagePage extends DecoratorAnimatedPage implements Deco
|
||||
BorderPane.setMargin(toolbar, new Insets(0, 0, 12, 0));
|
||||
left.setBottom(toolbar);
|
||||
|
||||
// Does it need to be done in the background?
|
||||
try {
|
||||
sessionLockChannel = world.lock();
|
||||
LOG.info("Acquired lock on world " + world.getFileName());
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
this.addEventHandler(Navigator.NavigationEvent.EXITED, this::onExited);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -142,14 +156,7 @@ public final class WorldManagePage extends DecoratorAnimatedPage implements Deco
|
||||
return sessionLockChannel == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean back() {
|
||||
closePage();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closePage() {
|
||||
public void onExited(Navigator.NavigationEvent event) {
|
||||
if (sessionLockChannel != null) {
|
||||
try {
|
||||
sessionLockChannel.close();
|
||||
@@ -161,4 +168,13 @@ public final class WorldManagePage extends DecoratorAnimatedPage implements Deco
|
||||
sessionLockChannel = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void launch() {
|
||||
fireEvent(new PageCloseEvent());
|
||||
Versions.launchAndEnterWorld(profile, id, world.getFileName());
|
||||
}
|
||||
|
||||
public void generateLaunchScript() {
|
||||
Versions.generateLaunchScriptForQuickEnterWorld(profile, id, world.getFileName());
|
||||
}
|
||||
}
|
||||
@@ -265,6 +265,10 @@
|
||||
-fx-spacing: 0;
|
||||
}
|
||||
|
||||
.no-padding .advanced-list-box-content {
|
||||
-fx-padding: 0 0 0 0;
|
||||
}
|
||||
|
||||
.iconed-item {
|
||||
-jfx-rippler-fill: -monet-secondary-container;
|
||||
}
|
||||
@@ -346,7 +350,7 @@
|
||||
-fx-font-size: 15px;
|
||||
}
|
||||
|
||||
.terracotta-license Text {
|
||||
.terracotta-hint Text {
|
||||
-fx-fill: -monet-on-surface;
|
||||
}
|
||||
|
||||
@@ -1005,6 +1009,10 @@
|
||||
-fx-text-fill: -monet-on-surface;
|
||||
}
|
||||
|
||||
.options-list-item .label.subtitle {
|
||||
-fx-text-fill: -monet-on-surface-variant;
|
||||
}
|
||||
|
||||
.options-list-item.no-padding {
|
||||
-fx-padding: 0;
|
||||
}
|
||||
|
||||
@@ -197,7 +197,15 @@ button.select_all=Select All
|
||||
button.view=View
|
||||
button.yes=Yes
|
||||
|
||||
chat=Join Group Chat
|
||||
contact=Feedback
|
||||
contact.chat=Join Group Chat
|
||||
contact.chat.discord=Discord
|
||||
contact.chat.discord.statement=Welcome to join our Discord server.
|
||||
contact.chat.qq_group=HMCL User QQ Group
|
||||
contact.chat.qq_group.statement=Welcome to join our user QQ group.
|
||||
contact.feedback=Feedback Channel
|
||||
contact.feedback.github=GitHub Issues
|
||||
contact.feedback.github.statement=Submit an issue on GitHub.
|
||||
|
||||
color.recent=Recommended
|
||||
color.custom=Custom Color
|
||||
@@ -376,6 +384,7 @@ extension.mod=Mod File
|
||||
extension.png=Image File
|
||||
extension.ps1=Windows PowerShell Script
|
||||
extension.sh=Shell Script
|
||||
extension.command=macOS Shell Script
|
||||
|
||||
fatal.create_hmcl_current_directory_failure=Hello Minecraft! Launcher cannot create the HMCL directory (%s). Please move HMCL to another location and reopen it.
|
||||
fatal.javafx.incompatible=Missing JavaFX environment.\n\
|
||||
@@ -432,15 +441,6 @@ fatal.unsupported_platform.windows_arm64=Hello Minecraft! Launcher has provided
|
||||
If you are using the <b>Qualcomm</b> platform, you may need to install the <a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">OpenGL Compatibility Pack</a> before playing games.\n\
|
||||
Click the link to navigate to the Microsoft Store and install the compatibility pack.
|
||||
|
||||
feedback=Feedback
|
||||
feedback.channel=Feedback Channel
|
||||
feedback.discord=Discord
|
||||
feedback.discord.statement=Welcome to join our Discord server.
|
||||
feedback.github=GitHub Issues
|
||||
feedback.github.statement=Submit an issue on GitHub.
|
||||
feedback.qq_group=HMCL User QQ Group
|
||||
feedback.qq_group.statement=Welcome to join our user QQ group.
|
||||
|
||||
file=File
|
||||
|
||||
folder.config=Configs
|
||||
@@ -1412,6 +1412,7 @@ settings.memory.unit.mib=MiB
|
||||
settings.memory.used_per_total=%1$.1f GiB Used / %2$.1f GiB Total
|
||||
settings.physical_memory=Physical Memory Size
|
||||
settings.show_log=Show Logs
|
||||
settings.enable_debug_log_output=Output debug log
|
||||
settings.tabs.installers=Loaders
|
||||
settings.take_effect_after_restart=Applies After Restart
|
||||
settings.type=Settings Type of Instance
|
||||
@@ -1537,7 +1538,7 @@ update.latest=This is the latest version
|
||||
update.no_browser=Cannot open in system browser. But we copied the link to your clipboard, and you can open it manually.
|
||||
update.tooltip=Update
|
||||
update.preview=Preview HMCL releases early
|
||||
update.preview.tooltip=Enable this option to receive new versions of HMCL early for testing before their official release.
|
||||
update.preview.subtitle=Enable this option to receive new versions of HMCL early for testing before their official release.
|
||||
|
||||
version=Games
|
||||
version.name=Instance Name
|
||||
@@ -1558,6 +1559,7 @@ version.game.support_status.unsupported=Unsupported
|
||||
version.game.support_status.untested=Untested
|
||||
version.game.type=Type
|
||||
version.launch=Launch Game
|
||||
version.launch_and_enter_world=Play World
|
||||
version.launch.empty=Start Game
|
||||
version.launch.empty.installing=Installing Game
|
||||
version.launch.empty.tooltip=Install and launch the latest official release
|
||||
|
||||
@@ -197,7 +197,15 @@ button.select_all=تحديد الكل
|
||||
button.view=عرض
|
||||
button.yes=نعم
|
||||
|
||||
chat=الانضمام إلى دردشة جماعية
|
||||
contact=الملاحظات
|
||||
contact.chat=الانضمام إلى دردشة جماعية
|
||||
contact.chat.discord=Discord
|
||||
contact.chat.discord.statement=مرحباً بك للانضمام إلى خادم Discord الخاص بنا.
|
||||
contact.chat.qq_group=مجموعة QQ لمستخدمي HMCL
|
||||
contact.chat.qq_group.statement=مرحباً بك للانضمام إلى مجموعة QQ الخاصة بمستخدمينا.
|
||||
contact.feedback=قناة الملاحظات
|
||||
contact.feedback.github=GitHub Issues
|
||||
contact.feedback.github.statement=إرسال مشكلة على GitHub.
|
||||
|
||||
color.recent=موصى به
|
||||
color.custom=لون مخصص
|
||||
@@ -432,15 +440,6 @@ fatal.unsupported_platform.windows_arm64=Hello Minecraft! Launcher وفر دعم
|
||||
إذا كنت تستخدم منصة <b>Qualcomm</b>، فقد تحتاج إلى تثبيت <a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">حزمة توافق OpenGL</a> قبل لعب الألعاب.\n\
|
||||
انقر على الرابط للانتقال إلى متجر Microsoft وتثبيت حزمة التوافق.
|
||||
|
||||
feedback=الملاحظات
|
||||
feedback.channel=قناة الملاحظات
|
||||
feedback.discord=Discord
|
||||
feedback.discord.statement=مرحباً بك للانضمام إلى خادم Discord الخاص بنا.
|
||||
feedback.github=GitHub Issues
|
||||
feedback.github.statement=إرسال مشكلة على GitHub.
|
||||
feedback.qq_group=مجموعة QQ لمستخدمي HMCL
|
||||
feedback.qq_group.statement=مرحباً بك للانضمام إلى مجموعة QQ الخاصة بمستخدمينا.
|
||||
|
||||
file=ملف
|
||||
|
||||
folder.config=التكوينات
|
||||
@@ -1526,7 +1525,7 @@ update.latest=هذا هو أحدث إصدار
|
||||
update.no_browser=لا يمكن الفتح في متصفح النظام. ولكننا نسخنا الرابط إلى الحافظة الخاصة بك، ويمكنك فتحه يدويًا.
|
||||
update.tooltip=تحديث
|
||||
update.preview=معاينة إصدارات HMCL مبكرًا
|
||||
update.preview.tooltip=قم بتفعيل هذا الخيار لاستلام إصدارات جديدة من HMCL مبكرًا للاختبار قبل إصدارها الرسمي.
|
||||
update.preview.subtitle=قم بتفعيل هذا الخيار لاستلام إصدارات جديدة من HMCL مبكرًا للاختبار قبل إصدارها الرسمي.
|
||||
|
||||
version=الألعاب
|
||||
version.name=اسم النسخة
|
||||
|
||||
@@ -198,7 +198,15 @@ button.select_all=Seleccionar todo
|
||||
button.view=Vista
|
||||
button.yes=Sí
|
||||
|
||||
chat=Chat de grupo
|
||||
contact=Comentarios
|
||||
contact.chat=Chat de grupo
|
||||
contact.chat.discord=Discord
|
||||
contact.chat.discord.statement=¡Únase a nuestro servidor Discord!
|
||||
contact.chat.qq_group=Grupo QQ de usuarios de HMCL
|
||||
contact.chat.qq_group.statement=¡Únase a nuestro grupo QQ de usuarios!
|
||||
contact.feedback=Canal de comentarios
|
||||
contact.feedback.github=GitHub Issues
|
||||
contact.feedback.github.statement=Envíe una propuesta en GitHub.
|
||||
|
||||
color.recent=Recomendado
|
||||
color.custom=Color personalizado
|
||||
@@ -433,15 +441,6 @@ fatal.unsupported_platform.windows_arm64=Hello Minecraft! Launcher ha proporcion
|
||||
Si utilizas la plataforma <b>Qualcomm</b>, es posible que tengas que instalar el <a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">paquete de compatibilidad OpenGL</a> antes de jugar.\n\
|
||||
Haz clic en el enlace para ir a Microsoft Store e instalar el paquete de compatibilidad.
|
||||
|
||||
feedback=Comentarios
|
||||
feedback.channel=Canal de comentarios
|
||||
feedback.discord=Discord
|
||||
feedback.discord.statement=¡Únase a nuestro servidor Discord!
|
||||
feedback.github=GitHub Issues
|
||||
feedback.github.statement=Envíe una propuesta en GitHub.
|
||||
feedback.qq_group=Grupo QQ de usuarios de HMCL
|
||||
feedback.qq_group.statement=¡Únase a nuestro grupo QQ de usuarios!
|
||||
|
||||
file=Archivo
|
||||
|
||||
folder.config=Configuraciones de mod
|
||||
@@ -1447,7 +1446,7 @@ update.latest=Esta es la última versión.
|
||||
update.no_browser=No se puede abrir en el navegador del sistema. Pero, hemos copiado el enlace a su portapapeles y puede abrirlo manualmente.
|
||||
update.tooltip=Actualización
|
||||
update.preview=Vista previa de actualizaciones anticipadas
|
||||
update.preview.tooltip=Activa esta opción para recibir nuevas versiones del lanzador antes de su lanzamiento oficial para probarlas
|
||||
update.preview.subtitle=Activa esta opción para recibir nuevas versiones del lanzador antes de su lanzamiento oficial para probarlas
|
||||
|
||||
version=Juegos
|
||||
version.name=Nombre de instancia
|
||||
|
||||
@@ -157,7 +157,15 @@ button.select_all=すべて選択
|
||||
button.view=読む
|
||||
button.yes=はい
|
||||
|
||||
chat=グループチャット
|
||||
contact=フィードバック
|
||||
contact.chat=グループチャット
|
||||
contact.chat.discord=Discord
|
||||
contact.chat.discord.statement=Discordサーバーに参加してください!
|
||||
contact.chat.qq_group=HMCLユーザーQQグループ
|
||||
contact.chat.qq_group.statement=ユーザーQQグループに参加してください!
|
||||
contact.feedback=フィードバックチャンネル
|
||||
contact.feedback.github=GitHub Issues
|
||||
contact.feedback.github.statement=GitHubで問題を送信します。
|
||||
|
||||
color.recent=推奨
|
||||
color.custom=カスタムカラー
|
||||
@@ -326,16 +334,6 @@ fatal.apply_update_failure=ごめんなさい、Hello Minecraft! Launcher 何か
|
||||
fatal.samba=If you are trying to run HMCL in a shared folder by Samba, HMCL may not working, please try updating your Java or running HMCL in a local folder.
|
||||
fatal.illegal_char=ユーザーフォルダーのパスに不正な文字'='が含まれています, ログインアカウントやオフラインログインではスキンの変更ができなくなり。
|
||||
|
||||
|
||||
feedback=フィードバック
|
||||
feedback.channel=フィードバックチャンネル
|
||||
feedback.discord=Discord
|
||||
feedback.discord.statement=Discordサーバーに参加してください!
|
||||
feedback.github=GitHub Issues
|
||||
feedback.github.statement=GitHubで問題を送信します。
|
||||
feedback.qq_group=HMCLユーザーQQグループ
|
||||
feedback.qq_group.statement=ユーザーQQグループに参加してください!
|
||||
|
||||
file=ファイル
|
||||
|
||||
folder.config=Config
|
||||
|
||||
@@ -206,11 +206,19 @@ button.select_all=悉擇之
|
||||
button.view=覽
|
||||
button.yes=然
|
||||
|
||||
chat=會集
|
||||
|
||||
color.recent=薦
|
||||
color.custom=自定色
|
||||
|
||||
contact=建言
|
||||
contact.chat=會集
|
||||
contact.chat.discord=齟齬
|
||||
contact.chat.discord.statement=恭迎至齟齬伺服器,且循論議之規
|
||||
contact.chat.qq_group=HMCL 群組
|
||||
contact.chat.qq_group.statement=恭迎至 HMCL 群組,且循論議之規
|
||||
contact.feedback=建言之徑
|
||||
contact.feedback.github=Github 議題
|
||||
contact.feedback.github.statement=舉一 Github 議題
|
||||
|
||||
crash.NoClassDefFound=宜驗 HMCL 之案全否,抑更迭爪哇。\n君可求助於 https://docs.hmcl.net/help.html。
|
||||
crash.user_fault=君之械網與爪哇或有謬,是以崩。宜驗爪哇與算機。\n君可求助於 https://docs.hmcl.net/help.html。
|
||||
|
||||
@@ -401,15 +409,6 @@ fatal.unsupported_platform.loongarch=HMCL 既適龍芯。\n凡有謬,遽求助
|
||||
fatal.unsupported_platform.macos_arm64=HMCL 既適蘋矽。宜啟以 ARM 之爪哇,以益君之戲事。\n誠有謬,宜啟以 x86-64 之爪哇,以益其兼。\n凡有謬,遽求助於右上之鈕。
|
||||
fatal.unsupported_platform.windows_arm64=HMCL 既適 ARM 之視窗。誠有謬,宜啟以 x86 之爪哇。\n誠用<b>栝柑</b>,或須置<a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">開圖庫兼囊</a>,而後可戯。擊鏈以置之於微軟貨舍。\n君可求助於右上之鈕。
|
||||
|
||||
feedback=建言
|
||||
feedback.channel=建言之徑
|
||||
feedback.discord=齟齬
|
||||
feedback.discord.statement=恭迎至齟齬伺服器,且循論議之規
|
||||
feedback.github=Github 議題
|
||||
feedback.github.statement=舉一 Github 議題
|
||||
feedback.qq_group=HMCL 群組
|
||||
feedback.qq_group.statement=恭迎至 HMCL 群組,且循論議之規
|
||||
|
||||
file=案
|
||||
|
||||
folder.config=置設案夾
|
||||
|
||||
@@ -197,7 +197,15 @@ button.select_all=Выбрать все
|
||||
button.view=Просмотреть
|
||||
button.yes=Да
|
||||
|
||||
chat=Групповой чат
|
||||
contact=Обратная связь
|
||||
contact.chat=Групповой чат
|
||||
contact.chat.discord=Discord
|
||||
contact.chat.discord.statement=Добро пожаловать в наш Discord.
|
||||
contact.chat.qq_group=Группа QQ пользователя HMCL
|
||||
contact.chat.qq_group.statement=Добро пожаловать в нашу группу QQ.
|
||||
contact.feedback=Канал обратной связи
|
||||
contact.feedback.github=Проблемы GitHub
|
||||
contact.feedback.github.statement=Отправить проблему на GitHub.
|
||||
|
||||
color.recent=Рекомендуемые
|
||||
color.custom=Пользовательский цвет
|
||||
@@ -429,15 +437,6 @@ fatal.unsupported_platform.windows_arm64=Лаунчер обеспечил на
|
||||
Если вы используете платформу <b>Qualcomm</b>, вам может потребоваться установить <a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">пакет совместимости OpenGL</a> перед началом игры.\n\
|
||||
Щелкните ссылку, чтобы перейти в Microsoft Store и установить пакет совместимости.
|
||||
|
||||
feedback=Обратная связь
|
||||
feedback.channel=Канал обратной связи
|
||||
feedback.discord=Discord
|
||||
feedback.discord.statement=Добро пожаловать в наш Discord.
|
||||
feedback.github=Проблемы GitHub
|
||||
feedback.github.statement=Отправить проблему на GitHub.
|
||||
feedback.qq_group=Группа QQ пользователя HMCL
|
||||
feedback.qq_group.statement=Добро пожаловать в нашу группу QQ.
|
||||
|
||||
file=Файл
|
||||
|
||||
folder.config=Конфигурация мод
|
||||
|
||||
@@ -194,7 +194,15 @@ button.select_all=Вибрати все
|
||||
button.view=Переглянути
|
||||
button.yes=Так
|
||||
|
||||
chat=Приєднатися до групового чату
|
||||
contact=Зворотний зв'язок
|
||||
contact.chat=Приєднатися до групового чату
|
||||
contact.chat.discord=Discord
|
||||
contact.chat.discord.statement=Ласкаво просимо приєднатися до нашого сервера Discord.
|
||||
contact.chat.qq_group=Група користувачів QQ HMCL
|
||||
contact.chat.qq_group.statement=Ласкаво просимо приєднатися до нашої групи користувачів QQ.
|
||||
contact.feedback=Канал зворотного зв'язку
|
||||
contact.feedback.github=GitHub Issues
|
||||
contact.feedback.github.statement=Надіслати проблему на GitHub.
|
||||
|
||||
color.recent=Рекомендовані
|
||||
color.custom=Власний колір
|
||||
@@ -411,15 +419,6 @@ fatal.unsupported_platform.windows_arm64=Hello Minecraft! Лаунчер над
|
||||
Якщо ви використовуєте платформу <b>Qualcomm</b>, вам може знадобитися встановити <a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">Пакет сумісності OpenGL</a> перед грою.\n\
|
||||
Натисніть посилання, щоб перейти до Microsoft Store та встановити пакет сумісності.
|
||||
|
||||
feedback=Зворотний зв'язок
|
||||
feedback.channel=Канал зворотного зв'язку
|
||||
feedback.discord=Discord
|
||||
feedback.discord.statement=Ласкаво просимо приєднатися до нашого сервера Discord.
|
||||
feedback.github=GitHub Issues
|
||||
feedback.github.statement=Надіслати проблему на GitHub.
|
||||
feedback.qq_group=Група користувачів QQ HMCL
|
||||
feedback.qq_group.statement=Ласкаво просимо приєднатися до нашої групи користувачів QQ.
|
||||
|
||||
file=Файл
|
||||
|
||||
folder.config=Конфігурації
|
||||
|
||||
@@ -200,7 +200,15 @@ button.select_all=全選
|
||||
button.view=查看
|
||||
button.yes=是
|
||||
|
||||
chat=官方群組
|
||||
contact=回報
|
||||
contact.chat=官方群組
|
||||
contact.chat.discord=Discord 伺服器
|
||||
contact.chat.discord.statement=歡迎加入 Discord 伺服器,加入後請遵守討論區規則
|
||||
contact.chat.qq_group=使用者 QQ 群組
|
||||
contact.chat.qq_group.statement=歡迎加入 HMCL 使用者 QQ 群組,加入後請遵守群組規則
|
||||
contact.feedback=回報管道
|
||||
contact.feedback.github=GitHub Issues
|
||||
contact.feedback.github.statement=提交一個 GitHub Issue
|
||||
|
||||
color.recent=建議
|
||||
color.custom=自訂顏色
|
||||
@@ -374,6 +382,7 @@ extension.mod=模組檔案
|
||||
extension.png=圖片檔案
|
||||
extension.ps1=PowerShell 指令碼
|
||||
extension.sh=Bash 指令碼
|
||||
extension.command=macOS Shell 指令碼
|
||||
|
||||
fatal.create_hmcl_current_directory_failure=Hello Minecraft! Launcher 無法建立 HMCL 資料夾 (%s),請將 HMCL 移動至其他位置再開啟。
|
||||
fatal.javafx.incompatible=缺少 JavaFX 執行環境。\nHMCL 無法在低於 Java 11 的 Java 環境上自行補全 JavaFX 執行環境。請更新到 Java 11 或更高版本。
|
||||
@@ -398,15 +407,6 @@ fatal.unsupported_platform.loongarch=Hello Minecraft! Launcher 已為龍芯提
|
||||
fatal.unsupported_platform.macos_arm64=Hello Minecraft! Launcher 已為 Apple Silicon 平臺提供支援。使用 ARM 原生 Java 啟動遊戲以獲得更流暢的遊戲體驗。\n如果你在遊戲中遭遇問題,使用 x86-64 架構的 Java 啟動遊戲可能有更好的相容性。
|
||||
fatal.unsupported_platform.windows_arm64=Hello Minecraft! Launcher 已為 Windows on Arm 平臺提供原生支援。如果你在遊戲中遭遇問題,請嘗試使用 x86 架構的 Java 啟動遊戲。\n\n如果你正在使用<b>高通</b>平臺,你可能需要安裝 <a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">OpenGL 相容包</a>後才能進行遊戲。點擊連結前往 Microsoft Store 安裝相容包。
|
||||
|
||||
feedback=回報
|
||||
feedback.channel=回報管道
|
||||
feedback.discord=Discord 伺服器
|
||||
feedback.discord.statement=歡迎加入 Discord 伺服器,加入後請遵守討論區規則
|
||||
feedback.github=GitHub Issues
|
||||
feedback.github.statement=提交一個 GitHub Issue
|
||||
feedback.qq_group=HMCL 使用者 QQ 群組
|
||||
feedback.qq_group.statement=歡迎加入 HMCL 使用者 QQ 群組,加入後請遵守群組規則
|
||||
|
||||
file=檔案
|
||||
|
||||
folder.config=模組設定目錄
|
||||
@@ -1200,6 +1200,7 @@ settings.memory.unit.mib=MiB
|
||||
settings.memory.used_per_total=已使用 %1$.1f GiB / 總記憶體 %2$.1f GiB
|
||||
settings.physical_memory=實體記憶體大小
|
||||
settings.show_log=查看日誌
|
||||
settings.enable_debug_log_output=輸出除錯日誌
|
||||
settings.tabs.installers=自動安裝
|
||||
settings.take_effect_after_restart=重啟後生效
|
||||
settings.type=實例遊戲設定類型
|
||||
@@ -1321,7 +1322,7 @@ update.latest=目前版本為最新版本
|
||||
update.no_browser=無法開啟瀏覽器。網址已經複製到剪貼簿了,你可以手動複製網址開啟頁面。
|
||||
update.tooltip=更新
|
||||
update.preview=提前測試 HMCL 預覽版本
|
||||
update.preview.tooltip=啟用此選項,你將可以提前取得 HMCL 的新版本,以便在正式發布前進行測試。
|
||||
update.preview.subtitle=啟用此選項,你將可以提前取得 HMCL 的新版本,以便在正式發布前進行測試。
|
||||
|
||||
version=遊戲
|
||||
version.name=遊戲實例名稱
|
||||
@@ -1342,6 +1343,7 @@ version.game.support_status.unsupported=不支援
|
||||
version.game.support_status.untested=未經測試
|
||||
version.game.type=版本類型
|
||||
version.launch=啟動遊戲
|
||||
version.launch_and_enter_world=進入世界
|
||||
version.launch.empty=開始遊戲
|
||||
version.launch.empty.installing=安裝遊戲
|
||||
version.launch.empty.tooltip=安裝並啟動最新正式版遊戲
|
||||
|
||||
@@ -208,11 +208,19 @@ button.select_all=全选
|
||||
button.view=查看
|
||||
button.yes=是
|
||||
|
||||
chat=官方群组
|
||||
|
||||
color.recent=推荐
|
||||
color.custom=自定义颜色
|
||||
|
||||
contact=反馈
|
||||
contact.feedback=提交反馈
|
||||
contact.feedback.github=GitHub Issue
|
||||
contact.feedback.github.statement=提交一个 GitHub Issue
|
||||
contact.chat=官方群组
|
||||
contact.chat.qq_group=用户 QQ 群
|
||||
contact.chat.qq_group.statement=欢迎加入 HMCL 官方 QQ 群,加入后请遵守群规
|
||||
contact.chat.discord=Discord
|
||||
contact.chat.discord.statement=欢迎加入 Discord 服务器,加入后请遵守讨论区规定
|
||||
|
||||
crash.NoClassDefFound=请确认 Hello Minecraft! Launcher 本体是否完整,或更新你的 Java。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。
|
||||
crash.user_fault=你的系统或 Java 环境可能安装不当导致本软件崩溃,请检查你的 Java 环境或你的电脑。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。
|
||||
|
||||
@@ -383,6 +391,7 @@ extension.mod=模组文件
|
||||
extension.png=图片文件
|
||||
extension.ps1=PowerShell 脚本
|
||||
extension.sh=Bash 脚本
|
||||
extension.command=macOS Shell 脚本
|
||||
|
||||
fatal.create_hmcl_current_directory_failure=Hello Minecraft! Launcher 无法创建 HMCL 文件夹 (%s),请将 HMCL 移动至其他位置再启动。\n如遇到问题,你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。
|
||||
fatal.javafx.incompatible=缺少 JavaFX 运行环境。\nHello Minecraft! Launcher 无法在低于 Java 11 的 Java 环境上自行补全 JavaFX 运行环境。请更新到 Java 11 或更高版本。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。
|
||||
@@ -407,15 +416,6 @@ fatal.unsupported_platform.loongarch=Hello Minecraft! Launcher 已为龙芯提
|
||||
fatal.unsupported_platform.macos_arm64=Hello Minecraft! Launcher 已为 Apple Silicon 平台提供支持。使用 ARM 原生 Java 启动游戏以获得更流畅的游戏体验。\n如果你在游戏中遇到问题,使用 x86-64 架构的 Java 启动游戏可能有更好的兼容性。\n如遇到问题,你可以点击右上角帮助按钮进行求助。
|
||||
fatal.unsupported_platform.windows_arm64=Hello Minecraft! Launcher 已为 Windows on Arm 平台提供原生支持。如果你在游戏中遇到问题,请尝试使用 x86 架构的 Java 启动游戏。\n如果你正在使用 <b>高通</b> 平台,你可能需要安装 <a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">OpenGL 兼容包</a> 后才能进行游戏。点击链接前往 Microsoft Store 安装兼容包。\n如遇到问题,你可以点击右上角帮助按钮进行求助。
|
||||
|
||||
feedback=反馈
|
||||
feedback.channel=反馈渠道
|
||||
feedback.discord=Discord
|
||||
feedback.discord.statement=欢迎加入 Discord 服务器,加入后请遵守讨论区规定
|
||||
feedback.github=GitHub Issue
|
||||
feedback.github.statement=提交一个 GitHub Issue
|
||||
feedback.qq_group=HMCL 用户群
|
||||
feedback.qq_group.statement=欢迎加入 HMCL 用户群,加入后请遵守群规
|
||||
|
||||
file=文件
|
||||
|
||||
folder.config=配置文件夹
|
||||
@@ -1210,6 +1210,7 @@ settings.memory.unit.mib=MiB
|
||||
settings.memory.used_per_total=设备中已使用 %1$.1f GiB / 设备总内存 %2$.1f GiB
|
||||
settings.physical_memory=物理内存大小
|
||||
settings.show_log=查看日志
|
||||
settings.enable_debug_log_output=输出调试日志
|
||||
settings.tabs.installers=自动安装
|
||||
settings.take_effect_after_restart=重启后生效
|
||||
settings.type=实例游戏设置类型
|
||||
@@ -1331,7 +1332,7 @@ update.latest=当前版本为最新版本
|
||||
update.no_browser=无法打开浏览器。网址已经复制到剪贴板,你可以手动粘贴网址打开页面。
|
||||
update.tooltip=更新
|
||||
update.preview=提前预览 HMCL 版本
|
||||
update.preview.tooltip=启用此选项,你将可以提前获取 HMCL 的新版本,以便在正式发布前进行测试。
|
||||
update.preview.subtitle=启用此选项,你将可以提前获取 HMCL 的新版本,以便在正式发布前进行测试。
|
||||
|
||||
version=游戏
|
||||
version.name=游戏实例名称
|
||||
@@ -1352,6 +1353,7 @@ version.game.support_status.unsupported=不支持
|
||||
version.game.support_status.untested=未经测试
|
||||
version.game.type=版本类型
|
||||
version.launch=启动游戏
|
||||
version.launch_and_enter_world=进入世界
|
||||
version.launch.empty=开始游戏
|
||||
version.launch.empty.installing=安装游戏
|
||||
version.launch.empty.tooltip=安装并启动最新正式版游戏
|
||||
|
||||
@@ -103,10 +103,14 @@ public class OfflineAccount extends Account {
|
||||
return skin != null && skin.getType() != Skin.Type.DEFAULT;
|
||||
}
|
||||
|
||||
public AuthInfo logInWithoutSkin() throws AuthenticationException {
|
||||
// Using "legacy" user type here because "mojang" user type may cause "invalid session token" or "disconnected" when connecting to a game server.
|
||||
return new AuthInfo(username, uuid, UUIDTypeAdapter.fromUUID(UUID.randomUUID()), AuthInfo.USER_TYPE_MSA, "{}");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthInfo logIn() throws AuthenticationException {
|
||||
// Using "legacy" user type here because "mojang" user type may cause "invalid session token" or "disconnected" when connecting to a game server.
|
||||
AuthInfo authInfo = new AuthInfo(username, uuid, UUIDTypeAdapter.fromUUID(UUID.randomUUID()), AuthInfo.USER_TYPE_MSA, "{}");
|
||||
AuthInfo authInfo = logInWithoutSkin();
|
||||
|
||||
if (loadAuthlibInjector(skin)) {
|
||||
CompletableFuture<AuthlibInjectorArtifactInfo> artifactTask = CompletableFuture.supplyAsync(() -> {
|
||||
|
||||
+4
-1
@@ -22,6 +22,7 @@ import org.jackhuang.hmcl.download.RemoteVersion;
|
||||
import org.jackhuang.hmcl.download.VersionList;
|
||||
import org.jackhuang.hmcl.task.GetTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.NetworkUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -64,11 +65,13 @@ public final class LiteLoaderBMCLVersionList extends VersionList<LiteLoaderRemot
|
||||
NetworkUtils.withQuery(downloadProvider.getApiRoot() + "/liteloader/list", Map.of(
|
||||
"mcversion", gameVersion
|
||||
)))
|
||||
.thenGetJsonAsync(LiteLoaderBMCLVersion.class)
|
||||
.thenApplyAsync(json -> JsonUtils.fromMaybeMalformedJson(json, LiteLoaderBMCLVersion.class))
|
||||
.thenAcceptAsync(v -> {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
versions.clear();
|
||||
if (v == null)
|
||||
return;
|
||||
versions.put(gameVersion, new LiteLoaderRemoteVersion(
|
||||
gameVersion, v.version, RemoteVersion.Type.UNCATEGORIZED,
|
||||
Collections.singletonList(NetworkUtils.withQuery(
|
||||
|
||||
+7
-1
@@ -63,7 +63,13 @@ public final class NeoForgeOfficialVersionList extends VersionList<NeoForgeRemot
|
||||
if (majorVersion == 0) { // Snapshot version.
|
||||
mcVersion = version.substring(si1 + 1, si2);
|
||||
} else {
|
||||
mcVersion = "1." + version.substring(0, Integer.parseInt(version.substring(si1 + 1, si2)) == 0 ? si1 : si2);
|
||||
String ver = version.substring(0, Integer.parseInt(version.substring(si1 + 1, si2)) == 0 ? si1 : si2);
|
||||
if (majorVersion >= 26) {
|
||||
int separator = version.indexOf('+');
|
||||
mcVersion = separator < 0 ? ver : ver + "-" + version.substring(separator + 1);
|
||||
} else {
|
||||
mcVersion = "1." + ver;
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
LOG.warning(String.format("Cannot parse NeoForge version %s for cracking its mc version.", version), e);
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ public class NeoForgeRemoteVersion extends RemoteVersion {
|
||||
}
|
||||
|
||||
private static Type getType(String version) {
|
||||
return version.contains("beta") ? Type.SNAPSHOT : Type.RELEASE;
|
||||
return version.contains("beta") || version.contains("alpha") ? Type.SNAPSHOT : Type.RELEASE;
|
||||
}
|
||||
|
||||
public static String normalize(String version) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
|
||||
import java.util.*;
|
||||
|
||||
public final class GameJavaVersion {
|
||||
public static final GameJavaVersion JAVA_25 = new GameJavaVersion("java-runtime-epsilon", 25);
|
||||
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);
|
||||
@@ -33,6 +34,8 @@ public final class GameJavaVersion {
|
||||
public static final GameJavaVersion LATEST = JAVA_21;
|
||||
|
||||
public static GameJavaVersion getMinimumJavaVersion(GameVersionNumber gameVersion) {
|
||||
if (gameVersion.compareTo("26.1") >= 0)
|
||||
return JAVA_25;
|
||||
if (gameVersion.compareTo("1.20.5") >= 0)
|
||||
return JAVA_21;
|
||||
if (gameVersion.compareTo("1.18") >= 0)
|
||||
@@ -45,18 +48,14 @@ public final class GameJavaVersion {
|
||||
}
|
||||
|
||||
public static GameJavaVersion get(int major) {
|
||||
switch (major) {
|
||||
case 8:
|
||||
return JAVA_8;
|
||||
case 16:
|
||||
return JAVA_16;
|
||||
case 17:
|
||||
return JAVA_17;
|
||||
case 21:
|
||||
return JAVA_21;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return switch (major) {
|
||||
case 8 -> JAVA_8;
|
||||
case 16 -> JAVA_16;
|
||||
case 17 -> JAVA_17;
|
||||
case 21 -> JAVA_21;
|
||||
case 25 -> JAVA_25;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
public static List<GameJavaVersion> getSupportedVersions(Platform platform) {
|
||||
@@ -74,13 +73,13 @@ public final class GameJavaVersion {
|
||||
case WINDOWS:
|
||||
case LINUX:
|
||||
case MACOS:
|
||||
return Arrays.asList(JAVA_8, JAVA_16, JAVA_17, JAVA_21);
|
||||
return Arrays.asList(JAVA_8, JAVA_16, JAVA_17, JAVA_21, JAVA_25);
|
||||
}
|
||||
} else if (architecture == Architecture.ARM64) {
|
||||
switch (operatingSystem) {
|
||||
case WINDOWS:
|
||||
case MACOS:
|
||||
return Arrays.asList(JAVA_17, JAVA_21);
|
||||
return Arrays.asList(JAVA_17, JAVA_21, JAVA_25);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ public class LaunchOptions implements Serializable {
|
||||
private Integer width;
|
||||
private Integer height;
|
||||
private boolean fullscreen;
|
||||
private String serverIp;
|
||||
private QuickPlayOption quickPlayOption;
|
||||
private String wrapper;
|
||||
private Proxy.Type proxyType;
|
||||
private String proxyHost;
|
||||
@@ -64,6 +64,7 @@ public class LaunchOptions implements Serializable {
|
||||
private Renderer renderer = Renderer.DEFAULT;
|
||||
private boolean useNativeGLFW;
|
||||
private boolean useNativeOpenAL;
|
||||
private boolean enableDebugLogOutput;
|
||||
private boolean daemon;
|
||||
|
||||
/**
|
||||
@@ -180,11 +181,11 @@ public class LaunchOptions implements Serializable {
|
||||
return fullscreen;
|
||||
}
|
||||
|
||||
/**
|
||||
* The server ip that will connect to when enter game main menu.
|
||||
*/
|
||||
public String getServerIp() {
|
||||
return serverIp;
|
||||
/// The quick play option.
|
||||
///
|
||||
/// @see <a href="https://minecraft.wiki/w/Quick_Play">Quick Play - Minecraft Wiki</a>
|
||||
public QuickPlayOption getQuickPlayOption() {
|
||||
return quickPlayOption;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -282,6 +283,10 @@ public class LaunchOptions implements Serializable {
|
||||
return useNativeOpenAL;
|
||||
}
|
||||
|
||||
public boolean isEnableDebugLogOutput() {
|
||||
return enableDebugLogOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will launcher keeps alive after game launched or not.
|
||||
*/
|
||||
@@ -407,8 +412,8 @@ public class LaunchOptions implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setServerIp(String serverIp) {
|
||||
options.serverIp = serverIp;
|
||||
public Builder setQuickPlayOption(QuickPlayOption quickPlayOption) {
|
||||
options.quickPlayOption = quickPlayOption;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -497,5 +502,9 @@ public class LaunchOptions implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEnableDebugLogOutput(boolean u) {
|
||||
options.enableDebugLogOutput = u;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
/// The quick play option.
|
||||
///
|
||||
/// @see <a href="https://minecraft.wiki/w/Quick_Play">Quick Play - Minecraft Wiki</a>
|
||||
public sealed interface QuickPlayOption {
|
||||
record SinglePlayer(String worldFolderName) implements QuickPlayOption {
|
||||
}
|
||||
|
||||
record MultiPlayer(String serverIP) implements QuickPlayOption {
|
||||
}
|
||||
|
||||
record Realm(String realmID) implements QuickPlayOption {
|
||||
}
|
||||
}
|
||||
@@ -149,7 +149,7 @@ public class DefaultLauncher extends Launcher {
|
||||
res.addDefault("-Dcom.sun.jndi.cosnaming.object.trustURLCodebase=", "false");
|
||||
|
||||
String formatMsgNoLookups = res.addDefault("-Dlog4j2.formatMsgNoLookups=", "true");
|
||||
if (!"-Dlog4j2.formatMsgNoLookups=false".equals(formatMsgNoLookups) && isUsingLog4j()) {
|
||||
if (isUsingLog4j() && (options.isEnableDebugLogOutput() || !"-Dlog4j2.formatMsgNoLookups=false".equals(formatMsgNoLookups))) {
|
||||
res.addDefault("-Dlog4j.configurationFile=", FileUtils.getAbsolutePath(getLog4jConfigurationFile()));
|
||||
}
|
||||
|
||||
@@ -304,23 +304,31 @@ public class DefaultLauncher extends Launcher {
|
||||
if (argumentsFromAuthInfo != null && argumentsFromAuthInfo.getGame() != null && !argumentsFromAuthInfo.getGame().isEmpty())
|
||||
res.addAll(Arguments.parseArguments(argumentsFromAuthInfo.getGame(), configuration, features));
|
||||
|
||||
if (StringUtils.isNotBlank(options.getServerIp())) {
|
||||
String address = options.getServerIp();
|
||||
if (options.getQuickPlayOption() instanceof QuickPlayOption.MultiPlayer multiPlayer) {
|
||||
String address = multiPlayer.serverIP();
|
||||
|
||||
try {
|
||||
ServerAddress parsed = ServerAddress.parse(address);
|
||||
if (GameVersionNumber.asGameVersion(gameVersion).compareTo("1.20") < 0) {
|
||||
if (GameVersionNumber.asGameVersion(gameVersion).isAtLeast("1.20", "23w14a")) {
|
||||
res.add("--quickPlayMultiplayer");
|
||||
res.add(parsed.getPort() >= 0 ? address : parsed.getHost() + ":25565");
|
||||
} else {
|
||||
res.add("--server");
|
||||
res.add(parsed.getHost());
|
||||
res.add("--port");
|
||||
res.add(parsed.getPort() >= 0 ? String.valueOf(parsed.getPort()) : "25565");
|
||||
} else {
|
||||
res.add("--quickPlayMultiplayer");
|
||||
res.add(parsed.getPort() < 0 ? address + ":25565" : address);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.warning("Invalid server address: " + address, e);
|
||||
}
|
||||
} else if (options.getQuickPlayOption() instanceof QuickPlayOption.SinglePlayer singlePlayer
|
||||
&& GameVersionNumber.asGameVersion(gameVersion).isAtLeast("1.20", "23w14a")) {
|
||||
res.add("--quickPlaySingleplayer");
|
||||
res.add(singlePlayer.worldFolderName());
|
||||
} else if (options.getQuickPlayOption() instanceof QuickPlayOption.Realm realm
|
||||
&& GameVersionNumber.asGameVersion(gameVersion).isAtLeast("1.20", "23w14a")) {
|
||||
res.add("--quickPlayRealms");
|
||||
res.add(realm.realmID());
|
||||
}
|
||||
|
||||
if (options.isFullscreen())
|
||||
@@ -421,14 +429,24 @@ public class DefaultLauncher extends Launcher {
|
||||
|
||||
public void extractLog4jConfigurationFile() throws IOException {
|
||||
Path targetFile = getLog4jConfigurationFile();
|
||||
InputStream source;
|
||||
|
||||
String sourcePath;
|
||||
|
||||
if (GameVersionNumber.asGameVersion(repository.getGameVersion(version)).compareTo("1.12") < 0) {
|
||||
source = DefaultLauncher.class.getResourceAsStream("/assets/game/log4j2-1.7.xml");
|
||||
if (options.isEnableDebugLogOutput()) {
|
||||
sourcePath = "/assets/game/log4j2-1.7-debug.xml";
|
||||
} else {
|
||||
sourcePath = "/assets/game/log4j2-1.7.xml";
|
||||
}
|
||||
} else {
|
||||
source = DefaultLauncher.class.getResourceAsStream("/assets/game/log4j2-1.12.xml");
|
||||
if (options.isEnableDebugLogOutput()) {
|
||||
sourcePath = "/assets/game/log4j2-1.12-debug.xml";
|
||||
} else {
|
||||
sourcePath = "/assets/game/log4j2-1.12.xml";
|
||||
}
|
||||
}
|
||||
|
||||
try (InputStream input = source) {
|
||||
try (InputStream input = DefaultLauncher.class.getResourceAsStream(sourcePath)) {
|
||||
Files.copy(input, targetFile, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
||||
@@ -609,8 +627,8 @@ public class DefaultLauncher extends Launcher {
|
||||
if (!usePowerShell) {
|
||||
if (isWindows && !scriptExtension.equals("bat"))
|
||||
throw new IllegalArgumentException("The extension of " + scriptFile + " is not 'bat' or 'ps1' in Windows");
|
||||
else if (!isWindows && !scriptExtension.equals("sh"))
|
||||
throw new IllegalArgumentException("The extension of " + scriptFile + " is not 'sh' or 'ps1' in macOS/Linux");
|
||||
else if (!isWindows && !(scriptExtension.equals("sh") || scriptExtension.equals("command")))
|
||||
throw new IllegalArgumentException("The extension of " + scriptFile + " is not 'sh', 'ps1' or 'command' in macOS/Linux");
|
||||
}
|
||||
|
||||
final Command commandLine = generateCommandLine(nativeFolder);
|
||||
|
||||
+14
-10
@@ -114,16 +114,20 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
|
||||
if (category != null && category.getSelf() instanceof CurseAddon.Category) {
|
||||
categoryId = ((CurseAddon.Category) category.getSelf()).getId();
|
||||
}
|
||||
Response<List<CurseAddon>> response = withApiKey(HttpRequest.GET(downloadProvider.injectURL(NetworkUtils.withQuery(PREFIX + "/v1/mods/search", mapOf(
|
||||
pair("gameId", "432"),
|
||||
pair("classId", Integer.toString(section)),
|
||||
pair("categoryId", Integer.toString(categoryId)),
|
||||
pair("gameVersion", gameVersion),
|
||||
pair("searchFilter", searchFilter),
|
||||
pair("sortField", Integer.toString(toModsSearchSortField(sortType))),
|
||||
pair("sortOrder", toSortOrder(sortOrder)),
|
||||
pair("index", Integer.toString(pageOffset * pageSize)),
|
||||
pair("pageSize", Integer.toString(pageSize)))))))
|
||||
|
||||
var query = new LinkedHashMap<String, String>();
|
||||
query.put("gameId", "432");
|
||||
query.put("classId", Integer.toString(section));
|
||||
if (categoryId != 0)
|
||||
query.put("categoryId", Integer.toString(categoryId));
|
||||
query.put("gameVersion", gameVersion);
|
||||
query.put("searchFilter", searchFilter);
|
||||
query.put("sortField", Integer.toString(toModsSearchSortField(sortType)));
|
||||
query.put("sortOrder", toSortOrder(sortOrder));
|
||||
query.put("index", Integer.toString(pageOffset * pageSize));
|
||||
query.put("pageSize", Integer.toString(pageSize));
|
||||
|
||||
Response<List<CurseAddon>> response = withApiKey(HttpRequest.GET(downloadProvider.injectURL(NetworkUtils.withQuery(PREFIX + "/v1/mods/search", query))))
|
||||
.getJson(Response.typeOf(listTypeOf(CurseAddon.class)));
|
||||
if (searchFilter.isEmpty()) {
|
||||
return new SearchResult(response.getData().stream().map(CurseAddon::toMod), calculateTotalPages(response, pageSize));
|
||||
|
||||
@@ -337,6 +337,10 @@ public abstract sealed class GameVersionNumber implements Comparable<GameVersion
|
||||
} else if (suffix.startsWith("-snapshot-")) {
|
||||
releaseType = ReleaseType.SNAPSHOT;
|
||||
eaVersion = VersionNumber.asVersion(suffix.substring("-snapshot-".length()));
|
||||
} else if (suffix.startsWith(" Snapshot ")) {
|
||||
needNormalize = true;
|
||||
releaseType = ReleaseType.SNAPSHOT;
|
||||
eaVersion = VersionNumber.asVersion(suffix.substring(" Snapshot ".length()));
|
||||
} else if (suffix.startsWith("-pre")) {
|
||||
releaseType = ReleaseType.PRE_RELEASE;
|
||||
eaVersion = VersionNumber.asVersion(suffix.substring("-pre".length()));
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="warn" packages="">
|
||||
<Appenders>
|
||||
<Console name="SysOut" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg{nolookups}%n" />
|
||||
</Console>
|
||||
<Queue name="ServerGuiConsole">
|
||||
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg{nolookups}%n" />
|
||||
</Queue>
|
||||
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
|
||||
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level] [%logger]: %msg{nolookups}%n"/>
|
||||
<Policies>
|
||||
<TimeBasedTriggeringPolicy/>
|
||||
<OnStartupTriggeringPolicy/>
|
||||
</Policies>
|
||||
</RollingRandomAccessFile>
|
||||
<RollingRandomAccessFile name="DebugFile" fileName="logs/debug.log" filePattern="logs/debug-%d{yyyy-MM-dd}-%i.log.gz">
|
||||
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] [%t/%level] [%logger]: %msg{nolookups}%n"/>
|
||||
<Policies>
|
||||
<TimeBasedTriggeringPolicy/>
|
||||
<OnStartupTriggeringPolicy/>
|
||||
</Policies>
|
||||
<DefaultRolloverStrategy max="999" fileIndex="min"/>
|
||||
</RollingRandomAccessFile>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Root level="all">
|
||||
<filters>
|
||||
<MarkerFilter marker="NETWORK_PACKETS" onMatch="DENY" onMismatch="NEUTRAL"/>
|
||||
</filters>
|
||||
<AppenderRef ref="SysOut" level="info"/>
|
||||
<AppenderRef ref="ServerGuiConsole" level="info"/>
|
||||
<AppenderRef ref="File" level="info"/>
|
||||
<AppenderRef ref="DebugFile" level="all"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="WARN">
|
||||
<Appenders>
|
||||
<Console name="SysOut" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" />
|
||||
</Console>
|
||||
<Queue name="ServerGuiConsole">
|
||||
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg%n" />
|
||||
</Queue>
|
||||
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
|
||||
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level] [%logger]: %msg%n"/>
|
||||
<Policies>
|
||||
<TimeBasedTriggeringPolicy/>
|
||||
<OnStartupTriggeringPolicy/>
|
||||
</Policies>
|
||||
</RollingRandomAccessFile>
|
||||
<RollingRandomAccessFile name="DebugFile" fileName="logs/debug.log" filePattern="logs/debug-%d{yyyy-MM-dd}-%i.log.gz">
|
||||
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] [%t/%level] [%logger]: %msg%n"/>
|
||||
<Policies>
|
||||
<TimeBasedTriggeringPolicy/>
|
||||
<OnStartupTriggeringPolicy/>
|
||||
</Policies>
|
||||
</RollingRandomAccessFile>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Root level="all">
|
||||
<filters>
|
||||
<MarkerFilter marker="NETWORK_PACKETS" onMatch="DENY" onMismatch="NEUTRAL"/>
|
||||
</filters>
|
||||
<AppenderRef ref="SysOut" level="info"/>
|
||||
<AppenderRef ref="ServerGuiConsole" level="info"/>
|
||||
<AppenderRef ref="File" level="info"/>
|
||||
<AppenderRef ref="DebugFile" level="all"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
@@ -432,6 +432,7 @@ public final class GameVersionNumberTest {
|
||||
assertNormalized(version, version);
|
||||
}
|
||||
|
||||
assertNormalized("26.1-snapshot-1", "26.1 Snapshot 1");
|
||||
assertNormalized("1.21.11-pre3", "1.21.11 Pre-Release 3");
|
||||
assertNormalized("1.21.11-pre3_unobfuscated", "1.21.11 Pre-Release 3 Unobfuscated");
|
||||
assertNormalized("1.21.11-pre3_unobfuscated", "1.21.11-pre3 Unobfuscated");
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<!-- #BEGIN BLOCK -->
|
||||
<!-- #PROPERTY NAME=BADGES -->
|
||||
[](https://cnb.cool/HMCL-dev/HMCL)
|
||||
[](https://github.com/HMCL-dev/HMCL/releases)
|
||||

|
||||
[](https://discord.gg/jVvC7HfM6U)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<!-- #BEGIN COPY -->
|
||||
<!-- #PROPERTY NAME=BADGES -->
|
||||
[](https://cnb.cool/HMCL-dev/HMCL)
|
||||
[](https://github.com/HMCL-dev/HMCL/releases)
|
||||

|
||||
[](https://discord.gg/jVvC7HfM6U)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<!-- #BEGIN COPY -->
|
||||
<!-- #PROPERTY NAME=BADGES -->
|
||||
[](https://cnb.cool/HMCL-dev/HMCL)
|
||||
[](https://github.com/HMCL-dev/HMCL/releases)
|
||||

|
||||
[](https://discord.gg/jVvC7HfM6U)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<!-- #BEGIN COPY -->
|
||||
<!-- #PROPERTY NAME=BADGES -->
|
||||
[](https://cnb.cool/HMCL-dev/HMCL)
|
||||
[](https://github.com/HMCL-dev/HMCL/releases)
|
||||

|
||||
[](https://discord.gg/jVvC7HfM6U)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<!-- #BEGIN COPY -->
|
||||
<!-- #PROPERTY NAME=BADGES -->
|
||||
[](https://cnb.cool/HMCL-dev/HMCL)
|
||||
[](https://github.com/HMCL-dev/HMCL/releases)
|
||||

|
||||
[](https://discord.gg/jVvC7HfM6U)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<!-- #BEGIN COPY -->
|
||||
<!-- #PROPERTY NAME=BADGES -->
|
||||
[](https://cnb.cool/HMCL-dev/HMCL)
|
||||
[](https://github.com/HMCL-dev/HMCL/releases)
|
||||

|
||||
[](https://discord.gg/jVvC7HfM6U)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<!-- #BEGIN COPY -->
|
||||
<!-- #PROPERTY NAME=BADGES -->
|
||||
[](https://cnb.cool/HMCL-dev/HMCL)
|
||||
[](https://github.com/HMCL-dev/HMCL/releases)
|
||||

|
||||
[](https://discord.gg/jVvC7HfM6U)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<!-- #BEGIN COPY -->
|
||||
<!-- #PROPERTY NAME=BADGES -->
|
||||
[](https://cnb.cool/HMCL-dev/HMCL)
|
||||
[](https://github.com/HMCL-dev/HMCL/releases)
|
||||

|
||||
[](https://discord.gg/jVvC7HfM6U)
|
||||
|
||||
@@ -16,7 +16,7 @@ twelvemonkeys = "3.12.0"
|
||||
jna = "5.18.1"
|
||||
pci-ids = "0.4.0"
|
||||
java-info = "1.0"
|
||||
authlib-injector = "1.2.6"
|
||||
authlib-injector = "1.2.7"
|
||||
monet-fx = "0.4.0"
|
||||
|
||||
# testing
|
||||
|
||||
Reference in new issue
Block a user