Merge branch 'develop' of https://github.com/PrismLauncher/PrismLauncher into filters
This commit is contained in:
commit
3c12e27226
3
.github/workflows/backport.yml
vendored
3
.github/workflows/backport.yml
vendored
@ -16,6 +16,7 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write # for korthout/backport-action to create branch
|
contents: write # for korthout/backport-action to create branch
|
||||||
pull-requests: write # for korthout/backport-action to create PR to backport
|
pull-requests: write # for korthout/backport-action to create PR to backport
|
||||||
|
actions: write # for korthout/backport-action to create PR with workflow changes
|
||||||
name: Backport Pull Request
|
name: Backport Pull Request
|
||||||
if: github.repository_owner == 'PrismLauncher' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name))
|
if: github.repository_owner == 'PrismLauncher' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name))
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -24,7 +25,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
- name: Create backport PRs
|
- name: Create backport PRs
|
||||||
uses: korthout/backport-action@v2.2.0
|
uses: korthout/backport-action@v2.4.1
|
||||||
with:
|
with:
|
||||||
# Config README: https://github.com/korthout/backport-action#backport-action
|
# Config README: https://github.com/korthout/backport-action#backport-action
|
||||||
pull_description: |-
|
pull_description: |-
|
||||||
|
96
.github/workflows/build.yml
vendored
96
.github/workflows/build.yml
vendored
@ -21,8 +21,23 @@ on:
|
|||||||
WINDOWS_CODESIGN_PASSWORD:
|
WINDOWS_CODESIGN_PASSWORD:
|
||||||
description: Password for signing Windows builds
|
description: Password for signing Windows builds
|
||||||
required: false
|
required: false
|
||||||
CACHIX_AUTH_TOKEN:
|
APPLE_CODESIGN_CERT:
|
||||||
description: Private token for authenticating against Cachix cache
|
description: Certificate for signing macOS builds
|
||||||
|
required: false
|
||||||
|
APPLE_CODESIGN_PASSWORD:
|
||||||
|
description: Password for signing macOS builds
|
||||||
|
required: false
|
||||||
|
APPLE_CODESIGN_ID:
|
||||||
|
description: Certificate ID for signing macOS builds
|
||||||
|
required: false
|
||||||
|
APPLE_NOTARIZE_APPLE_ID:
|
||||||
|
description: Apple ID used for notarizing macOS builds
|
||||||
|
required: false
|
||||||
|
APPLE_NOTARIZE_TEAM_ID:
|
||||||
|
description: Team ID used for notarizing macOS builds
|
||||||
|
required: false
|
||||||
|
APPLE_NOTARIZE_PASSWORD:
|
||||||
|
description: Password used for notarizing macOS builds
|
||||||
required: false
|
required: false
|
||||||
GPG_PRIVATE_KEY:
|
GPG_PRIVATE_KEY:
|
||||||
description: Private key for AppImage signing
|
description: Private key for AppImage signing
|
||||||
@ -61,7 +76,7 @@ jobs:
|
|||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: windows
|
qt_host: windows
|
||||||
qt_arch: ''
|
qt_arch: ''
|
||||||
qt_version: '6.6.1'
|
qt_version: '6.6.2'
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
qt_modules: 'qt5compat qtimageformats'
|
||||||
qt_tools: ''
|
qt_tools: ''
|
||||||
|
|
||||||
@ -73,7 +88,7 @@ jobs:
|
|||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: windows
|
qt_host: windows
|
||||||
qt_arch: 'win64_msvc2019_arm64'
|
qt_arch: 'win64_msvc2019_arm64'
|
||||||
qt_version: '6.6.1'
|
qt_version: '6.6.2'
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
qt_modules: 'qt5compat qtimageformats'
|
||||||
qt_tools: ''
|
qt_tools: ''
|
||||||
|
|
||||||
@ -83,7 +98,7 @@ jobs:
|
|||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: mac
|
qt_host: mac
|
||||||
qt_arch: ''
|
qt_arch: ''
|
||||||
qt_version: '6.6.1'
|
qt_version: '6.6.2'
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
qt_modules: 'qt5compat qtimageformats'
|
||||||
qt_tools: ''
|
qt_tools: ''
|
||||||
|
|
||||||
@ -145,13 +160,13 @@ jobs:
|
|||||||
|
|
||||||
- name: Setup ccache
|
- name: Setup ccache
|
||||||
if: (runner.os != 'Windows' || matrix.msystem == '') && inputs.build_type == 'Debug'
|
if: (runner.os != 'Windows' || matrix.msystem == '') && inputs.build_type == 'Debug'
|
||||||
uses: hendrikmuhs/ccache-action@v1.2.10
|
uses: hendrikmuhs/ccache-action@v1.2.12
|
||||||
with:
|
with:
|
||||||
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}-${{ matrix.architecture }}
|
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}-${{ matrix.architecture }}
|
||||||
|
|
||||||
- name: Retrieve ccache cache (Windows MinGW-w64)
|
- name: Retrieve ccache cache (Windows MinGW-w64)
|
||||||
if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug'
|
if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug'
|
||||||
uses: actions/cache@v3.3.2
|
uses: actions/cache@v4.0.2
|
||||||
with:
|
with:
|
||||||
path: '${{ github.workspace }}\.ccache'
|
path: '${{ github.workspace }}\.ccache'
|
||||||
key: ${{ matrix.os }}-mingw-w64-ccache-${{ github.run_id }}
|
key: ${{ matrix.os }}-mingw-w64-ccache-${{ github.run_id }}
|
||||||
@ -336,6 +351,20 @@ jobs:
|
|||||||
# PACKAGE BUILDS
|
# PACKAGE BUILDS
|
||||||
##
|
##
|
||||||
|
|
||||||
|
- name: Fetch codesign certificate (macOS)
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
run: |
|
||||||
|
echo '${{ secrets.APPLE_CODESIGN_CERT }}' | base64 --decode > codesign.p12
|
||||||
|
if [ -n '${{ secrets.APPLE_CODESIGN_ID }}' ]; then
|
||||||
|
security create-keychain -p '${{ secrets.APPLE_CODESIGN_PASSWORD }}' build.keychain
|
||||||
|
security default-keychain -s build.keychain
|
||||||
|
security unlock-keychain -p '${{ secrets.APPLE_CODESIGN_PASSWORD }}' build.keychain
|
||||||
|
security import codesign.p12 -k build.keychain -P '${{ secrets.APPLE_CODESIGN_PASSWORD }}' -T /usr/bin/codesign
|
||||||
|
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k '${{ secrets.APPLE_CODESIGN_PASSWORD }}' build.keychain
|
||||||
|
else
|
||||||
|
echo ":warning: Using ad-hoc code signing for macOS, as certificate was not present." >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Package (macOS)
|
- name: Package (macOS)
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
run: |
|
run: |
|
||||||
@ -343,9 +372,34 @@ jobs:
|
|||||||
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
cd ${{ env.INSTALL_DIR }}
|
||||||
chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
||||||
sudo codesign --sign - --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
|
||||||
|
if [ -n '${{ secrets.APPLE_CODESIGN_ID }}' ]; then
|
||||||
|
APPLE_CODESIGN_ID='${{ secrets.APPLE_CODESIGN_ID }}'
|
||||||
|
else
|
||||||
|
APPLE_CODESIGN_ID='-'
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo codesign --sign "$APPLE_CODESIGN_ID" --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
||||||
mv "PrismLauncher.app" "Prism Launcher.app"
|
mv "PrismLauncher.app" "Prism Launcher.app"
|
||||||
tar -czf ../PrismLauncher.tar.gz *
|
|
||||||
|
- name: Notarize (macOS)
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
run: |
|
||||||
|
cd ${{ env.INSTALL_DIR }}
|
||||||
|
|
||||||
|
if [ -n '${{ secrets.APPLE_NOTARIZE_PASSWORD }}' ]; then
|
||||||
|
ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip
|
||||||
|
xcrun notarytool submit ../PrismLauncher.zip \
|
||||||
|
--wait --progress \
|
||||||
|
--apple-id '${{ secrets.APPLE_NOTARIZE_APPLE_ID }}' \
|
||||||
|
--team-id '${{ secrets.APPLE_NOTARIZE_TEAM_ID }}' \
|
||||||
|
--password '${{ secrets.APPLE_NOTARIZE_PASSWORD }}'
|
||||||
|
|
||||||
|
xcrun stapler staple "Prism Launcher.app"
|
||||||
|
else
|
||||||
|
echo ":warning: Skipping notarization as credentials are not present." >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip
|
||||||
|
|
||||||
- name: Make Sparkle signature (macOS)
|
- name: Make Sparkle signature (macOS)
|
||||||
if: matrix.name == 'macOS'
|
if: matrix.name == 'macOS'
|
||||||
@ -353,7 +407,7 @@ jobs:
|
|||||||
if [ '${{ secrets.SPARKLE_ED25519_KEY }}' != '' ]; then
|
if [ '${{ secrets.SPARKLE_ED25519_KEY }}' != '' ]; then
|
||||||
brew install openssl@3
|
brew install openssl@3
|
||||||
echo '${{ secrets.SPARKLE_ED25519_KEY }}' > ed25519-priv.pem
|
echo '${{ secrets.SPARKLE_ED25519_KEY }}' > ed25519-priv.pem
|
||||||
signature=$(/usr/local/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.tar.gz -inkey ed25519-priv.pem | openssl base64 | tr -d \\n)
|
signature=$(/usr/local/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.zip -inkey ed25519-priv.pem | openssl base64 | tr -d \\n)
|
||||||
rm ed25519-priv.pem
|
rm ed25519-priv.pem
|
||||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
cat >> $GITHUB_STEP_SUMMARY << EOF
|
||||||
### Artifact Information :information_source:
|
### Artifact Information :information_source:
|
||||||
@ -517,70 +571,70 @@ jobs:
|
|||||||
|
|
||||||
- name: Upload binary tarball (macOS)
|
- name: Upload binary tarball (macOS)
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PrismLauncher.tar.gz
|
path: PrismLauncher.zip
|
||||||
|
|
||||||
- name: Upload binary zip (Windows)
|
- name: Upload binary zip (Windows)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: ${{ env.INSTALL_DIR }}/**
|
path: ${{ env.INSTALL_DIR }}/**
|
||||||
|
|
||||||
- name: Upload binary zip (Windows, portable)
|
- name: Upload binary zip (Windows, portable)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ matrix.name }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PrismLauncher-${{ matrix.name }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: ${{ env.INSTALL_PORTABLE_DIR }}/**
|
path: ${{ env.INSTALL_PORTABLE_DIR }}/**
|
||||||
|
|
||||||
- name: Upload installer (Windows)
|
- name: Upload installer (Windows)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PrismLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PrismLauncher-Setup.exe
|
path: PrismLauncher-Setup.exe
|
||||||
|
|
||||||
- name: Upload binary tarball (Linux, Qt 5)
|
- name: Upload binary tarball (Linux, Qt 5)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-Qt5-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PrismLauncher-${{ runner.os }}-Qt5-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PrismLauncher.tar.gz
|
path: PrismLauncher.tar.gz
|
||||||
|
|
||||||
- name: Upload binary tarball (Linux, portable, Qt 5)
|
- name: Upload binary tarball (Linux, portable, Qt 5)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-Qt5-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PrismLauncher-${{ runner.os }}-Qt5-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PrismLauncher-portable.tar.gz
|
path: PrismLauncher-portable.tar.gz
|
||||||
|
|
||||||
- name: Upload binary tarball (Linux, Qt 6)
|
- name: Upload binary tarball (Linux, Qt 6)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver !=5
|
if: runner.os == 'Linux' && matrix.qt_ver !=5
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-Qt6-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PrismLauncher-${{ runner.os }}-Qt6-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PrismLauncher.tar.gz
|
path: PrismLauncher.tar.gz
|
||||||
|
|
||||||
- name: Upload binary tarball (Linux, portable, Qt 6)
|
- name: Upload binary tarball (Linux, portable, Qt 6)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-Qt6-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PrismLauncher-${{ runner.os }}-Qt6-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PrismLauncher-portable.tar.gz
|
path: PrismLauncher-portable.tar.gz
|
||||||
|
|
||||||
- name: Upload AppImage (Linux)
|
- name: Upload AppImage (Linux)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||||
path: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
path: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||||
|
|
||||||
- name: Upload AppImage Zsync (Linux)
|
- name: Upload AppImage Zsync (Linux)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage.zsync
|
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage.zsync
|
||||||
path: PrismLauncher-Linux-x86_64.AppImage.zsync
|
path: PrismLauncher-Linux-x86_64.AppImage.zsync
|
||||||
|
4
.github/workflows/codeql.yml
vendored
4
.github/workflows/codeql.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
|||||||
submodules: 'true'
|
submodules: 'true'
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v2
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
config-file: ./.github/codeql/codeql-config.yml
|
config-file: ./.github/codeql/codeql-config.yml
|
||||||
queries: security-and-quality
|
queries: security-and-quality
|
||||||
@ -32,4 +32,4 @@ jobs:
|
|||||||
cmake --build build
|
cmake --build build
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v2
|
uses: github/codeql-action/analyze@v3
|
||||||
|
7
.github/workflows/trigger_builds.yml
vendored
7
.github/workflows/trigger_builds.yml
vendored
@ -32,6 +32,11 @@ jobs:
|
|||||||
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
||||||
WINDOWS_CODESIGN_CERT: ${{ secrets.WINDOWS_CODESIGN_CERT }}
|
WINDOWS_CODESIGN_CERT: ${{ secrets.WINDOWS_CODESIGN_CERT }}
|
||||||
WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
|
WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
|
||||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
APPLE_CODESIGN_CERT: ${{ secrets.APPLE_CODESIGN_CERT }}
|
||||||
|
APPLE_CODESIGN_PASSWORD: ${{ secrets.APPLE_CODESIGN_PASSWORD }}
|
||||||
|
APPLE_CODESIGN_ID: ${{ secrets.APPLE_CODESIGN_ID }}
|
||||||
|
APPLE_NOTARIZE_APPLE_ID: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }}
|
||||||
|
APPLE_NOTARIZE_TEAM_ID: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }}
|
||||||
|
APPLE_NOTARIZE_PASSWORD: ${{ secrets.APPLE_NOTARIZE_PASSWORD }}
|
||||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }}
|
GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }}
|
||||||
|
19
.github/workflows/trigger_release.yml
vendored
19
.github/workflows/trigger_release.yml
vendored
@ -16,7 +16,12 @@ jobs:
|
|||||||
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
||||||
WINDOWS_CODESIGN_CERT: ${{ secrets.WINDOWS_CODESIGN_CERT }}
|
WINDOWS_CODESIGN_CERT: ${{ secrets.WINDOWS_CODESIGN_CERT }}
|
||||||
WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
|
WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
|
||||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
APPLE_CODESIGN_CERT: ${{ secrets.APPLE_CODESIGN_CERT }}
|
||||||
|
APPLE_CODESIGN_PASSWORD: ${{ secrets.APPLE_CODESIGN_PASSWORD }}
|
||||||
|
APPLE_CODESIGN_ID: ${{ secrets.APPLE_CODESIGN_ID }}
|
||||||
|
APPLE_NOTARIZE_APPLE_ID: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }}
|
||||||
|
APPLE_NOTARIZE_TEAM_ID: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }}
|
||||||
|
APPLE_NOTARIZE_PASSWORD: ${{ secrets.APPLE_NOTARIZE_PASSWORD }}
|
||||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }}
|
GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }}
|
||||||
|
|
||||||
@ -32,7 +37,7 @@ jobs:
|
|||||||
submodules: "true"
|
submodules: "true"
|
||||||
path: "PrismLauncher-source"
|
path: "PrismLauncher-source"
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
- name: Grab and store version
|
- name: Grab and store version
|
||||||
run: |
|
run: |
|
||||||
tag_name=$(echo ${{ github.ref }} | grep -oE "[^/]+$")
|
tag_name=$(echo ${{ github.ref }} | grep -oE "[^/]+$")
|
||||||
@ -46,8 +51,8 @@ jobs:
|
|||||||
mv PrismLauncher-Linux-Qt5*/PrismLauncher.tar.gz PrismLauncher-Linux-Qt5-${{ env.VERSION }}.tar.gz
|
mv PrismLauncher-Linux-Qt5*/PrismLauncher.tar.gz PrismLauncher-Linux-Qt5-${{ env.VERSION }}.tar.gz
|
||||||
mv PrismLauncher-*.AppImage/PrismLauncher-*.AppImage PrismLauncher-Linux-x86_64.AppImage
|
mv PrismLauncher-*.AppImage/PrismLauncher-*.AppImage PrismLauncher-Linux-x86_64.AppImage
|
||||||
mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*.AppImage.zsync PrismLauncher-Linux-x86_64.AppImage.zsync
|
mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*.AppImage.zsync PrismLauncher-Linux-x86_64.AppImage.zsync
|
||||||
mv PrismLauncher-macOS-Legacy*/PrismLauncher.tar.gz PrismLauncher-macOS-Legacy-${{ env.VERSION }}.tar.gz
|
mv PrismLauncher-macOS-Legacy*/PrismLauncher.zip PrismLauncher-macOS-Legacy-${{ env.VERSION }}.zip
|
||||||
mv PrismLauncher-macOS*/PrismLauncher.tar.gz PrismLauncher-macOS-${{ env.VERSION }}.tar.gz
|
mv PrismLauncher-macOS*/PrismLauncher.zip PrismLauncher-macOS-${{ env.VERSION }}.zip
|
||||||
|
|
||||||
tar --exclude='.git' -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
|
tar --exclude='.git' -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
|
||||||
|
|
||||||
@ -79,7 +84,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Create release
|
- name: Create release
|
||||||
id: create_release
|
id: create_release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
tag_name: ${{ github.ref }}
|
tag_name: ${{ github.ref }}
|
||||||
@ -102,6 +107,6 @@ jobs:
|
|||||||
PrismLauncher-Windows-MSVC-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-MSVC-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-MSVC-Portable-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-MSVC-Portable-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-MSVC-Setup-${{ env.VERSION }}.exe
|
PrismLauncher-Windows-MSVC-Setup-${{ env.VERSION }}.exe
|
||||||
PrismLauncher-macOS-${{ env.VERSION }}.tar.gz
|
PrismLauncher-macOS-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-macOS-Legacy-${{ env.VERSION }}.tar.gz
|
PrismLauncher-macOS-Legacy-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-${{ env.VERSION }}.tar.gz
|
PrismLauncher-${{ env.VERSION }}.tar.gz
|
||||||
|
4
.github/workflows/update-flake.yml
vendored
4
.github/workflows/update-flake.yml
vendored
@ -17,9 +17,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: cachix/install-nix-action@7ac1ec25491415c381d9b62f0657c7a028df52a7 # v24
|
- uses: cachix/install-nix-action@8887e596b4ee1134dae06b98d573bd674693f47c # v26
|
||||||
|
|
||||||
- uses: DeterminateSystems/update-flake-lock@v20
|
- uses: DeterminateSystems/update-flake-lock@v21
|
||||||
with:
|
with:
|
||||||
commit-msg: "chore(nix): update lockfile"
|
commit-msg: "chore(nix): update lockfile"
|
||||||
pr-title: "chore(nix): update lockfile"
|
pr-title: "chore(nix): update lockfile"
|
||||||
|
@ -178,7 +178,7 @@ set(Launcher_NEWS_OPEN_URL "https://prismlauncher.org/news" CACHE STRING "URL th
|
|||||||
set(Launcher_HELP_URL "https://prismlauncher.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help")
|
set(Launcher_HELP_URL "https://prismlauncher.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help")
|
||||||
|
|
||||||
######## Set version numbers ########
|
######## Set version numbers ########
|
||||||
set(Launcher_VERSION_MAJOR 8)
|
set(Launcher_VERSION_MAJOR 9)
|
||||||
set(Launcher_VERSION_MINOR 0)
|
set(Launcher_VERSION_MINOR 0)
|
||||||
|
|
||||||
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}")
|
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}")
|
||||||
@ -377,12 +377,12 @@ if(UNIX AND APPLE)
|
|||||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
|
||||||
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}")
|
||||||
set(MACOSX_BUNDLE_ICON_FILE ${Launcher_Name}.icns)
|
set(MACOSX_BUNDLE_ICON_FILE ${Launcher_Name}.icns)
|
||||||
set(MACOSX_BUNDLE_COPYRIGHT "© 2022-2023 ${Launcher_Copyright_Mac}")
|
set(MACOSX_BUNDLE_COPYRIGHT "${Launcher_Copyright_Mac}")
|
||||||
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=" CACHE STRING "Public key for Sparkle update feed")
|
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=" CACHE STRING "Public key for Sparkle update feed")
|
||||||
set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml" CACHE STRING "URL for Sparkle update feed")
|
set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml" CACHE STRING "URL for Sparkle update feed")
|
||||||
|
|
||||||
set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.1.0/Sparkle-2.1.0.tar.xz" CACHE STRING "URL to Sparkle release archive")
|
set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.5.2/Sparkle-2.5.2.tar.xz" CACHE STRING "URL to Sparkle release archive")
|
||||||
set(MACOSX_SPARKLE_SHA256 "bf6ac1caa9f8d321d5784859c88da874f28412f37fb327bc21b7b14c5d61ef94" CACHE STRING "SHA256 checksum for Sparkle release archive")
|
set(MACOSX_SPARKLE_SHA256 "572dd67ae398a466f19f343a449e1890bac1ef74885b4739f68f979a8a89884b" CACHE STRING "SHA256 checksum for Sparkle release archive")
|
||||||
set(MACOSX_SPARKLE_DIR "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
set(MACOSX_SPARKLE_DIR "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
||||||
|
|
||||||
# directories to look for dependencies
|
# directories to look for dependencies
|
||||||
@ -504,11 +504,10 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
if(NOT cmark_FOUND)
|
if(NOT cmark_FOUND)
|
||||||
message(STATUS "Using bundled cmark")
|
message(STATUS "Using bundled cmark")
|
||||||
set(CMARK_STATIC ON CACHE BOOL "Build static libcmark library" FORCE)
|
set(BUILD_TESTING 0)
|
||||||
set(CMARK_SHARED OFF CACHE BOOL "Build shared libcmark library" FORCE)
|
set(BUILD_SHARED_LIBS 0)
|
||||||
set(CMARK_TESTS OFF CACHE BOOL "Build cmark tests and enable testing" FORCE)
|
|
||||||
add_subdirectory(libraries/cmark EXCLUDE_FROM_ALL) # Markdown parser
|
add_subdirectory(libraries/cmark EXCLUDE_FROM_ALL) # Markdown parser
|
||||||
add_library(cmark::cmark ALIAS cmark_static)
|
add_library(cmark::cmark ALIAS cmark)
|
||||||
else()
|
else()
|
||||||
message(STATUS "Using system cmark")
|
message(STATUS "Using system cmark")
|
||||||
endif()
|
endif()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
## Prism Launcher
|
## Prism Launcher
|
||||||
|
|
||||||
Prism Launcher - Minecraft Launcher
|
Prism Launcher - Minecraft Launcher
|
||||||
Copyright (C) 2022-2023 Prism Launcher Contributors
|
Copyright (C) 2022-2024 Prism Launcher Contributors
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
68
flake.lock
generated
68
flake.lock
generated
@ -18,14 +18,16 @@
|
|||||||
},
|
},
|
||||||
"flake-parts": {
|
"flake-parts": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs-lib": "nixpkgs-lib"
|
"nixpkgs-lib": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1701473968,
|
"lastModified": 1709336216,
|
||||||
"narHash": "sha256-YcVE5emp1qQ8ieHUnxt1wCZCC3ZfAS+SRRWZ2TMda7E=",
|
"narHash": "sha256-Dt/wOWeW6Sqm11Yh+2+t0dfEWxoMxGBvv3JpIocFl9E=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-parts",
|
"repo": "flake-parts",
|
||||||
"rev": "34fed993f1674c8d06d58b37ce1e0fe5eebcb9f5",
|
"rev": "f7b3c975cf067e56e7cda6cb098ebe3fb4d74ca2",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -39,11 +41,11 @@
|
|||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1685518550,
|
"lastModified": 1701680307,
|
||||||
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
|
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
|
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -60,11 +62,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1660459072,
|
"lastModified": 1703887061,
|
||||||
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
|
"narHash": "sha256-gGPa9qWNc6eCXT/+Z5/zMkyYOuRZqeFZBDbopNZQkuY=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "gitignore.nix",
|
"repo": "gitignore.nix",
|
||||||
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
|
"rev": "43e1aa1308018f37118e34d3a9cb4f5e75dc11d5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -89,28 +91,13 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nix-filter": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1701697642,
|
|
||||||
"narHash": "sha256-L217WytWZHSY8GW9Gx1A64OnNctbuDbfslaTEofXXRw=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "nix-filter",
|
|
||||||
"rev": "c843418ecfd0344ecb85844b082ff5675e02c443",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "nix-filter",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1701998057,
|
"lastModified": 1710534455,
|
||||||
"narHash": "sha256-gAJGhcTO9cso7XDfAScXUlPcva427AUT2q02qrmXPdo=",
|
"narHash": "sha256-huQT4Xs0y4EeFKn2BTBVYgEwJSv8SDlm82uWgMnCMmI=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "09dc04054ba2ff1f861357d0e7e76d021b273cd7",
|
"rev": "9af9c1c87ed3e3ed271934cb896e0cdd33dae212",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -120,24 +107,6 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs-lib": {
|
|
||||||
"locked": {
|
|
||||||
"dir": "lib",
|
|
||||||
"lastModified": 1701253981,
|
|
||||||
"narHash": "sha256-ztaDIyZ7HrTAfEEUt9AtTDNoCYxUdSd6NrRHaYOIxtk=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "e92039b55bcd58469325ded85d4f58dd5a4eaf58",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"dir": "lib",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pre-commit-hooks": {
|
"pre-commit-hooks": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": [
|
"flake-compat": [
|
||||||
@ -153,11 +122,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1700922917,
|
"lastModified": 1708018599,
|
||||||
"narHash": "sha256-ej2fch/T584b5K9sk1UhmZF7W6wEfDHuoUYpFN8dtvM=",
|
"narHash": "sha256-M+Ng6+SePmA8g06CmUZWi1AjG2tFBX9WCXElBHEKnyM=",
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "pre-commit-hooks.nix",
|
"repo": "pre-commit-hooks.nix",
|
||||||
"rev": "e5ee5c5f3844550c01d2131096c7271cec5e9b78",
|
"rev": "5df5a70ad7575f6601d91f0efec95dd9bc619431",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -171,7 +140,6 @@
|
|||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
"flake-parts": "flake-parts",
|
"flake-parts": "flake-parts",
|
||||||
"libnbtplusplus": "libnbtplusplus",
|
"libnbtplusplus": "libnbtplusplus",
|
||||||
"nix-filter": "nix-filter",
|
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"pre-commit-hooks": "pre-commit-hooks"
|
"pre-commit-hooks": "pre-commit-hooks"
|
||||||
}
|
}
|
||||||
|
19
flake.nix
19
flake.nix
@ -1,15 +1,24 @@
|
|||||||
{
|
{
|
||||||
description = "A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once (Fork of MultiMC)";
|
description = "A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once (Fork of MultiMC)";
|
||||||
|
|
||||||
|
nixConfig = {
|
||||||
|
extra-substituters = ["https://cache.garnix.io"];
|
||||||
|
extra-trusted-public-keys = ["cache.garnix.io:CTFPyKSLcx5RMJKfLo5EEPUObbA78b0YQ2DTCJXqr9g="];
|
||||||
|
};
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
||||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
flake-parts = {
|
||||||
nix-filter.url = "github:numtide/nix-filter";
|
url = "github:hercules-ci/flake-parts";
|
||||||
|
inputs.nixpkgs-lib.follows = "nixpkgs";
|
||||||
|
};
|
||||||
pre-commit-hooks = {
|
pre-commit-hooks = {
|
||||||
url = "github:cachix/pre-commit-hooks.nix";
|
url = "github:cachix/pre-commit-hooks.nix";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs = {
|
||||||
inputs.nixpkgs-stable.follows = "nixpkgs";
|
nixpkgs.follows = "nixpkgs";
|
||||||
inputs.flake-compat.follows = "flake-compat";
|
nixpkgs-stable.follows = "nixpkgs";
|
||||||
|
flake-compat.follows = "flake-compat";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
flake-compat = {
|
flake-compat = {
|
||||||
url = "github:edolstra/flake-compat";
|
url = "github:edolstra/flake-compat";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
id: org.prismlauncher.PrismLauncher
|
id: org.prismlauncher.PrismLauncher
|
||||||
runtime: org.kde.Platform
|
runtime: org.kde.Platform
|
||||||
runtime-version: "5.15-23.08"
|
runtime-version: 5.15-23.08
|
||||||
sdk: org.kde.Sdk
|
sdk: org.kde.Sdk
|
||||||
sdk-extensions:
|
sdk-extensions:
|
||||||
- org.freedesktop.Sdk.Extension.openjdk17
|
- org.freedesktop.Sdk.Extension.openjdk17
|
||||||
@ -104,18 +104,15 @@ modules:
|
|||||||
- install -Dm755 ../data/gamemoderun -t /app/bin
|
- install -Dm755 ../data/gamemoderun -t /app/bin
|
||||||
sources:
|
sources:
|
||||||
- type: archive
|
- type: archive
|
||||||
archive-type: tar-gzip
|
dest-filename: gamemode.tar.gz
|
||||||
url: https://api.github.com/repos/FeralInteractive/gamemode/tarball/1.7
|
url: https://api.github.com/repos/FeralInteractive/gamemode/tarball/1.8.1
|
||||||
sha256: 57ce73ba605d1cf12f8d13725006a895182308d93eba0f69f285648449641803
|
sha256: 969cf85b5ca3944f3e315cd73a0ee9bea4f9c968cd7d485e9f4745bc1e679c4e
|
||||||
x-checker-data:
|
x-checker-data:
|
||||||
type: json
|
type: json
|
||||||
url: https://api.github.com/repos/FeralInteractive/gamemode/releases/latest
|
url: https://api.github.com/repos/FeralInteractive/gamemode/releases/latest
|
||||||
version-query: .tag_name
|
version-query: .tag_name
|
||||||
url-query: .tarball_url
|
url-query: .tarball_url
|
||||||
timestamp-query: .published_at
|
timestamp-query: .published_at
|
||||||
# from https://github.com/flathub/net.gaijin.WarThunder/blob/7ea6f7a9f84b9c77150c003a7059dc03f8dcbc7f/gamemode.patch
|
|
||||||
- type: patch
|
|
||||||
path: patches/gamemode.patch
|
|
||||||
cleanup:
|
cleanup:
|
||||||
- /include
|
- /include
|
||||||
- /lib/pkgconfig
|
- /lib/pkgconfig
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
diff -ruN a/common/common-pidfds.c b/common/common-pidfds.c
|
|
||||||
--- a/common/common-pidfds.c 2021-02-18 20:00:12.000000000 +0100
|
|
||||||
+++ b/common/common-pidfds.c 2023-09-07 08:57:42.954362763 +0200
|
|
||||||
@@ -58,6 +58,8 @@
|
|
||||||
{
|
|
||||||
return (int)syscall(__NR_pidfd_open, pid, flags);
|
|
||||||
}
|
|
||||||
+#else
|
|
||||||
+#include <sys/pidfd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* pidfd functions */
|
|
@ -1 +1 @@
|
|||||||
Subproject commit 45094ca570be383d06df729b6972830ec63bd3df
|
Subproject commit f2b0c16a2a217a1822ce5a6538ba8f755ed1dd32
|
@ -494,8 +494,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
qDebug() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME) << ", (c) 2022-2023 "
|
qDebug() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME + ", " + QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", "));
|
||||||
<< qPrintable(QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", "));
|
|
||||||
qDebug() << "Version : " << BuildConfig.printableVersionString();
|
qDebug() << "Version : " << BuildConfig.printableVersionString();
|
||||||
qDebug() << "Platform : " << BuildConfig.BUILD_PLATFORM;
|
qDebug() << "Platform : " << BuildConfig.BUILD_PLATFORM;
|
||||||
qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT;
|
qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT;
|
||||||
@ -640,10 +639,11 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
m_settings->registerSetting("UseNativeGLFW", false);
|
m_settings->registerSetting("UseNativeGLFW", false);
|
||||||
m_settings->registerSetting("CustomGLFWPath", "");
|
m_settings->registerSetting("CustomGLFWPath", "");
|
||||||
|
|
||||||
// Peformance related options
|
// Performance related options
|
||||||
m_settings->registerSetting("EnableFeralGamemode", false);
|
m_settings->registerSetting("EnableFeralGamemode", false);
|
||||||
m_settings->registerSetting("EnableMangoHud", false);
|
m_settings->registerSetting("EnableMangoHud", false);
|
||||||
m_settings->registerSetting("UseDiscreteGpu", false);
|
m_settings->registerSetting("UseDiscreteGpu", false);
|
||||||
|
m_settings->registerSetting("UseZink", false);
|
||||||
|
|
||||||
// Game time
|
// Game time
|
||||||
m_settings->registerSetting("ShowGameTime", true);
|
m_settings->registerSetting("ShowGameTime", true);
|
||||||
@ -667,6 +667,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
// The cat
|
// The cat
|
||||||
m_settings->registerSetting("TheCat", false);
|
m_settings->registerSetting("TheCat", false);
|
||||||
|
m_settings->registerSetting("CatOpacity", 100);
|
||||||
|
|
||||||
m_settings->registerSetting("StatusBarVisible", true);
|
m_settings->registerSetting("StatusBarVisible", true);
|
||||||
|
|
||||||
@ -751,6 +752,9 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
m_settings->registerSetting("ModrinthToken", "");
|
m_settings->registerSetting("ModrinthToken", "");
|
||||||
m_settings->registerSetting("UserAgentOverride", "");
|
m_settings->registerSetting("UserAgentOverride", "");
|
||||||
|
|
||||||
|
// FTBApp instances
|
||||||
|
m_settings->registerSetting("FTBAppInstancesPath", "");
|
||||||
|
|
||||||
// Init page provider
|
// Init page provider
|
||||||
{
|
{
|
||||||
m_globalSettingsProvider = std::make_shared<GenericPageProvider>(tr("Settings"));
|
m_globalSettingsProvider = std::make_shared<GenericPageProvider>(tr("Settings"));
|
||||||
|
@ -37,140 +37,33 @@
|
|||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include "FileSystem.h"
|
||||||
/**
|
|
||||||
* This shouldn't exist, but until QTBUG-9328 and other unreported bugs are fixed, it needs to be a thing.
|
|
||||||
*/
|
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
bool IndirectOpen(T callable, qint64* pid_forked = nullptr)
|
|
||||||
{
|
|
||||||
auto pid = fork();
|
|
||||||
if (pid_forked) {
|
|
||||||
if (pid > 0)
|
|
||||||
*pid_forked = pid;
|
|
||||||
else
|
|
||||||
*pid_forked = 0;
|
|
||||||
}
|
|
||||||
if (pid == -1) {
|
|
||||||
qWarning() << "IndirectOpen failed to fork: " << errno;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// child - do the stuff
|
|
||||||
if (pid == 0) {
|
|
||||||
// unset all this garbage so it doesn't get passed to the child process
|
|
||||||
qunsetenv("LD_PRELOAD");
|
|
||||||
qunsetenv("LD_LIBRARY_PATH");
|
|
||||||
qunsetenv("LD_DEBUG");
|
|
||||||
qunsetenv("QT_PLUGIN_PATH");
|
|
||||||
qunsetenv("QT_FONTPATH");
|
|
||||||
|
|
||||||
// open the URL
|
|
||||||
auto status = callable();
|
|
||||||
|
|
||||||
// detach from the parent process group.
|
|
||||||
setsid();
|
|
||||||
|
|
||||||
// die. now. do not clean up anything, it would just hang forever.
|
|
||||||
_exit(status ? 0 : 1);
|
|
||||||
} else {
|
|
||||||
// parent - assume it worked.
|
|
||||||
int status;
|
|
||||||
while (waitpid(pid, &status, 0)) {
|
|
||||||
if (WIFEXITED(status)) {
|
|
||||||
return WEXITSTATUS(status) == 0;
|
|
||||||
}
|
|
||||||
if (WIFSIGNALED(status)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace DesktopServices {
|
namespace DesktopServices {
|
||||||
bool openDirectory(const QString& path, [[maybe_unused]] bool ensureExists)
|
bool openPath(const QFileInfo& path, bool ensureFolderPathExists)
|
||||||
{
|
{
|
||||||
qDebug() << "Opening directory" << path;
|
qDebug() << "Opening path" << path;
|
||||||
QDir parentPath;
|
if (ensureFolderPathExists) {
|
||||||
QDir dir(path);
|
FS::ensureFolderPathExists(path);
|
||||||
if (ensureExists && !dir.exists()) {
|
|
||||||
parentPath.mkpath(dir.absolutePath());
|
|
||||||
}
|
}
|
||||||
auto f = [&]() { return QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath())); };
|
return openUrl(QUrl::fromLocalFile(QFileInfo(path).absoluteFilePath()));
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
|
||||||
if (!isSandbox()) {
|
|
||||||
return IndirectOpen(f);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return f();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool openFile(const QString& path)
|
bool openPath(const QString& path, bool ensureFolderPathExists)
|
||||||
{
|
{
|
||||||
qDebug() << "Opening file" << path;
|
return openPath(QFileInfo(path), ensureFolderPathExists);
|
||||||
auto f = [&]() { return QDesktopServices::openUrl(QUrl::fromLocalFile(path)); };
|
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
|
||||||
if (!isSandbox()) {
|
|
||||||
return IndirectOpen(f);
|
|
||||||
} else {
|
|
||||||
return f();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return f();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool openFile(const QString& application, const QString& path, const QString& workingDirectory, qint64* pid)
|
|
||||||
{
|
|
||||||
qDebug() << "Opening file" << path << "using" << application;
|
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
|
||||||
// FIXME: the pid here is fake. So if something depends on it, it will likely misbehave
|
|
||||||
if (!isSandbox()) {
|
|
||||||
return IndirectOpen([&]() { return QProcess::startDetached(application, QStringList() << path, workingDirectory); }, pid);
|
|
||||||
} else {
|
|
||||||
return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool run(const QString& application, const QStringList& args, const QString& workingDirectory, qint64* pid)
|
bool run(const QString& application, const QStringList& args, const QString& workingDirectory, qint64* pid)
|
||||||
{
|
{
|
||||||
qDebug() << "Running" << application << "with args" << args.join(' ');
|
qDebug() << "Running" << application << "with args" << args.join(' ');
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
|
||||||
if (!isSandbox()) {
|
|
||||||
// FIXME: the pid here is fake. So if something depends on it, it will likely misbehave
|
|
||||||
return IndirectOpen([&]() { return QProcess::startDetached(application, args, workingDirectory); }, pid);
|
|
||||||
} else {
|
|
||||||
return QProcess::startDetached(application, args, workingDirectory, pid);
|
return QProcess::startDetached(application, args, workingDirectory, pid);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
return QProcess::startDetached(application, args, workingDirectory, pid);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool openUrl(const QUrl& url)
|
bool openUrl(const QUrl& url)
|
||||||
{
|
{
|
||||||
qDebug() << "Opening URL" << url.toString();
|
qDebug() << "Opening URL" << url.toString();
|
||||||
auto f = [&]() { return QDesktopServices::openUrl(url); };
|
return QDesktopServices::openUrl(url);
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
|
||||||
if (!isSandbox()) {
|
|
||||||
return IndirectOpen(f);
|
|
||||||
} else {
|
|
||||||
return f();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return f();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isFlatpak()
|
bool isFlatpak()
|
||||||
@ -191,9 +84,4 @@ bool isSnap()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSandbox()
|
|
||||||
{
|
|
||||||
return isSnap() || isFlatpak();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace DesktopServices
|
} // namespace DesktopServices
|
||||||
|
@ -3,31 +3,30 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
|
class QFileInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This wraps around QDesktopServices and adds workarounds where needed
|
* This wraps around QDesktopServices and adds workarounds where needed
|
||||||
* Use this instead of QDesktopServices!
|
* Use this instead of QDesktopServices!
|
||||||
*/
|
*/
|
||||||
namespace DesktopServices {
|
namespace DesktopServices {
|
||||||
/**
|
/**
|
||||||
* Open a file in whatever application is applicable
|
* Open a path in whatever application is applicable.
|
||||||
|
* @param ensureFolderPathExists Make sure the path exists
|
||||||
*/
|
*/
|
||||||
bool openFile(const QString& path);
|
bool openPath(const QFileInfo& path, bool ensureFolderPathExists = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a file in the specified application
|
* Open a path in whatever application is applicable.
|
||||||
|
* @param ensureFolderPathExists Make sure the path exists
|
||||||
*/
|
*/
|
||||||
bool openFile(const QString& application, const QString& path, const QString& workingDirectory = QString(), qint64* pid = 0);
|
bool openPath(const QString& path, bool ensureFolderPathExists = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run an application
|
* Run an application
|
||||||
*/
|
*/
|
||||||
bool run(const QString& application, const QStringList& args, const QString& workingDirectory = QString(), qint64* pid = 0);
|
bool run(const QString& application, const QStringList& args, const QString& workingDirectory = QString(), qint64* pid = 0);
|
||||||
|
|
||||||
/**
|
|
||||||
* Open a directory
|
|
||||||
*/
|
|
||||||
bool openDirectory(const QString& path, bool ensureExists = false);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open the URL, most likely in a browser. Maybe.
|
* Open the URL, most likely in a browser. Maybe.
|
||||||
*/
|
*/
|
||||||
@ -42,9 +41,4 @@ bool isFlatpak();
|
|||||||
* Determine whether the launcher is running in a Snap environment
|
* Determine whether the launcher is running in a Snap environment
|
||||||
*/
|
*/
|
||||||
bool isSnap();
|
bool isSnap();
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the launcher is running in a sandboxed (Flatpak or Snap) environment
|
|
||||||
*/
|
|
||||||
bool isSandbox();
|
|
||||||
} // namespace DesktopServices
|
} // namespace DesktopServices
|
||||||
|
@ -1,4 +1,37 @@
|
|||||||
// Licensed under the Apache-2.0 license. See README.md for details.
|
// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2024 TheKodeToad <TheKodeToad@proton.me>
|
||||||
|
*
|
||||||
|
* 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, version 3.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
* This file incorporates work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
@ -8,12 +41,12 @@
|
|||||||
|
|
||||||
class Exception : public std::exception {
|
class Exception : public std::exception {
|
||||||
public:
|
public:
|
||||||
Exception(const QString& message) : std::exception(), m_message(message) { qCritical() << "Exception:" << message; }
|
Exception(const QString& message) : std::exception(), m_message(message.toUtf8()) { qCritical() << "Exception:" << message; }
|
||||||
Exception(const Exception& other) : std::exception(), m_message(other.cause()) {}
|
Exception(const Exception& other) : std::exception(), m_message(other.m_message) {}
|
||||||
virtual ~Exception() noexcept {}
|
virtual ~Exception() noexcept {}
|
||||||
const char* what() const noexcept { return m_message.toLatin1().constData(); }
|
const char* what() const noexcept { return m_message.constData(); }
|
||||||
QString cause() const { return m_message; }
|
QString cause() const { return QString::fromUtf8(m_message); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_message;
|
QByteArray m_message;
|
||||||
};
|
};
|
||||||
|
@ -272,15 +272,19 @@ bool ensureFilePathExists(QString filenamepath)
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ensureFolderPathExists(QString foldernamepath)
|
bool ensureFolderPathExists(const QFileInfo folderPath)
|
||||||
{
|
{
|
||||||
QFileInfo a(foldernamepath);
|
|
||||||
QDir dir;
|
QDir dir;
|
||||||
QString ensuredPath = a.filePath();
|
QString ensuredPath = folderPath.filePath();
|
||||||
bool success = dir.mkpath(ensuredPath);
|
bool success = dir.mkpath(ensuredPath);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ensureFolderPathExists(const QString folderPathName)
|
||||||
|
{
|
||||||
|
return ensureFolderPathExists(QFileInfo(folderPathName));
|
||||||
|
}
|
||||||
|
|
||||||
bool copyFileAttributes(QString src, QString dst)
|
bool copyFileAttributes(QString src, QString dst)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
|
@ -91,7 +91,13 @@ bool ensureFilePathExists(QString filenamepath);
|
|||||||
* Creates all the folders in a path for the specified path
|
* Creates all the folders in a path for the specified path
|
||||||
* last segment of the path is treated as a folder name and is created!
|
* last segment of the path is treated as a folder name and is created!
|
||||||
*/
|
*/
|
||||||
bool ensureFolderPathExists(QString filenamepath);
|
bool ensureFolderPathExists(const QFileInfo folderPath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates all the folders in a path for the specified path
|
||||||
|
* last segment of the path is treated as a folder name and is created!
|
||||||
|
*/
|
||||||
|
bool ensureFolderPathExists(const QString folderPathName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Copies a directory and it's contents from src to dest
|
* @brief Copies a directory and it's contents from src to dest
|
||||||
|
@ -43,10 +43,10 @@ void InstanceCopyTask::executeTask()
|
|||||||
QFileInfo dotMCDir(FS::PathCombine(m_stagingPath, ".minecraft"));
|
QFileInfo dotMCDir(FS::PathCombine(m_stagingPath, ".minecraft"));
|
||||||
|
|
||||||
QString staging_mc_dir;
|
QString staging_mc_dir;
|
||||||
if (mcDir.exists() && !dotMCDir.exists())
|
if (dotMCDir.exists() && !mcDir.exists())
|
||||||
staging_mc_dir = mcDir.filePath();
|
|
||||||
else
|
|
||||||
staging_mc_dir = dotMCDir.filePath();
|
staging_mc_dir = dotMCDir.filePath();
|
||||||
|
else
|
||||||
|
staging_mc_dir = mcDir.filePath();
|
||||||
|
|
||||||
FS::copy savesCopy(FS::PathCombine(m_origInstance->gameRoot(), "saves"), FS::PathCombine(staging_mc_dir, "saves"));
|
FS::copy savesCopy(FS::PathCombine(m_origInstance->gameRoot(), "saves"), FS::PathCombine(staging_mc_dir, "saves"));
|
||||||
savesCopy.followSymlinks(true);
|
savesCopy.followSymlinks(true);
|
||||||
|
@ -164,8 +164,8 @@ void InstanceImportTask::processZipPack()
|
|||||||
} else if (technicFound) {
|
} else if (technicFound) {
|
||||||
// process as Technic pack
|
// process as Technic pack
|
||||||
qDebug() << "Technic:" << technicFound;
|
qDebug() << "Technic:" << technicFound;
|
||||||
extractDir.mkpath(".minecraft");
|
extractDir.mkpath("minecraft");
|
||||||
extractDir.cd(".minecraft");
|
extractDir.cd("minecraft");
|
||||||
m_modpackType = ModpackType::Technic;
|
m_modpackType = ModpackType::Technic;
|
||||||
} else {
|
} else {
|
||||||
QStringList paths_to_ignore{ "overrides/" };
|
QStringList paths_to_ignore{ "overrides/" };
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
#include <QFileSystemWatcher>
|
#include <QFileSystemWatcher>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
@ -847,14 +848,16 @@ class InstanceStaging : public Task {
|
|||||||
const unsigned maxBackoff = 16;
|
const unsigned maxBackoff = 16;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InstanceStaging(InstanceList* parent, InstanceTask* child, QString stagingPath, InstanceName const& instanceName, QString groupName)
|
InstanceStaging(InstanceList* parent, InstanceTask* child, SettingsObjectPtr settings)
|
||||||
: m_parent(parent)
|
: m_parent(parent), backoff(minBackoff, maxBackoff)
|
||||||
, backoff(minBackoff, maxBackoff)
|
|
||||||
, m_stagingPath(std::move(stagingPath))
|
|
||||||
, m_instance_name(std::move(instanceName))
|
|
||||||
, m_groupName(std::move(groupName))
|
|
||||||
{
|
{
|
||||||
|
m_stagingPath = parent->getStagedInstancePath();
|
||||||
|
|
||||||
m_child.reset(child);
|
m_child.reset(child);
|
||||||
|
|
||||||
|
m_child->setStagingPath(m_stagingPath);
|
||||||
|
m_child->setParentSettings(std::move(settings));
|
||||||
|
|
||||||
connect(child, &Task::succeeded, this, &InstanceStaging::childSucceeded);
|
connect(child, &Task::succeeded, this, &InstanceStaging::childSucceeded);
|
||||||
connect(child, &Task::failed, this, &InstanceStaging::childFailed);
|
connect(child, &Task::failed, this, &InstanceStaging::childFailed);
|
||||||
connect(child, &Task::aborted, this, &InstanceStaging::childAborted);
|
connect(child, &Task::aborted, this, &InstanceStaging::childAborted);
|
||||||
@ -866,7 +869,7 @@ class InstanceStaging : public Task {
|
|||||||
connect(&m_backoffTimer, &QTimer::timeout, this, &InstanceStaging::childSucceeded);
|
connect(&m_backoffTimer, &QTimer::timeout, this, &InstanceStaging::childSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~InstanceStaging(){};
|
virtual ~InstanceStaging() {}
|
||||||
|
|
||||||
// FIXME/TODO: add ability to abort during instance commit retries
|
// FIXME/TODO: add ability to abort during instance commit retries
|
||||||
bool abort() override
|
bool abort() override
|
||||||
@ -881,14 +884,22 @@ class InstanceStaging : public Task {
|
|||||||
bool canAbort() const override { return (m_child && m_child->canAbort()); }
|
bool canAbort() const override { return (m_child && m_child->canAbort()); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void executeTask() override { m_child->start(); }
|
virtual void executeTask() override
|
||||||
|
{
|
||||||
|
if (m_stagingPath.isNull()) {
|
||||||
|
emitFailed(tr("Could not create staging folder"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_child->start();
|
||||||
|
}
|
||||||
QStringList warnings() const override { return m_child->warnings(); }
|
QStringList warnings() const override { return m_child->warnings(); }
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void childSucceeded()
|
void childSucceeded()
|
||||||
{
|
{
|
||||||
unsigned sleepTime = backoff();
|
unsigned sleepTime = backoff();
|
||||||
if (m_parent->commitStagedInstance(m_stagingPath, m_instance_name, m_groupName, *m_child.get())) {
|
if (m_parent->commitStagedInstance(m_stagingPath, *m_child.get(), m_child->group(), *m_child.get())) {
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -897,7 +908,7 @@ class InstanceStaging : public Task {
|
|||||||
emitFailed(tr("Failed to commit instance, even after multiple retries. It is being blocked by something."));
|
emitFailed(tr("Failed to commit instance, even after multiple retries. It is being blocked by something."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
qDebug() << "Failed to commit instance" << m_instance_name.name() << "Initiating backoff:" << sleepTime;
|
qDebug() << "Failed to commit instance" << m_child->name() << "Initiating backoff:" << sleepTime;
|
||||||
m_backoffTimer.start(sleepTime * 500);
|
m_backoffTimer.start(sleepTime * 500);
|
||||||
}
|
}
|
||||||
void childFailed(const QString& reason)
|
void childFailed(const QString& reason)
|
||||||
@ -906,7 +917,11 @@ class InstanceStaging : public Task {
|
|||||||
emitFailed(reason);
|
emitFailed(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void childAborted() { emitAborted(); }
|
void childAborted()
|
||||||
|
{
|
||||||
|
m_parent->destroyStagingPath(m_stagingPath);
|
||||||
|
emitAborted();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
InstanceList* m_parent;
|
InstanceList* m_parent;
|
||||||
@ -918,34 +933,35 @@ class InstanceStaging : public Task {
|
|||||||
ExponentialSeries backoff;
|
ExponentialSeries backoff;
|
||||||
QString m_stagingPath;
|
QString m_stagingPath;
|
||||||
unique_qobject_ptr<InstanceTask> m_child;
|
unique_qobject_ptr<InstanceTask> m_child;
|
||||||
InstanceName m_instance_name;
|
|
||||||
QString m_groupName;
|
|
||||||
QTimer m_backoffTimer;
|
QTimer m_backoffTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
Task* InstanceList::wrapInstanceTask(InstanceTask* task)
|
Task* InstanceList::wrapInstanceTask(InstanceTask* task)
|
||||||
{
|
{
|
||||||
auto stagingPath = getStagedInstancePath();
|
return new InstanceStaging(this, task, m_globalSettings);
|
||||||
task->setStagingPath(stagingPath);
|
|
||||||
task->setParentSettings(m_globalSettings);
|
|
||||||
return new InstanceStaging(this, task, stagingPath, *task, task->group());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString InstanceList::getStagedInstancePath()
|
QString InstanceList::getStagedInstancePath()
|
||||||
{
|
{
|
||||||
QString key = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
const QString tempRoot = FS::PathCombine(m_instDir, ".tmp");
|
||||||
QString tempDir = ".LAUNCHER_TEMP/";
|
|
||||||
QString relPath = FS::PathCombine(tempDir, key);
|
QString result;
|
||||||
QDir rootPath(m_instDir);
|
int tries = 0;
|
||||||
auto path = FS::PathCombine(m_instDir, relPath);
|
|
||||||
if (!rootPath.mkpath(relPath)) {
|
do {
|
||||||
return QString();
|
if (++tries > 256)
|
||||||
}
|
return {};
|
||||||
|
|
||||||
|
const QString key = QUuid::createUuid().toString(QUuid::Id128).left(6);
|
||||||
|
result = FS::PathCombine(tempRoot, key);
|
||||||
|
} while (QFileInfo::exists(result));
|
||||||
|
|
||||||
|
if (!QDir::current().mkpath(result))
|
||||||
|
return {};
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
auto tempPath = FS::PathCombine(m_instDir, tempDir);
|
SetFileAttributesA(tempRoot.toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
|
||||||
SetFileAttributesA(tempPath.toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
|
|
||||||
#endif
|
#endif
|
||||||
return path;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstanceList::commitStagedInstance(const QString& path,
|
bool InstanceList::commitStagedInstance(const QString& path,
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
|
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& old_name, const QString& new_name)
|
InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& old_name, const QString& new_name)
|
||||||
{
|
{
|
||||||
auto dialog =
|
auto dialog =
|
||||||
@ -27,16 +29,15 @@ ShouldUpdate askIfShouldUpdate(QWidget* parent, QString original_version_name)
|
|||||||
"separate instance, or update the existing one?\n\nNOTE: Make sure you made a backup of your important instance data before "
|
"separate instance, or update the existing one?\n\nNOTE: Make sure you made a backup of your important instance data before "
|
||||||
"updating, as worlds can be corrupted and some configuration may be lost (due to pack overrides).")
|
"updating, as worlds can be corrupted and some configuration may be lost (due to pack overrides).")
|
||||||
.arg(original_version_name),
|
.arg(original_version_name),
|
||||||
QMessageBox::Information, QMessageBox::Ok | QMessageBox::Reset | QMessageBox::Abort);
|
QMessageBox::Information, QMessageBox::Cancel);
|
||||||
info->setButtonText(QMessageBox::Ok, QObject::tr("Update existing instance"));
|
QAbstractButton* update = info->addButton(QObject::tr("Update existing instance"), QMessageBox::AcceptRole);
|
||||||
info->setButtonText(QMessageBox::Abort, QObject::tr("Create new instance"));
|
QAbstractButton* skip = info->addButton(QObject::tr("Create new instance"), QMessageBox::ResetRole);
|
||||||
info->setButtonText(QMessageBox::Reset, QObject::tr("Cancel"));
|
|
||||||
|
|
||||||
info->exec();
|
info->exec();
|
||||||
|
|
||||||
if (info->clickedButton() == info->button(QMessageBox::Ok))
|
if (info->clickedButton() == update)
|
||||||
return ShouldUpdate::Update;
|
return ShouldUpdate::Update;
|
||||||
if (info->clickedButton() == info->button(QMessageBox::Abort))
|
if (info->clickedButton() == skip)
|
||||||
return ShouldUpdate::SkipUpdating;
|
return ShouldUpdate::SkipUpdating;
|
||||||
return ShouldUpdate::Cancel;
|
return ShouldUpdate::Cancel;
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,6 @@
|
|||||||
#include "ui/InstanceWindow.h"
|
#include "ui/InstanceWindow.h"
|
||||||
#include "ui/MainWindow.h"
|
#include "ui/MainWindow.h"
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
#include "ui/dialogs/EditAccountDialog.h"
|
|
||||||
#include "ui/dialogs/ProfileSelectDialog.h"
|
#include "ui/dialogs/ProfileSelectDialog.h"
|
||||||
#include "ui/dialogs/ProfileSetupDialog.h"
|
#include "ui/dialogs/ProfileSetupDialog.h"
|
||||||
#include "ui/dialogs/ProgressDialog.h"
|
#include "ui/dialogs/ProgressDialog.h"
|
||||||
@ -144,6 +143,12 @@ void LaunchController::login()
|
|||||||
bool tryagain = true;
|
bool tryagain = true;
|
||||||
unsigned int tries = 0;
|
unsigned int tries = 0;
|
||||||
|
|
||||||
|
if (m_accountToUse->accountType() != AccountType::Offline && m_accountToUse->accountState() == AccountState::Offline) {
|
||||||
|
// Force account refresh on the account used to launch the instance updating the AccountState
|
||||||
|
// only on first try and if it is not meant to be offline
|
||||||
|
auto accounts = APPLICATION->accounts();
|
||||||
|
accounts->requestRefresh(m_accountToUse->internalId());
|
||||||
|
}
|
||||||
while (tryagain) {
|
while (tryagain) {
|
||||||
if (tries > 0 && tries % 3 == 0) {
|
if (tries > 0 && tries % 3 == 0) {
|
||||||
auto result =
|
auto result =
|
||||||
@ -250,12 +255,6 @@ void LaunchController::login()
|
|||||||
progDialog.execWithTask(task.get());
|
progDialog.execWithTask(task.get());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// FIXME: this is missing - the meaning is that the account is queued for refresh and we should wait for that
|
|
||||||
/*
|
|
||||||
case AccountState::Queued: {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
case AccountState::Expired: {
|
case AccountState::Expired: {
|
||||||
auto errorString = tr("The account has expired and needs to be logged into manually again.");
|
auto errorString = tr("The account has expired and needs to be logged into manually again.");
|
||||||
QMessageBox::warning(m_parentWidget, tr("Account refresh failed"), errorString, QMessageBox::StandardButton::Ok,
|
QMessageBox::warning(m_parentWidget, tr("Account refresh failed"), errorString, QMessageBox::StandardButton::Ok,
|
||||||
|
@ -463,7 +463,7 @@ auto ExportToZipTask::exportZip() -> ZipResult
|
|||||||
|
|
||||||
auto absolute = file.absoluteFilePath();
|
auto absolute = file.absoluteFilePath();
|
||||||
auto relative = m_dir.relativeFilePath(absolute);
|
auto relative = m_dir.relativeFilePath(absolute);
|
||||||
setStatus("Compresing: " + relative);
|
setStatus("Compressing: " + relative);
|
||||||
setProgress(m_progress + 1, m_progressTotal);
|
setProgress(m_progress + 1, m_progressTotal);
|
||||||
if (m_follow_symlinks) {
|
if (m_follow_symlinks) {
|
||||||
if (file.isSymLink())
|
if (file.isSymLink())
|
||||||
|
@ -173,11 +173,12 @@ void MinecraftInstance::loadSpecificSettings()
|
|||||||
m_settings->registerOverride(global_settings->getSetting("UseNativeGLFW"), nativeLibraryWorkaroundsOverride);
|
m_settings->registerOverride(global_settings->getSetting("UseNativeGLFW"), nativeLibraryWorkaroundsOverride);
|
||||||
m_settings->registerOverride(global_settings->getSetting("CustomGLFWPath"), nativeLibraryWorkaroundsOverride);
|
m_settings->registerOverride(global_settings->getSetting("CustomGLFWPath"), nativeLibraryWorkaroundsOverride);
|
||||||
|
|
||||||
// Peformance related options
|
// Performance related options
|
||||||
auto performanceOverride = m_settings->registerSetting("OverridePerformance", false);
|
auto performanceOverride = m_settings->registerSetting("OverridePerformance", false);
|
||||||
m_settings->registerOverride(global_settings->getSetting("EnableFeralGamemode"), performanceOverride);
|
m_settings->registerOverride(global_settings->getSetting("EnableFeralGamemode"), performanceOverride);
|
||||||
m_settings->registerOverride(global_settings->getSetting("EnableMangoHud"), performanceOverride);
|
m_settings->registerOverride(global_settings->getSetting("EnableMangoHud"), performanceOverride);
|
||||||
m_settings->registerOverride(global_settings->getSetting("UseDiscreteGpu"), performanceOverride);
|
m_settings->registerOverride(global_settings->getSetting("UseDiscreteGpu"), performanceOverride);
|
||||||
|
m_settings->registerOverride(global_settings->getSetting("UseZink"), performanceOverride);
|
||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
auto miscellaneousOverride = m_settings->registerSetting("OverrideMiscellaneous", false);
|
auto miscellaneousOverride = m_settings->registerSetting("OverrideMiscellaneous", false);
|
||||||
@ -292,10 +293,10 @@ QString MinecraftInstance::gameRoot() const
|
|||||||
QFileInfo mcDir(FS::PathCombine(instanceRoot(), "minecraft"));
|
QFileInfo mcDir(FS::PathCombine(instanceRoot(), "minecraft"));
|
||||||
QFileInfo dotMCDir(FS::PathCombine(instanceRoot(), ".minecraft"));
|
QFileInfo dotMCDir(FS::PathCombine(instanceRoot(), ".minecraft"));
|
||||||
|
|
||||||
if (mcDir.exists() && !dotMCDir.exists())
|
if (dotMCDir.exists() && !mcDir.exists())
|
||||||
return mcDir.filePath();
|
|
||||||
else
|
|
||||||
return dotMCDir.filePath();
|
return dotMCDir.filePath();
|
||||||
|
else
|
||||||
|
return mcDir.filePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MinecraftInstance::binRoot() const
|
QString MinecraftInstance::binRoot() const
|
||||||
@ -594,9 +595,6 @@ QProcessEnvironment MinecraftInstance::createLaunchEnvironment()
|
|||||||
QStringList preloadList;
|
QStringList preloadList;
|
||||||
if (auto value = env.value("LD_PRELOAD"); !value.isEmpty())
|
if (auto value = env.value("LD_PRELOAD"); !value.isEmpty())
|
||||||
preloadList = value.split(QLatin1String(":"));
|
preloadList = value.split(QLatin1String(":"));
|
||||||
QStringList libPaths;
|
|
||||||
if (auto value = env.value("LD_LIBRARY_PATH"); !value.isEmpty())
|
|
||||||
libPaths = value.split(QLatin1String(":"));
|
|
||||||
|
|
||||||
auto mangoHudLibString = MangoHud::getLibraryString();
|
auto mangoHudLibString = MangoHud::getLibraryString();
|
||||||
if (!mangoHudLibString.isEmpty()) {
|
if (!mangoHudLibString.isEmpty()) {
|
||||||
@ -604,18 +602,16 @@ QProcessEnvironment MinecraftInstance::createLaunchEnvironment()
|
|||||||
QString libPath = mangoHudLib.absolutePath();
|
QString libPath = mangoHudLib.absolutePath();
|
||||||
auto appendLib = [libPath, &preloadList](QString fileName) {
|
auto appendLib = [libPath, &preloadList](QString fileName) {
|
||||||
if (QFileInfo(FS::PathCombine(libPath, fileName)).exists())
|
if (QFileInfo(FS::PathCombine(libPath, fileName)).exists())
|
||||||
preloadList << fileName;
|
preloadList << FS::PathCombine(libPath, fileName);
|
||||||
};
|
};
|
||||||
|
|
||||||
// dlsym variant is only needed for OpenGL and not included in the vulkan layer
|
// dlsym variant is only needed for OpenGL and not included in the vulkan layer
|
||||||
appendLib("libMangoHud_dlsym.so");
|
appendLib("libMangoHud_dlsym.so");
|
||||||
appendLib("libMangoHud_opengl.so");
|
appendLib("libMangoHud_opengl.so");
|
||||||
appendLib(mangoHudLib.fileName());
|
appendLib(mangoHudLib.fileName());
|
||||||
libPaths << libPath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
env.insert("LD_PRELOAD", preloadList.join(QLatin1String(":")));
|
env.insert("LD_PRELOAD", preloadList.join(QLatin1String(":")));
|
||||||
env.insert("LD_LIBRARY_PATH", libPaths.join(QLatin1String(":")));
|
|
||||||
env.insert("MANGOHUD", "1");
|
env.insert("MANGOHUD", "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -627,6 +623,13 @@ QProcessEnvironment MinecraftInstance::createLaunchEnvironment()
|
|||||||
env.insert("__VK_LAYER_NV_optimus", "NVIDIA_only");
|
env.insert("__VK_LAYER_NV_optimus", "NVIDIA_only");
|
||||||
env.insert("__GLX_VENDOR_LIBRARY_NAME", "nvidia");
|
env.insert("__GLX_VENDOR_LIBRARY_NAME", "nvidia");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settings()->get("UseZink").toBool()) {
|
||||||
|
// taken from https://wiki.archlinux.org/title/OpenGL#OpenGL_over_Vulkan_(Zink)
|
||||||
|
env.insert("__GLX_VENDOR_LIBRARY_NAME", "mesa");
|
||||||
|
env.insert("MESA_LOADER_DRIVER_OVERRIDE", "zink");
|
||||||
|
env.insert("GALLIUM_DRIVER", "zink");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
@ -157,20 +157,6 @@ void MojangVersionFormat::readVersionProperties(const QJsonObject& in, VersionFi
|
|||||||
Bits::readString(in, "id", out->minecraftVersion);
|
Bits::readString(in, "id", out->minecraftVersion);
|
||||||
Bits::readString(in, "mainClass", out->mainClass);
|
Bits::readString(in, "mainClass", out->mainClass);
|
||||||
Bits::readString(in, "minecraftArguments", out->minecraftArguments);
|
Bits::readString(in, "minecraftArguments", out->minecraftArguments);
|
||||||
if (out->minecraftArguments.isEmpty()) {
|
|
||||||
QString processArguments;
|
|
||||||
Bits::readString(in, "processArguments", processArguments);
|
|
||||||
QString toCompare = processArguments.toLower();
|
|
||||||
if (toCompare == "legacy") {
|
|
||||||
out->minecraftArguments = " ${auth_player_name} ${auth_session}";
|
|
||||||
} else if (toCompare == "username_session") {
|
|
||||||
out->minecraftArguments = "--username ${auth_player_name} --session ${auth_session}";
|
|
||||||
} else if (toCompare == "username_session_version") {
|
|
||||||
out->minecraftArguments = "--username ${auth_player_name} --session ${auth_session} --version ${profile_name}";
|
|
||||||
} else if (!toCompare.isEmpty()) {
|
|
||||||
out->addProblem(ProblemSeverity::Error, QObject::tr("processArguments is set to unknown value '%1'").arg(processArguments));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Bits::readString(in, "type", out->type);
|
Bits::readString(in, "type", out->type);
|
||||||
|
|
||||||
Bits::readString(in, "assets", out->assets);
|
Bits::readString(in, "assets", out->assets);
|
||||||
|
@ -52,8 +52,6 @@
|
|||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
#include <QSaveFile>
|
#include <QSaveFile>
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
enum AccountListVersion { MojangMSA = 3 };
|
enum AccountListVersion { MojangMSA = 3 };
|
||||||
|
|
||||||
AccountList::AccountList(QObject* parent) : QAbstractListModel(parent)
|
AccountList::AccountList(QObject* parent) : QAbstractListModel(parent)
|
||||||
|
@ -193,7 +193,7 @@ Task::Ptr GetModDependenciesTask::prepareDependencyTask(const ModPlatform::Depen
|
|||||||
ResourceAPI::DependencySearchArgs args = { dep, m_version, m_loaderType };
|
ResourceAPI::DependencySearchArgs args = { dep, m_version, m_loaderType };
|
||||||
ResourceAPI::DependencySearchCallbacks callbacks;
|
ResourceAPI::DependencySearchCallbacks callbacks;
|
||||||
callbacks.on_fail = [](QString reason, int) {
|
callbacks.on_fail = [](QString reason, int) {
|
||||||
qCritical() << tr("A network error occurred. Could not load project dependenies:%1").arg(reason);
|
qCritical() << tr("A network error occurred. Could not load project dependencies:%1").arg(reason);
|
||||||
};
|
};
|
||||||
callbacks.on_succeed = [dep, provider, pDep, level, this](auto& doc, [[maybe_unused]] auto& pack) {
|
callbacks.on_succeed = [dep, provider, pDep, level, this](auto& doc, [[maybe_unused]] auto& pack) {
|
||||||
try {
|
try {
|
||||||
|
@ -123,6 +123,8 @@ struct ExtraPackData {
|
|||||||
QString wikiUrl;
|
QString wikiUrl;
|
||||||
QString discordUrl;
|
QString discordUrl;
|
||||||
|
|
||||||
|
QString status;
|
||||||
|
|
||||||
QString body;
|
QString body;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -354,6 +354,8 @@ bool FlameCreationTask::createInstance()
|
|||||||
auto id = loader.id;
|
auto id = loader.id;
|
||||||
if (id.startsWith("neoforge-")) {
|
if (id.startsWith("neoforge-")) {
|
||||||
id.remove("neoforge-");
|
id.remove("neoforge-");
|
||||||
|
if (id.startsWith("1.20.1-"))
|
||||||
|
id.remove("1.20.1-"); // this is a mess for curseforge
|
||||||
loaderType = "neoforge";
|
loaderType = "neoforge";
|
||||||
loaderUid = "net.neoforged";
|
loaderUid = "net.neoforged";
|
||||||
} else if (id.startsWith("forge-")) {
|
} else if (id.startsWith("forge-")) {
|
||||||
|
@ -398,8 +398,12 @@ QByteArray FlamePackExportTask::generateIndex()
|
|||||||
id = "fabric-" + fabric->getVersion();
|
id = "fabric-" + fabric->getVersion();
|
||||||
else if (forge != nullptr)
|
else if (forge != nullptr)
|
||||||
id = "forge-" + forge->getVersion();
|
id = "forge-" + forge->getVersion();
|
||||||
else if (neoforge != nullptr)
|
else if (neoforge != nullptr) {
|
||||||
id = "neoforge-" + neoforge->getVersion();
|
id = "neoforge-";
|
||||||
|
if (minecraft->m_version == "1.20.1")
|
||||||
|
id += "1.20.1-";
|
||||||
|
id += neoforge->getVersion();
|
||||||
|
}
|
||||||
version["modLoaders"] = QJsonArray();
|
version["modLoaders"] = QJsonArray();
|
||||||
if (!id.isEmpty()) {
|
if (!id.isEmpty()) {
|
||||||
QJsonObject loader;
|
QJsonObject loader;
|
||||||
|
@ -43,7 +43,7 @@ Task::Ptr NetworkResourceAPI::searchProjects(SearchArgs&& args, SearchCallbacks&
|
|||||||
callbacks.on_succeed(doc);
|
callbacks.on_succeed(doc);
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::failed, [&netJob, callbacks](QString reason) {
|
QObject::connect(netJob.get(), &NetJob::failed, [netJob, callbacks](const QString& reason) {
|
||||||
int network_error_code = -1;
|
int network_error_code = -1;
|
||||||
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply)
|
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply)
|
||||||
network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
@ -102,7 +102,7 @@ Task::Ptr NetworkResourceAPI::getProjectVersions(VersionSearchArgs&& args, Versi
|
|||||||
|
|
||||||
callbacks.on_succeed(doc, args.pack);
|
callbacks.on_succeed(doc, args.pack);
|
||||||
});
|
});
|
||||||
QObject::connect(netJob.get(), &NetJob::failed, [&netJob, callbacks](QString reason) {
|
QObject::connect(netJob.get(), &NetJob::failed, [netJob, callbacks](const QString& reason) {
|
||||||
int network_error_code = -1;
|
int network_error_code = -1;
|
||||||
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply)
|
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply)
|
||||||
network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
@ -153,7 +153,7 @@ Task::Ptr NetworkResourceAPI::getDependencyVersion(DependencySearchArgs&& args,
|
|||||||
|
|
||||||
callbacks.on_succeed(doc, args.dependency);
|
callbacks.on_succeed(doc, args.dependency);
|
||||||
});
|
});
|
||||||
QObject::connect(netJob.get(), &NetJob::failed, [&netJob, callbacks](QString reason) {
|
QObject::connect(netJob.get(), &NetJob::failed, [netJob, callbacks](const QString& reason) {
|
||||||
int network_error_code = -1;
|
int network_error_code = -1;
|
||||||
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply)
|
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply)
|
||||||
network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
@ -37,7 +37,7 @@ void PackInstallTask::executeTask()
|
|||||||
progress(1, 2);
|
progress(1, 2);
|
||||||
|
|
||||||
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this] {
|
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this] {
|
||||||
FS::copy folderCopy(m_pack.path, FS::PathCombine(m_stagingPath, ".minecraft"));
|
FS::copy folderCopy(m_pack.path, FS::PathCombine(m_stagingPath, "minecraft"));
|
||||||
folderCopy.followSymlinks(true);
|
folderCopy.followSymlinks(true);
|
||||||
return folderCopy();
|
return folderCopy();
|
||||||
});
|
});
|
||||||
|
@ -137,7 +137,7 @@ void PackInstallTask::install()
|
|||||||
QDir unzipMcDir(m_stagingPath + "/unzip/minecraft");
|
QDir unzipMcDir(m_stagingPath + "/unzip/minecraft");
|
||||||
if (unzipMcDir.exists()) {
|
if (unzipMcDir.exists()) {
|
||||||
// ok, found minecraft dir, move contents to instance dir
|
// ok, found minecraft dir, move contents to instance dir
|
||||||
if (!QDir().rename(m_stagingPath + "/unzip/minecraft", m_stagingPath + "/.minecraft")) {
|
if (!QDir().rename(m_stagingPath + "/unzip/minecraft", m_stagingPath + "/minecraft")) {
|
||||||
emitFailed(tr("Failed to move unzipped Minecraft!"));
|
emitFailed(tr("Failed to move unzipped Minecraft!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -155,7 +155,7 @@ void PackInstallTask::install()
|
|||||||
bool fallback = true;
|
bool fallback = true;
|
||||||
|
|
||||||
// handle different versions
|
// handle different versions
|
||||||
QFile packJson(m_stagingPath + "/.minecraft/pack.json");
|
QFile packJson(m_stagingPath + "/minecraft/pack.json");
|
||||||
QDir jarmodDir = QDir(m_stagingPath + "/unzip/instMods");
|
QDir jarmodDir = QDir(m_stagingPath + "/unzip/instMods");
|
||||||
if (packJson.exists()) {
|
if (packJson.exists()) {
|
||||||
packJson.open(QIODevice::ReadOnly | QIODevice::Text);
|
packJson.open(QIODevice::ReadOnly | QIODevice::Text);
|
||||||
|
@ -173,7 +173,7 @@ bool ModrinthCreationTask::createInstance()
|
|||||||
FS::ensureFilePathExists(new_index_place);
|
FS::ensureFilePathExists(new_index_place);
|
||||||
QFile::rename(index_path, new_index_place);
|
QFile::rename(index_path, new_index_place);
|
||||||
|
|
||||||
auto mcPath = FS::PathCombine(m_stagingPath, ".minecraft");
|
auto mcPath = FS::PathCombine(m_stagingPath, "minecraft");
|
||||||
|
|
||||||
auto override_path = FS::PathCombine(m_stagingPath, "overrides");
|
auto override_path = FS::PathCombine(m_stagingPath, "overrides");
|
||||||
if (QFile::exists(override_path)) {
|
if (QFile::exists(override_path)) {
|
||||||
@ -234,7 +234,7 @@ bool ModrinthCreationTask::createInstance()
|
|||||||
|
|
||||||
m_files_job.reset(new NetJob(tr("Mod Download Modrinth"), APPLICATION->network()));
|
m_files_job.reset(new NetJob(tr("Mod Download Modrinth"), APPLICATION->network()));
|
||||||
|
|
||||||
auto root_modpack_path = FS::PathCombine(m_stagingPath, ".minecraft");
|
auto root_modpack_path = FS::PathCombine(m_stagingPath, "minecraft");
|
||||||
auto root_modpack_url = QUrl::fromLocalFile(root_modpack_path);
|
auto root_modpack_url = QUrl::fromLocalFile(root_modpack_path);
|
||||||
|
|
||||||
for (auto file : m_files) {
|
for (auto file : m_files) {
|
||||||
|
@ -287,16 +287,12 @@ QByteArray ModrinthPackExportTask::generateIndex()
|
|||||||
env["client"] = "required";
|
env["client"] = "required";
|
||||||
env["server"] = "required";
|
env["server"] = "required";
|
||||||
}
|
}
|
||||||
switch (iterator->side) {
|
|
||||||
case Metadata::ModSide::ClientSide:
|
// a server side mod does not imply that the mod does not work on the client
|
||||||
|
// however, if a mrpack mod is marked as server-only it will not install on the client
|
||||||
|
if (iterator->side == Metadata::ModSide::ClientSide)
|
||||||
env["server"] = "unsupported";
|
env["server"] = "unsupported";
|
||||||
break;
|
|
||||||
case Metadata::ModSide::ServerSide:
|
|
||||||
env["client"] = "unsupported";
|
|
||||||
break;
|
|
||||||
case Metadata::ModSide::UniversalSide:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fileOut["env"] = env;
|
fileOut["env"] = env;
|
||||||
|
|
||||||
fileOut["path"] = path;
|
fileOut["path"] = path;
|
||||||
|
@ -105,6 +105,8 @@ void Modrinth::loadExtraPackData(ModPlatform::IndexedPack& pack, QJsonObject& ob
|
|||||||
pack.extraData.donate.append(donate);
|
pack.extraData.donate.append(donate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pack.extraData.status = Json::ensureString(obj, "status");
|
||||||
|
|
||||||
pack.extraData.body = Json::ensureString(obj, "body").remove("<br>");
|
pack.extraData.body = Json::ensureString(obj, "body").remove("<br>");
|
||||||
|
|
||||||
pack.extraDataLoaded = true;
|
pack.extraDataLoaded = true;
|
||||||
|
@ -95,6 +95,8 @@ void loadIndexedInfo(Modpack& pack, QJsonObject& obj)
|
|||||||
pack.extra.donate.append(donate);
|
pack.extra.donate.append(donate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pack.extra.status = Json::ensureString(obj, "status");
|
||||||
|
|
||||||
pack.extraInfoLoaded = true;
|
pack.extraInfoLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +77,8 @@ struct ModpackExtra {
|
|||||||
QString discordUrl;
|
QString discordUrl;
|
||||||
|
|
||||||
QList<DonationData> donate;
|
QList<DonationData> donate;
|
||||||
|
|
||||||
|
QString status;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ModpackVersion {
|
struct ModpackVersion {
|
||||||
|
@ -62,7 +62,7 @@ void Technic::SingleZipPackInstallTask::downloadSucceeded()
|
|||||||
m_abortable = false;
|
m_abortable = false;
|
||||||
|
|
||||||
setStatus(tr("Extracting modpack"));
|
setStatus(tr("Extracting modpack"));
|
||||||
QDir extractDir(FS::PathCombine(m_stagingPath, ".minecraft"));
|
QDir extractDir(FS::PathCombine(m_stagingPath, "minecraft"));
|
||||||
qDebug() << "Attempting to create instance from" << m_archivePath;
|
qDebug() << "Attempting to create instance from" << m_archivePath;
|
||||||
|
|
||||||
// open the zip and find relevant files in it
|
// open the zip and find relevant files in it
|
||||||
|
@ -140,7 +140,7 @@ void Technic::SolderPackInstallTask::downloadSucceeded()
|
|||||||
m_filesNetJob.reset();
|
m_filesNetJob.reset();
|
||||||
m_extractFuture = QtConcurrent::run([this]() {
|
m_extractFuture = QtConcurrent::run([this]() {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
QString extractDir = FS::PathCombine(m_stagingPath, ".minecraft");
|
QString extractDir = FS::PathCombine(m_stagingPath, "minecraft");
|
||||||
FS::ensureFolderPathExists(extractDir);
|
FS::ensureFolderPathExists(extractDir);
|
||||||
|
|
||||||
while (m_modCount > i) {
|
while (m_modCount > i) {
|
||||||
|
@ -33,7 +33,7 @@ void Technic::TechnicPackProcessor::run(SettingsObjectPtr globalSettings,
|
|||||||
const QString& minecraftVersion,
|
const QString& minecraftVersion,
|
||||||
[[maybe_unused]] const bool isSolder)
|
[[maybe_unused]] const bool isSolder)
|
||||||
{
|
{
|
||||||
QString minecraftPath = FS::PathCombine(stagingPath, ".minecraft");
|
QString minecraftPath = FS::PathCombine(stagingPath, "minecraft");
|
||||||
QString configPath = FS::PathCombine(stagingPath, "instance.cfg");
|
QString configPath = FS::PathCombine(stagingPath, "instance.cfg");
|
||||||
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
|
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
|
||||||
MinecraftInstance instance(globalSettings, instanceSettings, stagingPath);
|
MinecraftInstance instance(globalSettings, instanceSettings, stagingPath);
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
qt.*.debug=false
|
qt.*.debug=false
|
||||||
# don't log credentials by default
|
# don't log credentials by default
|
||||||
launcher.auth.credentials.debug=false
|
launcher.auth.credentials.debug=false
|
||||||
|
katabasis.*.debug=false
|
||||||
# remove the debug lines, other log levels still get through
|
# remove the debug lines, other log levels still get through
|
||||||
launcher.task.net.download.debug=false
|
launcher.task.net.download.debug=false
|
||||||
# enable or disable whole catageries
|
# enable or disable whole catageries
|
||||||
|
@ -1197,43 +1197,43 @@ void MainWindow::undoTrashInstance()
|
|||||||
|
|
||||||
void MainWindow::on_actionViewLauncherRootFolder_triggered()
|
void MainWindow::on_actionViewLauncherRootFolder_triggered()
|
||||||
{
|
{
|
||||||
DesktopServices::openDirectory(".");
|
DesktopServices::openPath(".");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionViewInstanceFolder_triggered()
|
void MainWindow::on_actionViewInstanceFolder_triggered()
|
||||||
{
|
{
|
||||||
QString str = APPLICATION->settings()->get("InstanceDir").toString();
|
QString str = APPLICATION->settings()->get("InstanceDir").toString();
|
||||||
DesktopServices::openDirectory(str);
|
DesktopServices::openPath(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionViewCentralModsFolder_triggered()
|
void MainWindow::on_actionViewCentralModsFolder_triggered()
|
||||||
{
|
{
|
||||||
DesktopServices::openDirectory(APPLICATION->settings()->get("CentralModsDir").toString(), true);
|
DesktopServices::openPath(APPLICATION->settings()->get("CentralModsDir").toString(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionViewIconThemeFolder_triggered()
|
void MainWindow::on_actionViewIconThemeFolder_triggered()
|
||||||
{
|
{
|
||||||
DesktopServices::openDirectory(APPLICATION->themeManager()->getIconThemesFolder().path(), true);
|
DesktopServices::openPath(APPLICATION->themeManager()->getIconThemesFolder().path(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionViewWidgetThemeFolder_triggered()
|
void MainWindow::on_actionViewWidgetThemeFolder_triggered()
|
||||||
{
|
{
|
||||||
DesktopServices::openDirectory(APPLICATION->themeManager()->getApplicationThemesFolder().path(), true);
|
DesktopServices::openPath(APPLICATION->themeManager()->getApplicationThemesFolder().path(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionViewCatPackFolder_triggered()
|
void MainWindow::on_actionViewCatPackFolder_triggered()
|
||||||
{
|
{
|
||||||
DesktopServices::openDirectory(APPLICATION->themeManager()->getCatPacksFolder().path(), true);
|
DesktopServices::openPath(APPLICATION->themeManager()->getCatPacksFolder().path(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionViewIconsFolder_triggered()
|
void MainWindow::on_actionViewIconsFolder_triggered()
|
||||||
{
|
{
|
||||||
DesktopServices::openDirectory(APPLICATION->icons()->getDirectory(), true);
|
DesktopServices::openPath(APPLICATION->icons()->getDirectory(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionViewLogsFolder_triggered()
|
void MainWindow::on_actionViewLogsFolder_triggered()
|
||||||
{
|
{
|
||||||
DesktopServices::openDirectory("logs", true);
|
DesktopServices::openPath("logs", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::refreshInstances()
|
void MainWindow::refreshInstances()
|
||||||
@ -1452,7 +1452,7 @@ void MainWindow::on_actionViewSelectedInstFolder_triggered()
|
|||||||
{
|
{
|
||||||
if (m_selectedInstance) {
|
if (m_selectedInstance) {
|
||||||
QString str = m_selectedInstance->instanceRoot();
|
QString str = m_selectedInstance->instanceRoot();
|
||||||
DesktopServices::openDirectory(QDir(str).absolutePath());
|
DesktopServices::openPath(QFileInfo(str));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,8 +174,7 @@ AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDia
|
|||||||
QString urlText("<html><head/><body><p><a href=\"%1\">%1</a></p></body></html>");
|
QString urlText("<html><head/><body><p><a href=\"%1\">%1</a></p></body></html>");
|
||||||
ui->urlLabel->setText(urlText.arg(BuildConfig.LAUNCHER_GIT));
|
ui->urlLabel->setText(urlText.arg(BuildConfig.LAUNCHER_GIT));
|
||||||
|
|
||||||
QString copyText("© 2022-2023 %1");
|
ui->copyLabel->setText(BuildConfig.LAUNCHER_COPYRIGHT);
|
||||||
ui->copyLabel->setText(copyText.arg(BuildConfig.LAUNCHER_COPYRIGHT));
|
|
||||||
|
|
||||||
connect(ui->closeButton, SIGNAL(clicked()), SLOT(close()));
|
connect(ui->closeButton, SIGNAL(clicked()), SLOT(close()));
|
||||||
|
|
||||||
|
@ -47,11 +47,18 @@ ExportPackDialog::ExportPackDialog(InstancePtr instance, QWidget* parent, ModPla
|
|||||||
|
|
||||||
if (m_provider == ModPlatform::ResourceProvider::MODRINTH) {
|
if (m_provider == ModPlatform::ResourceProvider::MODRINTH) {
|
||||||
setWindowTitle(tr("Export Modrinth Pack"));
|
setWindowTitle(tr("Export Modrinth Pack"));
|
||||||
ui->summary->setText(instance->settings()->get("ExportSummary").toString());
|
|
||||||
|
ui->authorLabel->hide();
|
||||||
|
ui->author->hide();
|
||||||
|
|
||||||
|
ui->summary->setPlainText(instance->settings()->get("ExportSummary").toString());
|
||||||
} else {
|
} else {
|
||||||
setWindowTitle(tr("Export CurseForge Pack"));
|
setWindowTitle(tr("Export CurseForge Pack"));
|
||||||
ui->summaryLabel->setText(tr("&Author"));
|
|
||||||
ui->summary->setText(instance->settings()->get("ExportAuthor").toString());
|
ui->summaryLabel->hide();
|
||||||
|
ui->summary->hide();
|
||||||
|
|
||||||
|
ui->author->setText(instance->settings()->get("ExportAuthor").toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure a valid pack is generated
|
// ensure a valid pack is generated
|
||||||
@ -108,9 +115,13 @@ void ExportPackDialog::done(int result)
|
|||||||
auto settings = instance->settings();
|
auto settings = instance->settings();
|
||||||
settings->set("ExportName", ui->name->text());
|
settings->set("ExportName", ui->name->text());
|
||||||
settings->set("ExportVersion", ui->version->text());
|
settings->set("ExportVersion", ui->version->text());
|
||||||
settings->set(m_provider == ModPlatform::ResourceProvider::FLAME ? "ExportAuthor" : "ExportSummary", ui->summary->text());
|
|
||||||
settings->set("ExportOptionalFiles", ui->optionalFiles->isChecked());
|
settings->set("ExportOptionalFiles", ui->optionalFiles->isChecked());
|
||||||
|
|
||||||
|
if (m_provider == ModPlatform::ResourceProvider::MODRINTH)
|
||||||
|
settings->set("ExportSummary", ui->summary->toPlainText());
|
||||||
|
else
|
||||||
|
settings->set("ExportAuthor", ui->author->text());
|
||||||
|
|
||||||
if (result == Accepted) {
|
if (result == Accepted) {
|
||||||
const QString name = ui->name->text().isEmpty() ? instance->name() : ui->name->text();
|
const QString name = ui->name->text().isEmpty() ? instance->name() : ui->name->text();
|
||||||
const QString filename = FS::RemoveInvalidFilenameChars(name);
|
const QString filename = FS::RemoveInvalidFilenameChars(name);
|
||||||
@ -134,10 +145,10 @@ void ExportPackDialog::done(int result)
|
|||||||
|
|
||||||
Task* task;
|
Task* task;
|
||||||
if (m_provider == ModPlatform::ResourceProvider::MODRINTH) {
|
if (m_provider == ModPlatform::ResourceProvider::MODRINTH) {
|
||||||
task = new ModrinthPackExportTask(name, ui->version->text(), ui->summary->text(), ui->optionalFiles->isChecked(), instance,
|
task = new ModrinthPackExportTask(name, ui->version->text(), ui->summary->toPlainText(), ui->optionalFiles->isChecked(),
|
||||||
output, std::bind(&FileIgnoreProxy::filterFile, proxy, std::placeholders::_1));
|
instance, output, std::bind(&FileIgnoreProxy::filterFile, proxy, std::placeholders::_1));
|
||||||
} else {
|
} else {
|
||||||
task = new FlamePackExportTask(name, ui->version->text(), ui->summary->text(), ui->optionalFiles->isChecked(), instance, output,
|
task = new FlamePackExportTask(name, ui->version->text(), ui->author->text(), ui->optionalFiles->isChecked(), instance, output,
|
||||||
std::bind(&FileIgnoreProxy::filterFile, proxy, std::placeholders::_1));
|
std::bind(&FileIgnoreProxy::filterFile, proxy, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>650</width>
|
<width>650</width>
|
||||||
<height>510</height>
|
<height>532</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeGripEnabled">
|
<property name="sizeGripEnabled">
|
||||||
@ -19,21 +19,8 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>&Description</string>
|
<string>&Description</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
<item row="3" column="0">
|
<item>
|
||||||
<widget class="QLabel" name="summaryLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>&Summary</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>summary</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="1">
|
|
||||||
<widget class="QLineEdit" name="summary"/>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="nameLabel">
|
<widget class="QLabel" name="nameLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Name</string>
|
<string>&Name</string>
|
||||||
@ -43,7 +30,10 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item>
|
||||||
|
<widget class="QLineEdit" name="name"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
<widget class="QLabel" name="versionLabel">
|
<widget class="QLabel" name="versionLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Version</string>
|
<string>&Version</string>
|
||||||
@ -53,16 +43,43 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item>
|
||||||
<widget class="QLineEdit" name="name"/>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QLineEdit" name="version">
|
<widget class="QLineEdit" name="version">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>1.0.0</string>
|
<string>1.0.0</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="summaryLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Summary</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>summary</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPlainTextEdit" name="summary">
|
||||||
|
<property name="tabChangesFocus">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="authorLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Author</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>author</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="author"/>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -124,6 +141,7 @@
|
|||||||
<tabstop>name</tabstop>
|
<tabstop>name</tabstop>
|
||||||
<tabstop>version</tabstop>
|
<tabstop>version</tabstop>
|
||||||
<tabstop>summary</tabstop>
|
<tabstop>summary</tabstop>
|
||||||
|
<tabstop>author</tabstop>
|
||||||
<tabstop>files</tabstop>
|
<tabstop>files</tabstop>
|
||||||
<tabstop>optionalFiles</tabstop>
|
<tabstop>optionalFiles</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
|
@ -159,5 +159,5 @@ IconPickerDialog::~IconPickerDialog()
|
|||||||
|
|
||||||
void IconPickerDialog::openFolder()
|
void IconPickerDialog::openFolder()
|
||||||
{
|
{
|
||||||
DesktopServices::openDirectory(APPLICATION->icons()->getDirectory(), true);
|
DesktopServices::openPath(APPLICATION->icons()->getDirectory(), true);
|
||||||
}
|
}
|
||||||
|
@ -443,6 +443,9 @@ void ModUpdateDialog::appendMod(CheckUpdateTask::UpdatableMod const& info, QStri
|
|||||||
reqItem->insertChildren(i++, { reqItem });
|
reqItem->insertChildren(i++, { reqItem });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui->toggleDepsButton->show();
|
||||||
|
m_deps << item_top;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto changelog_item = new QTreeWidgetItem(item_top);
|
auto changelog_item = new QTreeWidgetItem(item_top);
|
||||||
|
@ -13,6 +13,7 @@ ReviewMessageBox::ReviewMessageBox(QWidget* parent, [[maybe_unused]] QString con
|
|||||||
auto back_button = ui->buttonBox->button(QDialogButtonBox::Cancel);
|
auto back_button = ui->buttonBox->button(QDialogButtonBox::Cancel);
|
||||||
back_button->setText(tr("Back"));
|
back_button->setText(tr("Back"));
|
||||||
|
|
||||||
|
ui->toggleDepsButton->hide();
|
||||||
ui->modTreeWidget->header()->setSectionResizeMode(0, QHeaderView::Stretch);
|
ui->modTreeWidget->header()->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||||
ui->modTreeWidget->header()->setStretchLastSection(false);
|
ui->modTreeWidget->header()->setStretchLastSection(false);
|
||||||
ui->modTreeWidget->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
|
ui->modTreeWidget->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
|
||||||
@ -75,6 +76,8 @@ void ReviewMessageBox::appendResource(ResourceInformation&& info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
itemTop->insertChildren(childIndx++, { requiredByItem });
|
itemTop->insertChildren(childIndx++, { requiredByItem });
|
||||||
|
ui->toggleDepsButton->show();
|
||||||
|
m_deps << itemTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto versionTypeItem = new QTreeWidgetItem(itemTop);
|
auto versionTypeItem = new QTreeWidgetItem(itemTop);
|
||||||
@ -108,3 +111,10 @@ void ReviewMessageBox::retranslateUi(QString resources_name)
|
|||||||
ui->explainLabel->setText(tr("You're about to download the following %1:").arg(resources_name));
|
ui->explainLabel->setText(tr("You're about to download the following %1:").arg(resources_name));
|
||||||
ui->onlyCheckedLabel->setText(tr("Only %1 with a check will be downloaded!").arg(resources_name));
|
ui->onlyCheckedLabel->setText(tr("Only %1 with a check will be downloaded!").arg(resources_name));
|
||||||
}
|
}
|
||||||
|
void ReviewMessageBox::on_toggleDepsButton_clicked()
|
||||||
|
{
|
||||||
|
m_deps_checked = !m_deps_checked;
|
||||||
|
auto state = m_deps_checked ? Qt::Checked : Qt::Unchecked;
|
||||||
|
for (auto dep : m_deps)
|
||||||
|
dep->setCheckState(0, state);
|
||||||
|
};
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
#include <QTreeWidgetItem>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class ReviewMessageBox;
|
class ReviewMessageBox;
|
||||||
@ -28,8 +29,14 @@ class ReviewMessageBox : public QDialog {
|
|||||||
|
|
||||||
~ReviewMessageBox() override;
|
~ReviewMessageBox() override;
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void on_toggleDepsButton_clicked();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ReviewMessageBox(QWidget* parent, const QString& title, const QString& icon);
|
ReviewMessageBox(QWidget* parent, const QString& title, const QString& icon);
|
||||||
|
|
||||||
Ui::ReviewMessageBox* ui;
|
Ui::ReviewMessageBox* ui;
|
||||||
|
|
||||||
|
QList<QTreeWidgetItem*> m_deps;
|
||||||
|
bool m_deps_checked = true;
|
||||||
};
|
};
|
||||||
|
@ -44,15 +44,20 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="explainLabel">
|
<widget class="QLabel" name="explainLabel"/>
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0" rowspan="2">
|
<item row="5" column="0" rowspan="2">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="onlyCheckedLabel">
|
<widget class="QPushButton" name="toggleDepsButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Toggle Dependencies</string>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="onlyCheckedLabel"/>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="standardButtons">
|
<property name="standardButtons">
|
||||||
|
@ -458,6 +458,7 @@ void InstanceView::paintEvent([[maybe_unused]] QPaintEvent* event)
|
|||||||
QPainter painter(this->viewport());
|
QPainter painter(this->viewport());
|
||||||
|
|
||||||
if (m_catVisible) {
|
if (m_catVisible) {
|
||||||
|
painter.setOpacity(APPLICATION->settings()->get("CatOpacity").toFloat() / 100);
|
||||||
int widWidth = this->viewport()->width();
|
int widWidth = this->viewport()->width();
|
||||||
int widHeight = this->viewport()->height();
|
int widHeight = this->viewport()->height();
|
||||||
if (m_catPixmap.width() < widWidth)
|
if (m_catPixmap.width() < widWidth)
|
||||||
@ -468,6 +469,7 @@ void InstanceView::paintEvent([[maybe_unused]] QPaintEvent* event)
|
|||||||
QRect rectOfPixmap = pixmap.rect();
|
QRect rectOfPixmap = pixmap.rect();
|
||||||
rectOfPixmap.moveBottomRight(this->viewport()->rect().bottomRight());
|
rectOfPixmap.moveBottomRight(this->viewport()->rect().bottomRight());
|
||||||
painter.drawPixmap(rectOfPixmap.topLeft(), pixmap);
|
painter.drawPixmap(rectOfPixmap.topLeft(), pixmap);
|
||||||
|
painter.setOpacity(1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
@ -480,32 +482,42 @@ void InstanceView::paintEvent([[maybe_unused]] QPaintEvent* event)
|
|||||||
|
|
||||||
if (model()->rowCount() == 0) {
|
if (model()->rowCount() == 0) {
|
||||||
painter.save();
|
painter.save();
|
||||||
const QString line1 = tr("Welcome!");
|
QString emptyString = tr("Welcome!") + "\n" + tr("Click \"Add Instance\" to get started.");
|
||||||
const QString line2 = tr("Click \"Add Instance\" to get started.");
|
|
||||||
auto rect = this->viewport()->rect();
|
|
||||||
auto font = option.font;
|
|
||||||
font.setPointSize(37);
|
|
||||||
painter.setFont(font);
|
|
||||||
auto fm = painter.fontMetrics();
|
|
||||||
|
|
||||||
if (rect.height() <= (fm.height() * 5) || rect.width() <= fm.horizontalAdvance(line2)) {
|
// calculate the rect for the overlay
|
||||||
auto s = rect.height() / (5. * fm.height());
|
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||||
auto sx = rect.width() * 1. / fm.horizontalAdvance(line2);
|
QFont font("sans", 20);
|
||||||
if (s >= sx)
|
font.setBold(true);
|
||||||
s = sx;
|
|
||||||
auto ps = font.pointSize() * s;
|
QRect bounds = viewport()->geometry();
|
||||||
if (ps <= 0)
|
bounds.moveTop(0);
|
||||||
ps = 1;
|
auto innerBounds = bounds;
|
||||||
font.setPointSize(ps);
|
innerBounds.adjust(10, 10, -10, -10);
|
||||||
|
|
||||||
|
QColor background = QApplication::palette().color(QPalette::WindowText);
|
||||||
|
QColor foreground = QApplication::palette().color(QPalette::Base);
|
||||||
|
foreground.setAlpha(190);
|
||||||
painter.setFont(font);
|
painter.setFont(font);
|
||||||
fm = painter.fontMetrics();
|
auto fontMetrics = painter.fontMetrics();
|
||||||
|
auto textRect = fontMetrics.boundingRect(innerBounds, Qt::AlignHCenter | Qt::TextWordWrap, emptyString);
|
||||||
|
textRect.moveCenter(bounds.center());
|
||||||
|
|
||||||
|
auto wrapRect = textRect;
|
||||||
|
wrapRect.adjust(-10, -10, 10, 10);
|
||||||
|
|
||||||
|
// check if we are allowed to draw in our area
|
||||||
|
if (!event->rect().intersects(wrapRect)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// text
|
painter.setBrush(QBrush(background));
|
||||||
rect.setTop(rect.top() + fm.height() * 1.5);
|
painter.setPen(foreground);
|
||||||
painter.drawText(rect, Qt::AlignHCenter, line1);
|
painter.drawRoundedRect(wrapRect, 5.0, 5.0);
|
||||||
rect.setTop(rect.top() + fm.height());
|
|
||||||
painter.drawText(rect, Qt::AlignHCenter, line2);
|
painter.setPen(foreground);
|
||||||
|
painter.setFont(font);
|
||||||
|
painter.drawText(textRect, Qt::AlignHCenter | Qt::TextWordWrap, emptyString);
|
||||||
|
|
||||||
painter.restore();
|
painter.restore();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -221,6 +221,9 @@ void LauncherPage::applySettings()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cat
|
||||||
|
s->set("CatOpacity", ui->catOpacitySpinBox->value());
|
||||||
|
|
||||||
// Mods
|
// Mods
|
||||||
s->set("ModMetadataDisabled", ui->metadataDisableBtn->isChecked());
|
s->set("ModMetadataDisabled", ui->metadataDisableBtn->isChecked());
|
||||||
s->set("ModDependenciesDisabled", ui->dependenciesDisableBtn->isChecked());
|
s->set("ModDependenciesDisabled", ui->dependenciesDisableBtn->isChecked());
|
||||||
@ -276,6 +279,9 @@ void LauncherPage::loadSettings()
|
|||||||
ui->sortByNameBtn->setChecked(true);
|
ui->sortByNameBtn->setChecked(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cat
|
||||||
|
ui->catOpacitySpinBox->setValue(s->get("CatOpacity").toInt());
|
||||||
|
|
||||||
// Mods
|
// Mods
|
||||||
ui->metadataDisableBtn->setChecked(s->get("ModMetadataDisabled").toBool());
|
ui->metadataDisableBtn->setChecked(s->get("ModMetadataDisabled").toBool());
|
||||||
ui->metadataWarningLabel->setHidden(!ui->metadataDisableBtn->isChecked());
|
ui->metadataWarningLabel->setHidden(!ui->metadataDisableBtn->isChecked());
|
||||||
|
@ -300,6 +300,54 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="catBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Cat</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_5">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="catOpacityLabel">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Set the cat's opacity. 0% is fully transparent and 100% is fully opaque.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Opacity</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QSpinBox" name="catOpacitySpinBox">
|
||||||
|
<property name="specialValueText">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="suffix">
|
||||||
|
<string>%</string>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="toolsBox">
|
<widget class="QGroupBox" name="toolsBox">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
@ -109,6 +109,7 @@ void MinecraftPage::applySettings()
|
|||||||
s->set("EnableFeralGamemode", ui->enableFeralGamemodeCheck->isChecked());
|
s->set("EnableFeralGamemode", ui->enableFeralGamemodeCheck->isChecked());
|
||||||
s->set("EnableMangoHud", ui->enableMangoHud->isChecked());
|
s->set("EnableMangoHud", ui->enableMangoHud->isChecked());
|
||||||
s->set("UseDiscreteGpu", ui->useDiscreteGpuCheck->isChecked());
|
s->set("UseDiscreteGpu", ui->useDiscreteGpuCheck->isChecked());
|
||||||
|
s->set("UseZink", ui->useZink->isChecked());
|
||||||
|
|
||||||
// Game time
|
// Game time
|
||||||
s->set("ShowGameTime", ui->showGameTime->isChecked());
|
s->set("ShowGameTime", ui->showGameTime->isChecked());
|
||||||
@ -151,6 +152,7 @@ void MinecraftPage::loadSettings()
|
|||||||
ui->enableFeralGamemodeCheck->setChecked(s->get("EnableFeralGamemode").toBool());
|
ui->enableFeralGamemodeCheck->setChecked(s->get("EnableFeralGamemode").toBool());
|
||||||
ui->enableMangoHud->setChecked(s->get("EnableMangoHud").toBool());
|
ui->enableMangoHud->setChecked(s->get("EnableMangoHud").toBool());
|
||||||
ui->useDiscreteGpuCheck->setChecked(s->get("UseDiscreteGpu").toBool());
|
ui->useDiscreteGpuCheck->setChecked(s->get("UseDiscreteGpu").toBool());
|
||||||
|
ui->useZink->setChecked(s->get("UseZink").toBool());
|
||||||
|
|
||||||
#if !defined(Q_OS_LINUX)
|
#if !defined(Q_OS_LINUX)
|
||||||
ui->perfomanceGroupBox->setVisible(false);
|
ui->perfomanceGroupBox->setVisible(false);
|
||||||
|
@ -206,7 +206,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="onlineFixes">
|
<widget class="QCheckBox" name="onlineFixes">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p>Emulates usages of old online services which are no longer operating.</p><p>This currently allows modern skins to be used.</p></body></html></string>
|
<string><html><head/><body><p>Emulates usages of old online services which are no longer operating.</p><p>Current fixes include: skin and online mode support.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Enable online fixes (experimental)</string>
|
<string>Enable online fixes (experimental)</string>
|
||||||
@ -309,6 +309,16 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="useZink">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Use Zink, a Mesa OpenGL driver that implements OpenGL on top of Vulkan. Performance may vary depending on the situation. Note: If no suitable Vulkan driver is found, software rendering will be used.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Use Zink</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -290,12 +290,12 @@ void ExternalResourcesPage::disableItem()
|
|||||||
|
|
||||||
void ExternalResourcesPage::viewConfigs()
|
void ExternalResourcesPage::viewConfigs()
|
||||||
{
|
{
|
||||||
DesktopServices::openDirectory(m_instance->instanceConfigFolder(), true);
|
DesktopServices::openPath(m_instance->instanceConfigFolder(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExternalResourcesPage::viewFolder()
|
void ExternalResourcesPage::viewFolder()
|
||||||
{
|
{
|
||||||
DesktopServices::openDirectory(m_model->dir().absolutePath(), true);
|
DesktopServices::openPath(m_model->dir().absolutePath(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExternalResourcesPage::current(const QModelIndex& current, const QModelIndex& previous)
|
bool ExternalResourcesPage::current(const QModelIndex& current, const QModelIndex& previous)
|
||||||
|
@ -232,10 +232,13 @@ void InstanceSettingsPage::applySettings()
|
|||||||
m_settings->set("EnableFeralGamemode", ui->enableFeralGamemodeCheck->isChecked());
|
m_settings->set("EnableFeralGamemode", ui->enableFeralGamemodeCheck->isChecked());
|
||||||
m_settings->set("EnableMangoHud", ui->enableMangoHud->isChecked());
|
m_settings->set("EnableMangoHud", ui->enableMangoHud->isChecked());
|
||||||
m_settings->set("UseDiscreteGpu", ui->useDiscreteGpuCheck->isChecked());
|
m_settings->set("UseDiscreteGpu", ui->useDiscreteGpuCheck->isChecked());
|
||||||
|
m_settings->set("UseZink", ui->useZink->isChecked());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
m_settings->reset("EnableFeralGamemode");
|
m_settings->reset("EnableFeralGamemode");
|
||||||
m_settings->reset("EnableMangoHud");
|
m_settings->reset("EnableMangoHud");
|
||||||
m_settings->reset("UseDiscreteGpu");
|
m_settings->reset("UseDiscreteGpu");
|
||||||
|
m_settings->reset("UseZink");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Game time
|
// Game time
|
||||||
@ -346,7 +349,7 @@ void InstanceSettingsPage::loadSettings()
|
|||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
ui->lineEditOpenALPath->setPlaceholderText(APPLICATION->m_detectedOpenALPath);
|
ui->lineEditOpenALPath->setPlaceholderText(APPLICATION->m_detectedOpenALPath);
|
||||||
#else
|
#else
|
||||||
ui->lineEditGLFWPath->setPlaceholderText(tr("Path to %1 library file").arg(BuildConfig.OPENAL_LIBRARY_NAME));
|
ui->lineEditOpenALPath->setPlaceholderText(tr("Path to %1 library file").arg(BuildConfig.OPENAL_LIBRARY_NAME));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Performance
|
// Performance
|
||||||
@ -354,6 +357,7 @@ void InstanceSettingsPage::loadSettings()
|
|||||||
ui->enableFeralGamemodeCheck->setChecked(m_settings->get("EnableFeralGamemode").toBool());
|
ui->enableFeralGamemodeCheck->setChecked(m_settings->get("EnableFeralGamemode").toBool());
|
||||||
ui->enableMangoHud->setChecked(m_settings->get("EnableMangoHud").toBool());
|
ui->enableMangoHud->setChecked(m_settings->get("EnableMangoHud").toBool());
|
||||||
ui->useDiscreteGpuCheck->setChecked(m_settings->get("UseDiscreteGpu").toBool());
|
ui->useDiscreteGpuCheck->setChecked(m_settings->get("UseDiscreteGpu").toBool());
|
||||||
|
ui->useZink->setChecked(m_settings->get("UseZink").toBool());
|
||||||
|
|
||||||
#if !defined(Q_OS_LINUX)
|
#if !defined(Q_OS_LINUX)
|
||||||
ui->settingsTabs->setTabVisible(ui->settingsTabs->indexOf(ui->performancePage), false);
|
ui->settingsTabs->setTabVisible(ui->settingsTabs->indexOf(ui->performancePage), false);
|
||||||
|
@ -567,6 +567,16 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="useZink">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Use Zink, a Mesa OpenGL driver that implements OpenGL on top of Vulkan. Performance may vary depending on the situation. Note: If no suitable Vulkan driver is found, software rendering will be used.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Use Zink</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -605,7 +615,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="onlineFixes">
|
<widget class="QCheckBox" name="onlineFixes">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p>Emulates usages of old online services which are no longer operating.</p><p>This currently allows modern skins to be used.</p></body></html></string>
|
<string><html><head/><body><p>Emulates usages of old online services which are no longer operating.</p><p>Current fixes include: skin and online mode support.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Enable online fixes (experimental)</string>
|
<string>Enable online fixes (experimental)</string>
|
||||||
|
@ -242,7 +242,7 @@ void ModFolderPage::updateMods(bool includeDeps)
|
|||||||
if (m_instance != nullptr && m_instance->isRunning()) {
|
if (m_instance != nullptr && m_instance->isRunning()) {
|
||||||
auto response =
|
auto response =
|
||||||
CustomMessageBox::selectable(this, tr("Confirm Update"),
|
CustomMessageBox::selectable(this, tr("Confirm Update"),
|
||||||
tr("If you update mods while the game is running may cause mod duplication and game crashes.\n"
|
tr("Updating mods while the game is running may cause mod duplication and game crashes.\n"
|
||||||
"The old files may not be deleted as they are in use.\n"
|
"The old files may not be deleted as they are in use.\n"
|
||||||
"Are you sure you want to do this?"),
|
"Are you sure you want to do this?"),
|
||||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
||||||
|
@ -324,8 +324,7 @@ void ScreenshotsPage::onItemActivated(QModelIndex index)
|
|||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return;
|
return;
|
||||||
auto info = m_model->fileInfo(index);
|
auto info = m_model->fileInfo(index);
|
||||||
QString fileName = info.absoluteFilePath();
|
DesktopServices::openPath(info);
|
||||||
DesktopServices::openFile(info.absoluteFilePath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenshotsPage::onCurrentSelectionChanged(const QItemSelection& selected)
|
void ScreenshotsPage::onCurrentSelectionChanged(const QItemSelection& selected)
|
||||||
@ -352,7 +351,7 @@ void ScreenshotsPage::onCurrentSelectionChanged(const QItemSelection& selected)
|
|||||||
|
|
||||||
void ScreenshotsPage::on_actionView_Folder_triggered()
|
void ScreenshotsPage::on_actionView_Folder_triggered()
|
||||||
{
|
{
|
||||||
DesktopServices::openDirectory(m_folder, true);
|
DesktopServices::openPath(m_folder, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenshotsPage::on_actionUpload_triggered()
|
void ScreenshotsPage::on_actionUpload_triggered()
|
||||||
|
@ -447,12 +447,12 @@ void VersionPage::on_actionAdd_Empty_triggered()
|
|||||||
|
|
||||||
void VersionPage::on_actionLibrariesFolder_triggered()
|
void VersionPage::on_actionLibrariesFolder_triggered()
|
||||||
{
|
{
|
||||||
DesktopServices::openDirectory(m_inst->getLocalLibraryPath(), true);
|
DesktopServices::openPath(m_inst->getLocalLibraryPath(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionPage::on_actionMinecraftFolder_triggered()
|
void VersionPage::on_actionMinecraftFolder_triggered()
|
||||||
{
|
{
|
||||||
DesktopServices::openDirectory(m_inst->gameRoot(), true);
|
DesktopServices::openPath(m_inst->gameRoot(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionPage::versionCurrent(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous)
|
void VersionPage::versionCurrent(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous)
|
||||||
|
@ -207,7 +207,7 @@ void WorldListPage::on_actionRemove_triggered()
|
|||||||
|
|
||||||
void WorldListPage::on_actionView_Folder_triggered()
|
void WorldListPage::on_actionView_Folder_triggered()
|
||||||
{
|
{
|
||||||
DesktopServices::openDirectory(m_worlds->dir().absolutePath(), true);
|
DesktopServices::openPath(m_worlds->dir().absolutePath(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldListPage::on_actionDatapacks_triggered()
|
void WorldListPage::on_actionDatapacks_triggered()
|
||||||
@ -223,7 +223,7 @@ void WorldListPage::on_actionDatapacks_triggered()
|
|||||||
|
|
||||||
auto fullPath = m_worlds->data(index, WorldList::FolderRole).toString();
|
auto fullPath = m_worlds->data(index, WorldList::FolderRole).toString();
|
||||||
|
|
||||||
DesktopServices::openDirectory(FS::PathCombine(fullPath, "datapacks"), true);
|
DesktopServices::openPath(FS::PathCombine(fullPath, "datapacks"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldListPage::on_actionReset_Icon_triggered()
|
void WorldListPage::on_actionReset_Icon_triggered()
|
||||||
|
@ -200,7 +200,9 @@ void ImportPage::setExtraInfo(const QMap<QString, QString>& extra_info)
|
|||||||
|
|
||||||
void ImportPage::on_modpackBtn_clicked()
|
void ImportPage::on_modpackBtn_clicked()
|
||||||
{
|
{
|
||||||
auto filter = QMimeDatabase().mimeTypeForName("application/zip").filterString();
|
const QMimeType zip = QMimeDatabase().mimeTypeForName("application/zip");
|
||||||
|
auto filter = tr("Supported files") + QString(" (%1 *.mrpack)").arg(zip.globPatterns().join(" "));
|
||||||
|
filter += ";;" + zip.filterString();
|
||||||
//: Option for filtering for *.mrpack files when importing
|
//: Option for filtering for *.mrpack files when importing
|
||||||
filter += ";;" + tr("Modrinth pack") + " (*.mrpack)";
|
filter += ";;" + tr("Modrinth pack") + " (*.mrpack)";
|
||||||
const QUrl url = QFileDialog::getOpenFileUrl(this, tr("Choose modpack"), modpackUrl(), filter);
|
const QUrl url = QFileDialog::getOpenFileUrl(this, tr("Choose modpack"), modpackUrl(), filter);
|
||||||
|
@ -209,7 +209,8 @@ void ResourceModel::loadEntry(QModelIndex& entry)
|
|||||||
};
|
};
|
||||||
if (!callbacks.on_fail)
|
if (!callbacks.on_fail)
|
||||||
callbacks.on_fail = [](QString reason, int) {
|
callbacks.on_fail = [](QString reason, int) {
|
||||||
QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load project versions:%1").arg(reason));
|
QMessageBox::critical(nullptr, tr("Error"),
|
||||||
|
tr("A network error occurred. Could not load project versions: %1").arg(reason));
|
||||||
};
|
};
|
||||||
|
|
||||||
if (auto job = m_api->getProjectVersions(std::move(args), std::move(callbacks)); job)
|
if (auto job = m_api->getProjectVersions(std::move(args), std::move(callbacks)); job)
|
||||||
@ -238,7 +239,7 @@ void ResourceModel::loadEntry(QModelIndex& entry)
|
|||||||
callbacks.on_abort = [this] {
|
callbacks.on_abort = [this] {
|
||||||
if (!s_running_models.constFind(this).value())
|
if (!s_running_models.constFind(this).value())
|
||||||
return;
|
return;
|
||||||
qCritical() << tr("The request was abborted for an unknown reason");
|
qCritical() << tr("The request was aborted for an unknown reason");
|
||||||
};
|
};
|
||||||
|
|
||||||
if (auto job = m_api->getProjectInfo(std::move(args), std::move(callbacks)); job)
|
if (auto job = m_api->getProjectInfo(std::move(args), std::move(callbacks)); job)
|
||||||
|
@ -201,6 +201,11 @@ void ResourcePage::updateUi()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (current_pack->extraDataLoaded) {
|
if (current_pack->extraDataLoaded) {
|
||||||
|
if (current_pack->extraData.status == "archived") {
|
||||||
|
text += "<br><br>" + tr("<b>This project has been archived. It will not receive any further updates unless the author decides "
|
||||||
|
"to unarchive the project.</b>");
|
||||||
|
}
|
||||||
|
|
||||||
if (!current_pack->extraData.donate.isEmpty()) {
|
if (!current_pack->extraData.donate.isEmpty()) {
|
||||||
text += "<br><br>" + tr("Donate information: ");
|
text += "<br><br>" + tr("Donate information: ");
|
||||||
auto donateToStr = [](ModPlatform::DonationData& donate) -> QString {
|
auto donateToStr = [](ModPlatform::DonationData& donate) -> QString {
|
||||||
@ -405,9 +410,9 @@ void ResourcePage::openUrl(const QUrl& url)
|
|||||||
auto jump = [url, slug, model, view] {
|
auto jump = [url, slug, model, view] {
|
||||||
for (int row = 0; row < model->rowCount({}); row++) {
|
for (int row = 0; row < model->rowCount({}); row++) {
|
||||||
const QModelIndex index = model->index(row);
|
const QModelIndex index = model->index(row);
|
||||||
const auto pack = model->data(index, Qt::UserRole).value<ModPlatform::IndexedPack>();
|
const auto pack = model->data(index, Qt::UserRole).value<ModPlatform::IndexedPack::Ptr>();
|
||||||
|
|
||||||
if (pack.slug == slug) {
|
if (pack->slug == slug) {
|
||||||
view->setCurrentIndex(index);
|
view->setCurrentIndex(index);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "ui/widgets/ProjectItem.h"
|
#include "ui/widgets/ProjectItem.h"
|
||||||
#include "ui_ImportFTBPage.h"
|
#include "ui_ImportFTBPage.h"
|
||||||
|
|
||||||
|
#include <QFileDialog>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "ListModel.h"
|
#include "ListModel.h"
|
||||||
@ -56,6 +57,13 @@ ImportFTBPage::ImportFTBPage(NewInstanceDialog* dialog, QWidget* parent) : QWidg
|
|||||||
|
|
||||||
connect(ui->searchEdit, &QLineEdit::textChanged, this, &ImportFTBPage::triggerSearch);
|
connect(ui->searchEdit, &QLineEdit::textChanged, this, &ImportFTBPage::triggerSearch);
|
||||||
|
|
||||||
|
connect(ui->browseButton, &QPushButton::clicked, this, [this] {
|
||||||
|
auto path = listModel->getPath();
|
||||||
|
QString dir = QFileDialog::getExistingDirectory(this, tr("Select FTBApp instances directory"), path, QFileDialog::ShowDirsOnly);
|
||||||
|
if (!dir.isEmpty())
|
||||||
|
listModel->setPath(dir);
|
||||||
|
});
|
||||||
|
|
||||||
ui->modpackList->setItemDelegate(new ProjectItemDelegate(this));
|
ui->modpackList->setItemDelegate(new ProjectItemDelegate(this));
|
||||||
ui->modpackList->selectionModel()->reset();
|
ui->modpackList->selectionModel()->reset();
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="1" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QTreeView" name="modpackList">
|
<widget class="QTreeView" name="modpackList">
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
<size>
|
<size>
|
||||||
@ -21,28 +21,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="3" column="1">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="searchEdit">
|
|
||||||
<property name="placeholderText">
|
|
||||||
<string>Search and filter...</string>
|
|
||||||
</property>
|
|
||||||
<property name="clearButtonEnabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="pushButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Search</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="sortByBox">
|
<widget class="QComboBox" name="sortByBox">
|
||||||
@ -69,6 +48,54 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="searchEdit">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Search and filter...</string>
|
||||||
|
</property>
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Search</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="browseButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Select FTBApp instances directory</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="viewfolder">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Note: If your FTB instances are not in the default location, select it using the button next to search.</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
@ -17,11 +17,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ListModel.h"
|
#include "ListModel.h"
|
||||||
|
#include <qfileinfo.h>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QProcessEnvironment>
|
#include <QProcessEnvironment>
|
||||||
|
#include "Application.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
#include "modplatform/import_ftb/PackHelpers.h"
|
#include "modplatform/import_ftb/PackHelpers.h"
|
||||||
@ -29,7 +31,7 @@
|
|||||||
|
|
||||||
namespace FTBImportAPP {
|
namespace FTBImportAPP {
|
||||||
|
|
||||||
QString getPath()
|
QString getStaticPath()
|
||||||
{
|
{
|
||||||
QString partialPath;
|
QString partialPath;
|
||||||
#if defined(Q_OS_OSX)
|
#if defined(Q_OS_OSX)
|
||||||
@ -42,14 +44,14 @@ QString getPath()
|
|||||||
return FS::PathCombine(partialPath, ".ftba");
|
return FS::PathCombine(partialPath, ".ftba");
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString ListModel::FTB_APP_PATH = getPath();
|
static const QString FTB_APP_PATH = FS::PathCombine(getStaticPath(), "instances");
|
||||||
|
|
||||||
void ListModel::update()
|
void ListModel::update()
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
modpacks.clear();
|
modpacks.clear();
|
||||||
|
|
||||||
QString instancesPath = FS::PathCombine(FTB_APP_PATH, "instances");
|
QString instancesPath = getPath();
|
||||||
if (auto instancesInfo = QFileInfo(instancesPath); instancesInfo.exists() && instancesInfo.isDir()) {
|
if (auto instancesInfo = QFileInfo(instancesPath); instancesInfo.exists() && instancesInfo.isDir()) {
|
||||||
QDirIterator directoryIterator(instancesPath, QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable | QDir::Hidden,
|
QDirIterator directoryIterator(instancesPath, QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable | QDir::Hidden,
|
||||||
QDirIterator::FollowSymlinks);
|
QDirIterator::FollowSymlinks);
|
||||||
@ -168,4 +170,17 @@ FilterModel::Sorting FilterModel::getCurrentSorting()
|
|||||||
{
|
{
|
||||||
return currentSorting;
|
return currentSorting;
|
||||||
}
|
}
|
||||||
|
void ListModel::setPath(QString path)
|
||||||
|
{
|
||||||
|
APPLICATION->settings()->set("FTBAppInstancesPath", path);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ListModel::getPath()
|
||||||
|
{
|
||||||
|
auto path = APPLICATION->settings()->get("FTBAppInstancesPath").toString();
|
||||||
|
if (path.isEmpty() || !QFileInfo(path).exists())
|
||||||
|
path = FTB_APP_PATH;
|
||||||
|
return path;
|
||||||
|
}
|
||||||
} // namespace FTBImportAPP
|
} // namespace FTBImportAPP
|
@ -60,7 +60,8 @@ class ListModel : public QAbstractListModel {
|
|||||||
|
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
static const QString FTB_APP_PATH;
|
QString getPath();
|
||||||
|
void setPath(QString path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ModpackList modpacks;
|
ModpackList modpacks;
|
||||||
|
@ -142,7 +142,7 @@ void ModpackListModel::performPaginatedSearch()
|
|||||||
callbacks.on_succeed = [this](auto& doc, auto& pack) { searchRequestForOneSucceeded(doc); };
|
callbacks.on_succeed = [this](auto& doc, auto& pack) { searchRequestForOneSucceeded(doc); };
|
||||||
callbacks.on_abort = [this] {
|
callbacks.on_abort = [this] {
|
||||||
qCritical() << "Search task aborted by an unknown reason!";
|
qCritical() << "Search task aborted by an unknown reason!";
|
||||||
searchRequestFailed("Abborted");
|
searchRequestFailed("Aborted");
|
||||||
};
|
};
|
||||||
static const ModrinthAPI api;
|
static const ModrinthAPI api;
|
||||||
if (auto job = api.getProjectInfo({ projectId }, std::move(callbacks)); job) {
|
if (auto job = api.getProjectInfo({ projectId }, std::move(callbacks)); job) {
|
||||||
|
@ -267,6 +267,11 @@ void ModrinthPage::updateUI()
|
|||||||
text += "<br>" + tr(" by ") + QString("<a href=%1>%2</a>").arg(std::get<1>(current.author).toString(), std::get<0>(current.author));
|
text += "<br>" + tr(" by ") + QString("<a href=%1>%2</a>").arg(std::get<1>(current.author).toString(), std::get<0>(current.author));
|
||||||
|
|
||||||
if (current.extraInfoLoaded) {
|
if (current.extraInfoLoaded) {
|
||||||
|
if (current.extra.status == "archived") {
|
||||||
|
text += "<br><br>" + tr("<b>This project has been archived. It will not receive any further updates unless the author decides "
|
||||||
|
"to unarchive the project.</b>");
|
||||||
|
}
|
||||||
|
|
||||||
if (!current.extra.donate.isEmpty()) {
|
if (!current.extra.donate.isEmpty()) {
|
||||||
text += "<br><br>" + tr("Donate information: ");
|
text += "<br><br>" + tr("Donate information: ");
|
||||||
auto donateToStr = [](Modrinth::DonationData& donate) -> QString {
|
auto donateToStr = [](Modrinth::DonationData& donate) -> QString {
|
||||||
|
@ -11,43 +11,7 @@
|
|||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="0" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<italic>true</italic>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Note: Modrinth modpacks are still in alpha phase. Some things may be rough on the edges, or not working at all! Use it with caution.</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignCenter</set>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<layout class="QHBoxLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="searchEdit">
|
|
||||||
<property name="placeholderText">
|
|
||||||
<string>Search and filter ...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="searchButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Search</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QListView" name="packView">
|
<widget class="QListView" name="packView">
|
||||||
@ -77,7 +41,7 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="3" column="0">
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="sortByBox"/>
|
<widget class="QComboBox" name="sortByBox"/>
|
||||||
@ -97,6 +61,24 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<layout class="QHBoxLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="searchEdit">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Search and filter ...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="searchButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Search</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "LogView.h"
|
#include "LogView.h"
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include <QTextBlock>
|
#include <QTextBlock>
|
||||||
|
#include <QTextDocumentFragment>
|
||||||
|
|
||||||
LogView::LogView(QWidget* parent) : QPlainTextEdit(parent)
|
LogView::LogView(QWidget* parent) : QPlainTextEdit(parent)
|
||||||
{
|
{
|
||||||
@ -117,6 +118,9 @@ void LogView::rowsAboutToBeInserted(const QModelIndex& parent, int first, int la
|
|||||||
|
|
||||||
void LogView::rowsInserted(const QModelIndex& parent, int first, int last)
|
void LogView::rowsInserted(const QModelIndex& parent, int first, int last)
|
||||||
{
|
{
|
||||||
|
QTextDocument document;
|
||||||
|
QTextCursor cursor(&document);
|
||||||
|
|
||||||
for (int i = first; i <= last; i++) {
|
for (int i = first; i <= last; i++) {
|
||||||
auto idx = m_model->index(i, 0, parent);
|
auto idx = m_model->index(i, 0, parent);
|
||||||
auto text = m_model->data(idx, Qt::DisplayRole).toString();
|
auto text = m_model->data(idx, Qt::DisplayRole).toString();
|
||||||
@ -133,11 +137,16 @@ void LogView::rowsInserted(const QModelIndex& parent, int first, int last)
|
|||||||
if (bg.isValid()) {
|
if (bg.isValid()) {
|
||||||
format.setBackground(bg.value<QColor>());
|
format.setBackground(bg.value<QColor>());
|
||||||
}
|
}
|
||||||
auto workCursor = textCursor();
|
cursor.movePosition(QTextCursor::End);
|
||||||
workCursor.movePosition(QTextCursor::End);
|
cursor.insertText(text, format);
|
||||||
workCursor.insertText(text, format);
|
cursor.insertBlock();
|
||||||
workCursor.insertBlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QTextDocumentFragment fragment(&document);
|
||||||
|
QTextCursor workCursor = textCursor();
|
||||||
|
workCursor.movePosition(QTextCursor::End);
|
||||||
|
workCursor.insertFragment(fragment);
|
||||||
|
|
||||||
if (m_scroll && !m_scrolling) {
|
if (m_scroll && !m_scrolling) {
|
||||||
m_scrolling = true;
|
m_scrolling = true;
|
||||||
QMetaObject::invokeMethod(this, "scrollToBottom", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "scrollToBottom", Qt::QueuedConnection);
|
||||||
|
@ -88,7 +88,7 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o
|
|||||||
}
|
}
|
||||||
|
|
||||||
{ // Description painting
|
{ // Description painting
|
||||||
auto description = index.data(UserDataTypes::DESCRIPTION).toString();
|
auto description = index.data(UserDataTypes::DESCRIPTION).toString().simplified();
|
||||||
|
|
||||||
QTextLayout text_layout(description, opt.font);
|
QTextLayout text_layout(description, opt.font);
|
||||||
|
|
||||||
|
@ -34,11 +34,11 @@ ThemeCustomizationWidget::ThemeCustomizationWidget(QWidget* parent) : QWidget(pa
|
|||||||
connect(ui->backgroundCatComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ThemeCustomizationWidget::applyCatTheme);
|
connect(ui->backgroundCatComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ThemeCustomizationWidget::applyCatTheme);
|
||||||
|
|
||||||
connect(ui->iconsFolder, &QPushButton::clicked, this,
|
connect(ui->iconsFolder, &QPushButton::clicked, this,
|
||||||
[] { DesktopServices::openDirectory(APPLICATION->themeManager()->getIconThemesFolder().path()); });
|
[] { DesktopServices::openPath(APPLICATION->themeManager()->getIconThemesFolder().path()); });
|
||||||
connect(ui->widgetStyleFolder, &QPushButton::clicked, this,
|
connect(ui->widgetStyleFolder, &QPushButton::clicked, this,
|
||||||
[] { DesktopServices::openDirectory(APPLICATION->themeManager()->getApplicationThemesFolder().path()); });
|
[] { DesktopServices::openPath(APPLICATION->themeManager()->getApplicationThemesFolder().path()); });
|
||||||
connect(ui->catPackFolder, &QPushButton::clicked, this,
|
connect(ui->catPackFolder, &QPushButton::clicked, this,
|
||||||
[] { DesktopServices::openDirectory(APPLICATION->themeManager()->getCatPacksFolder().path()); });
|
[] { DesktopServices::openPath(APPLICATION->themeManager()->getCatPacksFolder().path()); });
|
||||||
}
|
}
|
||||||
|
|
||||||
ThemeCustomizationWidget::~ThemeCustomizationWidget()
|
ThemeCustomizationWidget::~ThemeCustomizationWidget()
|
||||||
|
@ -436,8 +436,8 @@ PrismUpdaterApp::PrismUpdaterApp(int& argc, char** argv) : QApplication(argc, ar
|
|||||||
}
|
}
|
||||||
|
|
||||||
{ // log debug program info
|
{ // log debug program info
|
||||||
qDebug() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME) << "Updater"
|
qDebug() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME + " Updater, " +
|
||||||
<< ", (c) 2022-2023 " << qPrintable(QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", "));
|
QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", "));
|
||||||
qDebug() << "Version : " << BuildConfig.printableVersionString();
|
qDebug() << "Version : " << BuildConfig.printableVersionString();
|
||||||
qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT;
|
qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT;
|
||||||
qDebug() << "Git refspec : " << BuildConfig.GIT_REFSPEC;
|
qDebug() << "Git refspec : " << BuildConfig.GIT_REFSPEC;
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 5ba25ff40eba44c811f79ab6a792baf945b8307c
|
Subproject commit 8fbf029685482827828b5858444157052f1b0a5f
|
@ -1 +1 @@
|
|||||||
Subproject commit 8a2edd6d92ed820521d42c94d179462bf06b5ed3
|
Subproject commit 2fc4b463759e043476fc0036da094e5877e3dd50
|
@ -25,13 +25,14 @@ set(LEGACY_SRC
|
|||||||
legacy/org/prismlauncher/legacy/LegacyLauncher.java
|
legacy/org/prismlauncher/legacy/LegacyLauncher.java
|
||||||
legacy/org/prismlauncher/legacy/fix/online/Handler.java
|
legacy/org/prismlauncher/legacy/fix/online/Handler.java
|
||||||
legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java
|
legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java
|
||||||
|
legacy/org/prismlauncher/legacy/fix/online/OnlineModeFix.java
|
||||||
legacy/org/prismlauncher/legacy/fix/online/SkinFix.java
|
legacy/org/prismlauncher/legacy/fix/online/SkinFix.java
|
||||||
legacy/org/prismlauncher/legacy/utils/Base64.java
|
legacy/org/prismlauncher/legacy/utils/Base64.java
|
||||||
legacy/org/prismlauncher/legacy/utils/api/MojangApi.java
|
legacy/org/prismlauncher/legacy/utils/api/MojangApi.java
|
||||||
legacy/org/prismlauncher/legacy/utils/api/Texture.java
|
legacy/org/prismlauncher/legacy/utils/api/Texture.java
|
||||||
legacy/org/prismlauncher/legacy/utils/json/JsonParseException.java
|
legacy/org/prismlauncher/legacy/utils/json/JsonParseException.java
|
||||||
legacy/org/prismlauncher/legacy/utils/json/JsonParser.java
|
legacy/org/prismlauncher/legacy/utils/json/JsonParser.java
|
||||||
legacy/org/prismlauncher/legacy/utils/url/CustomUrlConnection.java
|
legacy/org/prismlauncher/legacy/utils/url/ByteArrayUrlConnection.java
|
||||||
legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java
|
legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java
|
||||||
legacy/net/minecraft/Launcher.java
|
legacy/net/minecraft/Launcher.java
|
||||||
legacy/org/prismlauncher/legacy/LegacyProxy.java
|
legacy/org/prismlauncher/legacy/LegacyProxy.java
|
||||||
|
@ -53,11 +53,16 @@ final class Handler extends URLStreamHandler {
|
|||||||
protected URLConnection openConnection(URL address, Proxy proxy) throws IOException {
|
protected URLConnection openConnection(URL address, Proxy proxy) throws IOException {
|
||||||
URLConnection result;
|
URLConnection result;
|
||||||
|
|
||||||
// try skin fix
|
// try various fixes...
|
||||||
result = SkinFix.openConnection(address, proxy);
|
result = SkinFix.openConnection(address, proxy);
|
||||||
if (result != null)
|
if (result != null)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
result = OnlineModeFix.openConnection(address, proxy);
|
||||||
|
if (result != null)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
// ...then give up and make the request directly
|
||||||
return UrlUtils.openConnection(address, proxy);
|
return UrlUtils.openConnection(address, proxy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,8 @@ import java.net.URLStreamHandlerFactory;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Fixes skins by redirecting to other URLs.
|
* Fixes skins by redirecting to other URLs.
|
||||||
|
* Thanks to MineOnline for the implementation from which this was inspired!
|
||||||
|
* See https://github.com/ahnewark/MineOnline/tree/main/src/main/java/gg/codie/mineonline/protocol.
|
||||||
*
|
*
|
||||||
* @see {@link Handler}
|
* @see {@link Handler}
|
||||||
* @see {@link UrlUtils}
|
* @see {@link UrlUtils}
|
||||||
|
@ -0,0 +1,66 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
|
||||||
|
*
|
||||||
|
* 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, version 3.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Linking this library statically or dynamically with other modules is
|
||||||
|
* making a combined work based on this library. Thus, the terms and
|
||||||
|
* conditions of the GNU General Public License cover the whole
|
||||||
|
* combination.
|
||||||
|
*
|
||||||
|
* As a special exception, the copyright holders of this library give
|
||||||
|
* you permission to link this library with independent modules to
|
||||||
|
* produce an executable, regardless of the license terms of these
|
||||||
|
* independent modules, and to copy and distribute the resulting
|
||||||
|
* executable under terms of your choice, provided that you also meet,
|
||||||
|
* for each linked independent module, the terms and conditions of the
|
||||||
|
* license of that module. An independent module is a module which is
|
||||||
|
* not derived from or based on this library. If you modify this
|
||||||
|
* library, you may extend this exception to your version of the
|
||||||
|
* library, but you are not obliged to do so. If you do not wish to do
|
||||||
|
* so, delete this exception statement from your version.
|
||||||
|
*
|
||||||
|
* 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.prismlauncher.legacy.fix.online;
|
||||||
|
|
||||||
|
import org.prismlauncher.legacy.utils.url.UrlUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.Proxy;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
|
||||||
|
public final class OnlineModeFix {
|
||||||
|
public static URLConnection openConnection(URL address, Proxy proxy) throws IOException {
|
||||||
|
// we start with "http://www.minecraft.net/game/joinserver.jsp?user=..."
|
||||||
|
if (!(address.getHost().equals("www.minecraft.net") && address.getPath().equals("/game/joinserver.jsp")))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// change it to "https://session.minecraft.net/game/joinserver.jsp?user=..."
|
||||||
|
// this seems to be the modern version of the same endpoint...
|
||||||
|
// maybe Mojang planned to patch old versions of the game to use it
|
||||||
|
// if it ever disappears this should be changed to use sessionserver.mojang.com/session/minecraft/join
|
||||||
|
// which of course has a different usage requiring JSON serialisation...
|
||||||
|
URL url;
|
||||||
|
try {
|
||||||
|
url = new URL("https", "session.minecraft.net", address.getPort(), address.getFile());
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
throw new AssertionError("url should be valid", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return UrlUtils.openConnection(url, proxy);
|
||||||
|
}
|
||||||
|
}
|
@ -54,7 +54,7 @@ package org.prismlauncher.legacy.fix.online;
|
|||||||
|
|
||||||
import org.prismlauncher.legacy.utils.api.MojangApi;
|
import org.prismlauncher.legacy.utils.api.MojangApi;
|
||||||
import org.prismlauncher.legacy.utils.api.Texture;
|
import org.prismlauncher.legacy.utils.api.Texture;
|
||||||
import org.prismlauncher.legacy.utils.url.CustomUrlConnection;
|
import org.prismlauncher.legacy.utils.url.ByteArrayUrlConnection;
|
||||||
import org.prismlauncher.legacy.utils.url.UrlUtils;
|
import org.prismlauncher.legacy.utils.url.UrlUtils;
|
||||||
|
|
||||||
import java.awt.AlphaComposite;
|
import java.awt.AlphaComposite;
|
||||||
@ -97,9 +97,9 @@ final class SkinFix {
|
|||||||
|
|
||||||
URLConnection connection = UrlUtils.openConnection(texture.getUrl(), proxy);
|
URLConnection connection = UrlUtils.openConnection(texture.getUrl(), proxy);
|
||||||
try (InputStream in = connection.getInputStream()) {
|
try (InputStream in = connection.getInputStream()) {
|
||||||
// thank you craftycodie!
|
// thank you ahnewark!
|
||||||
// this is heavily based on
|
// this is heavily based on
|
||||||
// https://github.com/craftycodie/MineOnline/blob/4f4f86f9d051e0a6fd7ff0b95b2a05f7437683d7/src/main/java/gg/codie/mineonline/gui/textures/TextureHelper.java#L17
|
// https://github.com/ahnewark/MineOnline/blob/4f4f86f9d051e0a6fd7ff0b95b2a05f7437683d7/src/main/java/gg/codie/mineonline/gui/textures/TextureHelper.java#L17
|
||||||
BufferedImage image = ImageIO.read(in);
|
BufferedImage image = ImageIO.read(in);
|
||||||
Graphics2D graphics = image.createGraphics();
|
Graphics2D graphics = image.createGraphics();
|
||||||
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
|
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
|
||||||
@ -131,7 +131,7 @@ final class SkinFix {
|
|||||||
image = image.getSubimage(0, 0, 64, 32);
|
image = image.getSubimage(0, 0, 64, 32);
|
||||||
ImageIO.write(image, "png", out);
|
ImageIO.write(image, "png", out);
|
||||||
|
|
||||||
return new CustomUrlConnection(out.toByteArray());
|
return new ByteArrayUrlConnection(out.toByteArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,16 +40,12 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
|
|
||||||
public final class CustomUrlConnection extends HttpURLConnection {
|
public final class ByteArrayUrlConnection extends HttpURLConnection {
|
||||||
private final InputStream in;
|
private final InputStream in;
|
||||||
|
|
||||||
public CustomUrlConnection(byte[] data) {
|
public ByteArrayUrlConnection(byte[] data) {
|
||||||
this(new ByteArrayInputStream(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
public CustomUrlConnection(InputStream in) {
|
|
||||||
super(null);
|
super(null);
|
||||||
this.in = in;
|
this.in = new ByteArrayInputStream(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -58,12 +54,7 @@ public final class CustomUrlConnection extends HttpURLConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void disconnect() {
|
public void disconnect() {}
|
||||||
try {
|
|
||||||
in.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputStream getInputStream() throws IOException {
|
public InputStream getInputStream() throws IOException {
|
@ -101,7 +101,7 @@ public final class UrlUtils {
|
|||||||
} catch (IOException | Error | RuntimeException e) {
|
} catch (IOException | Error | RuntimeException e) {
|
||||||
throw e; // rethrow if possible
|
throw e; // rethrow if possible
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw new AssertionError(e); // oh dear! this isn't meant to happen
|
throw new AssertionError("openConnection should not throw", e); // oh dear! this isn't meant to happen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,10 +81,9 @@ public final class EntryPoint {
|
|||||||
PreLaunchAction action = PreLaunchAction.PROCEED;
|
PreLaunchAction action = PreLaunchAction.PROCEED;
|
||||||
|
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8))) {
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8))) {
|
||||||
String line;
|
|
||||||
|
|
||||||
while (action == PreLaunchAction.PROCEED) {
|
while (action == PreLaunchAction.PROCEED) {
|
||||||
if ((line = reader.readLine()) != null)
|
String line = reader.readLine();
|
||||||
|
if (line != null)
|
||||||
action = parseLine(line, params);
|
action = parseLine(line, params);
|
||||||
else
|
else
|
||||||
action = PreLaunchAction.ABORT;
|
action = PreLaunchAction.ABORT;
|
||||||
@ -105,7 +104,7 @@ public final class EntryPoint {
|
|||||||
return ExitCode.ABORT;
|
return ExitCode.ABORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
setProperties(params);
|
SystemProperties.apply(params);
|
||||||
|
|
||||||
String launcherType = params.getString("launcher");
|
String launcherType = params.getString("launcher");
|
||||||
|
|
||||||
@ -141,43 +140,10 @@ public final class EntryPoint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setProperties(Parameters params) {
|
|
||||||
String launcherBrand = params.getString("launcherBrand", null);
|
|
||||||
String launcherVersion = params.getString("launcherVersion", null);
|
|
||||||
String name = params.getString("instanceName", null);
|
|
||||||
String iconId = params.getString("instanceIconKey", null);
|
|
||||||
String iconPath = params.getString("instanceIconPath", null);
|
|
||||||
String windowTitle = params.getString("windowTitle", null);
|
|
||||||
String windowDimensions = params.getString("windowParams", null);
|
|
||||||
|
|
||||||
if (launcherBrand != null)
|
|
||||||
System.setProperty("minecraft.launcher.brand", launcherBrand);
|
|
||||||
if (launcherVersion != null)
|
|
||||||
System.setProperty("minecraft.launcher.version", launcherVersion);
|
|
||||||
|
|
||||||
// set useful properties for mods
|
|
||||||
if (name != null)
|
|
||||||
System.setProperty("org.prismlauncher.instance.name", name);
|
|
||||||
if (iconId != null)
|
|
||||||
System.setProperty("org.prismlauncher.instance.icon.id", iconId);
|
|
||||||
if (iconPath != null)
|
|
||||||
System.setProperty("org.prismlauncher.instance.icon.path", iconPath);
|
|
||||||
if (windowTitle != null)
|
|
||||||
System.setProperty("org.prismlauncher.window.title", windowTitle);
|
|
||||||
if (windowDimensions != null)
|
|
||||||
System.setProperty("org.prismlauncher.window.dimensions", windowDimensions);
|
|
||||||
|
|
||||||
// set multimc properties for compatibility
|
|
||||||
if (name != null)
|
|
||||||
System.setProperty("multimc.instance.title", name);
|
|
||||||
if (iconId != null)
|
|
||||||
System.setProperty("multimc.instance.icon", iconId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PreLaunchAction parseLine(String input, Parameters params) throws ParseException {
|
private static PreLaunchAction parseLine(String input, Parameters params) throws ParseException {
|
||||||
switch (input) {
|
switch (input) {
|
||||||
case "":
|
case "":
|
||||||
break;
|
return PreLaunchAction.PROCEED;
|
||||||
|
|
||||||
case "launch":
|
case "launch":
|
||||||
return PreLaunchAction.LAUNCH;
|
return PreLaunchAction.LAUNCH;
|
||||||
@ -192,10 +158,10 @@ public final class EntryPoint {
|
|||||||
throw new ParseException(input, "[key] [value]");
|
throw new ParseException(input, "[key] [value]");
|
||||||
|
|
||||||
params.add(pair[0], pair[1]);
|
params.add(pair[0], pair[1]);
|
||||||
}
|
|
||||||
|
|
||||||
return PreLaunchAction.PROCEED;
|
return PreLaunchAction.PROCEED;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private enum PreLaunchAction { PROCEED, LAUNCH, ABORT }
|
private enum PreLaunchAction { PROCEED, LAUNCH, ABORT }
|
||||||
|
|
||||||
|
38
libraries/launcher/org/prismlauncher/SystemProperties.java
Normal file
38
libraries/launcher/org/prismlauncher/SystemProperties.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package org.prismlauncher;
|
||||||
|
|
||||||
|
import org.prismlauncher.utils.Parameters;
|
||||||
|
|
||||||
|
public final class SystemProperties {
|
||||||
|
public static void apply(Parameters params) {
|
||||||
|
String launcherBrand = params.getString("launcherBrand", null);
|
||||||
|
String launcherVersion = params.getString("launcherVersion", null);
|
||||||
|
String name = params.getString("instanceName", null);
|
||||||
|
String iconId = params.getString("instanceIconKey", null);
|
||||||
|
String iconPath = params.getString("instanceIconPath", null);
|
||||||
|
String windowTitle = params.getString("windowTitle", null);
|
||||||
|
String windowDimensions = params.getString("windowParams", null);
|
||||||
|
|
||||||
|
if (launcherBrand != null)
|
||||||
|
System.setProperty("minecraft.launcher.brand", launcherBrand);
|
||||||
|
if (launcherVersion != null)
|
||||||
|
System.setProperty("minecraft.launcher.version", launcherVersion);
|
||||||
|
|
||||||
|
// set useful properties for mods
|
||||||
|
if (name != null)
|
||||||
|
System.setProperty("org.prismlauncher.instance.name", name);
|
||||||
|
if (iconId != null)
|
||||||
|
System.setProperty("org.prismlauncher.instance.icon.id", iconId);
|
||||||
|
if (iconPath != null)
|
||||||
|
System.setProperty("org.prismlauncher.instance.icon.path", iconPath);
|
||||||
|
if (windowTitle != null)
|
||||||
|
System.setProperty("org.prismlauncher.window.title", windowTitle);
|
||||||
|
if (windowDimensions != null)
|
||||||
|
System.setProperty("org.prismlauncher.window.dimensions", windowDimensions);
|
||||||
|
|
||||||
|
// set multimc properties for compatibility
|
||||||
|
if (name != null)
|
||||||
|
System.setProperty("multimc.instance.title", name);
|
||||||
|
if (iconId != null)
|
||||||
|
System.setProperty("multimc.instance.icon", iconId);
|
||||||
|
}
|
||||||
|
}
|
@ -54,15 +54,9 @@
|
|||||||
|
|
||||||
package org.prismlauncher.utils;
|
package org.prismlauncher.utils;
|
||||||
|
|
||||||
import org.prismlauncher.utils.logging.Log;
|
|
||||||
|
|
||||||
import java.applet.Applet;
|
|
||||||
import java.io.File;
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
|
|
||||||
public final class ReflectionUtils {
|
public final class ReflectionUtils {
|
||||||
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
|
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit a5e8fd52b8bf4ab5d5bcc042b2a247867589985f
|
Subproject commit 23b955121b8217c1c348a9ed2483167a6f3ff4ad
|
@ -1 +1 @@
|
|||||||
Subproject commit 6117161af08e366c37499895b00ef62f93adc345
|
Subproject commit 9d3aa3ee948c1cde5a9f873ecbc3bb229c1182ee
|
@ -9,7 +9,8 @@ See [Package variants](#package-variants) for a list of available packages.
|
|||||||
## Installing a development release (flake)
|
## Installing a development release (flake)
|
||||||
|
|
||||||
We use [garnix](https://garnix.io/) to build and cache our development builds.
|
We use [garnix](https://garnix.io/) to build and cache our development builds.
|
||||||
If you want to avoid rebuilds you may add the garnix cache to your substitutors.
|
If you want to avoid rebuilds you may add the garnix cache to your substitutors, or use `--accept-flake-config`
|
||||||
|
to temporarily enable it when using `nix` commands.
|
||||||
|
|
||||||
Example (NixOS):
|
Example (NixOS):
|
||||||
|
|
||||||
|
@ -26,24 +26,8 @@
|
|||||||
overlays.default = final: prev: let
|
overlays.default = final: prev: let
|
||||||
version = builtins.substring 0 8 self.lastModifiedDate or "dirty";
|
version = builtins.substring 0 8 self.lastModifiedDate or "dirty";
|
||||||
|
|
||||||
filteredSelf = inputs.nix-filter.lib.filter {
|
|
||||||
root = ../.;
|
|
||||||
include = [
|
|
||||||
"buildconfig"
|
|
||||||
"cmake"
|
|
||||||
"launcher"
|
|
||||||
"libraries"
|
|
||||||
"program_info"
|
|
||||||
"tests"
|
|
||||||
../COPYING.md
|
|
||||||
../CMakeLists.txt
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
# common args for prismlauncher evaluations
|
# common args for prismlauncher evaluations
|
||||||
unwrappedArgs = {
|
unwrappedArgs = {
|
||||||
self = filteredSelf;
|
|
||||||
|
|
||||||
inherit (inputs) libnbtplusplus;
|
inherit (inputs) libnbtplusplus;
|
||||||
inherit ((final.darwin or prev.darwin).apple_sdk.frameworks) Cocoa;
|
inherit ((final.darwin or prev.darwin).apple_sdk.frameworks) Cocoa;
|
||||||
inherit version;
|
inherit version;
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
gamemode,
|
gamemode,
|
||||||
msaClientID ? null,
|
msaClientID ? null,
|
||||||
gamemodeSupport ? stdenv.isLinux,
|
gamemodeSupport ? stdenv.isLinux,
|
||||||
self,
|
|
||||||
version,
|
version,
|
||||||
libnbtplusplus,
|
libnbtplusplus,
|
||||||
}:
|
}:
|
||||||
@ -25,7 +24,19 @@ assert lib.assertMsg (stdenv.isLinux || !gamemodeSupport) "gamemodeSupport is on
|
|||||||
pname = "prismlauncher-unwrapped";
|
pname = "prismlauncher-unwrapped";
|
||||||
inherit version;
|
inherit version;
|
||||||
|
|
||||||
src = lib.cleanSource self;
|
src = lib.fileset.toSource {
|
||||||
|
root = ../../.;
|
||||||
|
fileset = lib.fileset.unions (map (fileName: ../../${fileName}) [
|
||||||
|
"buildconfig"
|
||||||
|
"cmake"
|
||||||
|
"launcher"
|
||||||
|
"libraries"
|
||||||
|
"program_info"
|
||||||
|
"tests"
|
||||||
|
"COPYING.md"
|
||||||
|
"CMakeLists.txt"
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [extra-cmake-modules cmake jdk17 ninja canonicalize-jars-hook];
|
nativeBuildInputs = [extra-cmake-modules cmake jdk17 ninja canonicalize-jars-hook];
|
||||||
buildInputs =
|
buildInputs =
|
||||||
|
@ -14,8 +14,8 @@ set(Launcher_DisplayName "Prism Launcher")
|
|||||||
set(Launcher_Name "${Launcher_CommonName}" PARENT_SCOPE)
|
set(Launcher_Name "${Launcher_CommonName}" PARENT_SCOPE)
|
||||||
set(Launcher_DisplayName "${Launcher_DisplayName}" PARENT_SCOPE)
|
set(Launcher_DisplayName "${Launcher_DisplayName}" PARENT_SCOPE)
|
||||||
|
|
||||||
set(Launcher_Copyright "Prism Launcher Contributors\\n© 2021-2022 PolyMC Contributors \\n© 2012-2021 MultiMC Contributors")
|
set(Launcher_Copyright "© 2022-2024 Prism Launcher Contributors\\n© 2021-2022 PolyMC Contributors\\n© 2012-2021 MultiMC Contributors")
|
||||||
set(Launcher_Copyright_Mac "Prism Launcher Contributors, © 2021-2022 PolyMC Contributors and © 2012-2021 MultiMC Contributors" PARENT_SCOPE)
|
set(Launcher_Copyright_Mac "© 2022-2024 Prism Launcher Contributors, © 2021-2022 PolyMC Contributors and © 2012-2021 MultiMC Contributors" PARENT_SCOPE)
|
||||||
set(Launcher_Copyright "${Launcher_Copyright}" PARENT_SCOPE)
|
set(Launcher_Copyright "${Launcher_Copyright}" PARENT_SCOPE)
|
||||||
set(Launcher_Domain "prismlauncher.org" PARENT_SCOPE)
|
set(Launcher_Domain "prismlauncher.org" PARENT_SCOPE)
|
||||||
set(Launcher_UserAgent "${Launcher_CommonName}/${Launcher_VERSION_NAME}" PARENT_SCOPE)
|
set(Launcher_UserAgent "${Launcher_CommonName}/${Launcher_VERSION_NAME}" PARENT_SCOPE)
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
|
||||||
|
<ws2:longPathAware>true</ws2:longPathAware>
|
||||||
|
</windowsSettings>
|
||||||
|
</application>
|
||||||
<assemblyIdentity name="PrismLauncher.Application.1" type="win32" version="@Launcher_VERSION_NAME4@" />
|
<assemblyIdentity name="PrismLauncher.Application.1" type="win32" version="@Launcher_VERSION_NAME4@" />
|
||||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
<security>
|
<security>
|
||||||
|
Loading…
Reference in New Issue
Block a user