Merge tag '9.0' into develop
This is an intermediate/halfway commit, more refactoring is needed to get this to build.
This commit is contained in:
commit
7dbaa896a6
@ -2,3 +2,6 @@
|
|||||||
|
|
||||||
# tabs -> spaces
|
# tabs -> spaces
|
||||||
bbb3b3e6f6e3c0f95873f22e6d0a4aaf350f49d9
|
bbb3b3e6f6e3c0f95873f22e6d0a4aaf350f49d9
|
||||||
|
|
||||||
|
# (nix) alejandra -> nixfmt
|
||||||
|
4c81d8c53d09196426568c4a31a4e752ed05397a
|
||||||
|
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.1.1
|
uses: korthout/backport-action@v3.1.0
|
||||||
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: |-
|
||||||
|
230
.github/workflows/build.yml
vendored
230
.github/workflows/build.yml
vendored
@ -39,6 +39,9 @@ on:
|
|||||||
APPLE_NOTARIZE_PASSWORD:
|
APPLE_NOTARIZE_PASSWORD:
|
||||||
description: Password used for notarizing macOS builds
|
description: Password used for notarizing macOS builds
|
||||||
required: false
|
required: false
|
||||||
|
CACHIX_AUTH_TOKEN:
|
||||||
|
description: Private token for authenticating against Cachix cache
|
||||||
|
required: false
|
||||||
GPG_PRIVATE_KEY:
|
GPG_PRIVATE_KEY:
|
||||||
description: Private key for AppImage signing
|
description: Private key for AppImage signing
|
||||||
required: false
|
required: false
|
||||||
@ -54,14 +57,17 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
qt_ver: 5
|
qt_ver: 5
|
||||||
|
qt_host: linux
|
||||||
|
qt_arch: ""
|
||||||
|
qt_version: "5.12.8"
|
||||||
|
qt_modules: "qtnetworkauth"
|
||||||
|
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: linux
|
qt_host: linux
|
||||||
qt_arch: ""
|
qt_arch: ""
|
||||||
qt_version: "6.2.4"
|
qt_version: "6.2.4"
|
||||||
qt_modules: "qt5compat qtimageformats"
|
qt_modules: "qt5compat qtimageformats qtnetworkauth"
|
||||||
qt_tools: ""
|
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
name: "Windows-MinGW-w64"
|
name: "Windows-MinGW-w64"
|
||||||
@ -75,10 +81,11 @@ jobs:
|
|||||||
vcvars_arch: "amd64"
|
vcvars_arch: "amd64"
|
||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: windows
|
qt_host: windows
|
||||||
qt_arch: ''
|
qt_arch: ""
|
||||||
qt_version: '6.6.3'
|
qt_version: "6.7.3"
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
qt_modules: "qt5compat qtimageformats qtnetworkauth"
|
||||||
qt_tools: ''
|
nscurl_tag: "v24.9.26.122"
|
||||||
|
nscurl_sha256: "AEE6C4BE3CB6455858E9C1EE4B3AFE0DB9960FA03FE99CCDEDC28390D57CCBB0"
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
name: "Windows-MSVC-arm64"
|
name: "Windows-MSVC-arm64"
|
||||||
@ -87,29 +94,28 @@ jobs:
|
|||||||
vcvars_arch: "amd64_arm64"
|
vcvars_arch: "amd64_arm64"
|
||||||
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.3'
|
qt_version: "6.7.3"
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
qt_modules: "qt5compat qtimageformats qtnetworkauth"
|
||||||
qt_tools: ''
|
nscurl_tag: "v24.9.26.122"
|
||||||
|
nscurl_sha256: "AEE6C4BE3CB6455858E9C1EE4B3AFE0DB9960FA03FE99CCDEDC28390D57CCBB0"
|
||||||
|
|
||||||
- os: macos-12
|
- os: macos-14
|
||||||
name: macOS
|
name: macOS
|
||||||
macosx_deployment_target: 11.0
|
macosx_deployment_target: 11.0
|
||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: mac
|
qt_host: mac
|
||||||
qt_arch: ''
|
qt_arch: ""
|
||||||
qt_version: '6.6.3'
|
qt_version: "6.7.3"
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
qt_modules: "qt5compat qtimageformats qtnetworkauth"
|
||||||
qt_tools: ''
|
|
||||||
|
|
||||||
- os: macos-12
|
- os: macos-14
|
||||||
name: macOS-Legacy
|
name: macOS-Legacy
|
||||||
macosx_deployment_target: 10.13
|
macosx_deployment_target: 10.13
|
||||||
qt_ver: 5
|
qt_ver: 5
|
||||||
qt_host: mac
|
qt_host: mac
|
||||||
qt_version: "5.15.2"
|
qt_version: "5.15.2"
|
||||||
qt_modules: ""
|
qt_modules: "qtnetworkauth"
|
||||||
qt_tools: ""
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
@ -151,6 +157,7 @@ jobs:
|
|||||||
quazip-qt6:p
|
quazip-qt6:p
|
||||||
ccache:p
|
ccache:p
|
||||||
qt6-5compat:p
|
qt6-5compat:p
|
||||||
|
qt6-networkauth:p
|
||||||
cmark:p
|
cmark:p
|
||||||
|
|
||||||
- name: Force newer ccache
|
- name: Force newer ccache
|
||||||
@ -160,13 +167,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.14
|
||||||
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.1.1
|
||||||
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 }}
|
||||||
@ -207,11 +214,6 @@ jobs:
|
|||||||
brew update
|
brew update
|
||||||
brew install ninja extra-cmake-modules
|
brew install ninja extra-cmake-modules
|
||||||
|
|
||||||
- name: Install Qt (Linux)
|
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
|
||||||
run: |
|
|
||||||
sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5
|
|
||||||
|
|
||||||
- name: Install host Qt (Windows MSVC arm64)
|
- name: Install host Qt (Windows MSVC arm64)
|
||||||
if: runner.os == 'Windows' && matrix.architecture == 'arm64'
|
if: runner.os == 'Windows' && matrix.architecture == 'arm64'
|
||||||
uses: jurplel/install-qt-action@v3
|
uses: jurplel/install-qt-action@v3
|
||||||
@ -223,20 +225,18 @@ jobs:
|
|||||||
target: "desktop"
|
target: "desktop"
|
||||||
arch: ""
|
arch: ""
|
||||||
modules: ${{ matrix.qt_modules }}
|
modules: ${{ matrix.qt_modules }}
|
||||||
tools: ${{ matrix.qt_tools }}
|
|
||||||
cache: ${{ inputs.is_qt_cached }}
|
cache: ${{ inputs.is_qt_cached }}
|
||||||
cache-key-prefix: host-qt-arm64-windows
|
cache-key-prefix: host-qt-arm64-windows
|
||||||
dir: ${{ github.workspace }}\HostQt
|
dir: ${{ github.workspace }}\HostQt
|
||||||
set-env: false
|
set-env: false
|
||||||
|
|
||||||
- name: Install Qt (macOS, Linux, Qt 6 & Windows MSVC)
|
- name: Install Qt (macOS, Linux & Windows MSVC)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver == 6 || runner.os == 'macOS' || (runner.os == 'Windows' && matrix.msystem == '')
|
if: matrix.msystem == ''
|
||||||
uses: jurplel/install-qt-action@v3
|
uses: jurplel/install-qt-action@v3
|
||||||
with:
|
with:
|
||||||
aqtversion: "==3.1.*"
|
aqtversion: "==3.1.*"
|
||||||
py7zrversion: ">=0.20.2"
|
py7zrversion: ">=0.20.2"
|
||||||
version: ${{ matrix.qt_version }}
|
version: ${{ matrix.qt_version }}
|
||||||
host: ${{ matrix.qt_host }}
|
|
||||||
target: "desktop"
|
target: "desktop"
|
||||||
arch: ${{ matrix.qt_arch }}
|
arch: ${{ matrix.qt_arch }}
|
||||||
modules: ${{ matrix.qt_modules }}
|
modules: ${{ matrix.qt_modules }}
|
||||||
@ -266,6 +266,12 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "QT_HOST_PATH=${{ github.workspace }}\HostQt\Qt\${{ matrix.qt_version }}\msvc2019_64" >> $env:GITHUB_ENV
|
echo "QT_HOST_PATH=${{ github.workspace }}\HostQt\Qt\${{ matrix.qt_version }}\msvc2019_64" >> $env:GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Setup java (macOS)
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: "temurin"
|
||||||
|
java-version: "17"
|
||||||
##
|
##
|
||||||
# CONFIGURE
|
# CONFIGURE
|
||||||
##
|
##
|
||||||
@ -273,23 +279,23 @@ jobs:
|
|||||||
- name: Configure CMake (macOS)
|
- name: Configure CMake (macOS)
|
||||||
if: runner.os == 'macOS' && matrix.qt_ver == 6
|
if: runner.os == 'macOS' && matrix.qt_ver == 6
|
||||||
run: |
|
run: |
|
||||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -G Ninja
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -G Ninja
|
||||||
|
|
||||||
- name: Configure CMake (macOS-Legacy)
|
- name: Configure CMake (macOS-Legacy)
|
||||||
if: runner.os == 'macOS' && matrix.qt_ver == 5
|
if: runner.os == 'macOS' && matrix.qt_ver == 5
|
||||||
run: |
|
run: |
|
||||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DMACOSX_SPARKLE_UPDATE_PUBLIC_KEY="" -DMACOSX_SPARKLE_UPDATE_FEED_URL="" -G Ninja
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DMACOSX_SPARKLE_UPDATE_PUBLIC_KEY="" -DMACOSX_SPARKLE_UPDATE_FEED_URL="" -DCMAKE_OSX_ARCHITECTURES="x86_64" -G Ninja
|
||||||
|
|
||||||
- name: Configure CMake (Windows MinGW-w64)
|
- name: Configure CMake (Windows MinGW-w64)
|
||||||
if: runner.os == 'Windows' && matrix.msystem != ''
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
run: |
|
run: |
|
||||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=6 -DCMAKE_OBJDUMP=/mingw64/bin/objdump.exe -DLauncher_BUILD_ARTIFACT=${{ matrix.name }}-Qt${{ matrix.qt_ver }} -G Ninja
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=6 -DCMAKE_OBJDUMP=/mingw64/bin/objdump.exe -DLauncher_BUILD_ARTIFACT=${{ matrix.name }}-Qt${{ matrix.qt_ver }} -G Ninja
|
||||||
|
|
||||||
- name: Configure CMake (Windows MSVC)
|
- name: Configure CMake (Windows MSVC)
|
||||||
if: runner.os == 'Windows' && matrix.msystem == ''
|
if: runner.os == 'Windows' && matrix.msystem == ''
|
||||||
run: |
|
run: |
|
||||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreadedDLL" -A${{ matrix.architecture}} -DLauncher_FORCE_BUNDLED_LIBS=ON -DLauncher_BUILD_ARTIFACT=${{ matrix.name }}-Qt${{ matrix.qt_ver }}
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreadedDLL" -A${{ matrix.architecture}} -DLauncher_FORCE_BUNDLED_LIBS=ON -DLauncher_BUILD_ARTIFACT=${{ matrix.name }}-Qt${{ matrix.qt_ver }}
|
||||||
# https://github.com/ccache/ccache/wiki/MS-Visual-Studio (I coudn't figure out the compiler prefix)
|
# https://github.com/ccache/ccache/wiki/MS-Visual-Studio (I coudn't figure out the compiler prefix)
|
||||||
if ("${{ env.CCACHE_VAR }}")
|
if ("${{ env.CCACHE_VAR }}")
|
||||||
{
|
{
|
||||||
@ -304,7 +310,7 @@ jobs:
|
|||||||
- name: Configure CMake (Linux)
|
- name: Configure CMake (Linux)
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
run: |
|
run: |
|
||||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DLauncher_BUILD_ARTIFACT=Linux-Qt${{ matrix.qt_ver }} -G Ninja
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DLauncher_BUILD_ARTIFACT=Linux-Qt${{ matrix.qt_ver }} -G Ninja
|
||||||
|
|
||||||
##
|
##
|
||||||
# BUILD
|
# BUILD
|
||||||
@ -404,9 +410,8 @@ jobs:
|
|||||||
if: matrix.name == 'macOS'
|
if: matrix.name == 'macOS'
|
||||||
run: |
|
run: |
|
||||||
if [ '${{ secrets.SPARKLE_ED25519_KEY }}' != '' ]; then
|
if [ '${{ secrets.SPARKLE_ED25519_KEY }}' != '' ]; then
|
||||||
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 }}/FjordLauncher.zip -inkey ed25519-priv.pem | openssl base64 | tr -d \\n)
|
signature=$(/opt/homebrew/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/FjordLauncher.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:
|
||||||
@ -432,12 +437,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build_type }}
|
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build_type }}
|
||||||
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
|
||||||
if ("${{ matrix.qt_ver }}" -eq "5")
|
|
||||||
{
|
|
||||||
Copy-Item ${{ runner.workspace }}/Qt/Tools/OpenSSL/Win_x86/bin/libcrypto-1_1.dll -Destination libcrypto-1_1.dll
|
|
||||||
Copy-Item ${{ runner.workspace }}/Qt/Tools/OpenSSL/Win_x86/bin/libssl-1_1.dll -Destination libssl-1_1.dll
|
|
||||||
}
|
|
||||||
cd ${{ github.workspace }}
|
cd ${{ github.workspace }}
|
||||||
|
|
||||||
Get-ChildItem ${{ env.INSTALL_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt
|
Get-ChildItem ${{ env.INSTALL_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt
|
||||||
@ -454,7 +453,7 @@ jobs:
|
|||||||
if (Get-Content ./codesign.pfx){
|
if (Get-Content ./codesign.pfx){
|
||||||
cd ${{ env.INSTALL_DIR }}
|
cd ${{ env.INSTALL_DIR }}
|
||||||
# We ship the exact same executable for portable and non-portable editions, so signing just once is fine
|
# We ship the exact same executable for portable and non-portable editions, so signing just once is fine
|
||||||
SignTool sign /fd sha256 /td sha256 /f ../codesign.pfx /p '${{ secrets.WINDOWS_CODESIGN_PASSWORD }}' /tr http://timestamp.digicert.com fjordlauncher.exe fjordlauncher_filelink.exe
|
SignTool sign /fd sha256 /td sha256 /f ../codesign.pfx /p '${{ secrets.WINDOWS_CODESIGN_PASSWORD }}' /tr http://timestamp.digicert.com fjordlauncher.exe fjordlauncher_updater.exe fjordlauncher_filelink.exe
|
||||||
} else {
|
} else {
|
||||||
":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY
|
":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY
|
||||||
}
|
}
|
||||||
@ -478,6 +477,16 @@ jobs:
|
|||||||
- name: Package (Windows, installer)
|
- name: Package (Windows, installer)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
run: |
|
run: |
|
||||||
|
if ('${{ matrix.nscurl_tag }}') {
|
||||||
|
New-Item -Name NSISPlugins -ItemType Directory
|
||||||
|
Invoke-Webrequest https://github.com/negrutiu/nsis-nscurl/releases/download/${{ matrix.nscurl_tag }}/NScurl.zip -OutFile NSISPlugins\NScurl.zip
|
||||||
|
$nscurl_hash = Get-FileHash NSISPlugins\NScurl.zip -Algorithm Sha256 | Select-Object -ExpandProperty Hash
|
||||||
|
if ( $nscurl_hash -ne "${{ matrix.nscurl_sha256 }}") {
|
||||||
|
echo "::error:: NSCurl.zip sha256 mismatch"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Expand-Archive -Path NSISPlugins\NScurl.zip -DestinationPath NSISPlugins\NScurl
|
||||||
|
}
|
||||||
cd ${{ env.INSTALL_DIR }}
|
cd ${{ env.INSTALL_DIR }}
|
||||||
makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi"
|
makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi"
|
||||||
|
|
||||||
@ -490,28 +499,6 @@ jobs:
|
|||||||
":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY
|
":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY
|
||||||
}
|
}
|
||||||
|
|
||||||
- name: Package (Linux)
|
|
||||||
if: runner.os == 'Linux'
|
|
||||||
run: |
|
|
||||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_DIR }}
|
|
||||||
for l in $(find ${{ env.INSTALL_DIR }} -type f); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_DIR }}/manifest.txt
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
|
||||||
tar --owner root --group root -czf ../FjordLauncher.tar.gz *
|
|
||||||
|
|
||||||
- name: Package (Linux, portable)
|
|
||||||
if: runner.os == 'Linux'
|
|
||||||
run: |
|
|
||||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }}
|
|
||||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
|
||||||
|
|
||||||
# workaround to make portable installs to work on fedora
|
|
||||||
mkdir ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
|
||||||
cp /lib/x86_64-linux-gnu/libbz2.so.1.0 ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
|
||||||
|
|
||||||
for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt
|
|
||||||
cd ${{ env.INSTALL_PORTABLE_DIR }}
|
|
||||||
tar -czf ../FjordLauncher-portable.tar.gz *
|
|
||||||
|
|
||||||
- name: Package AppImage (Linux)
|
- name: Package AppImage (Linux)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
shell: bash
|
shell: bash
|
||||||
@ -520,7 +507,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}/usr
|
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}/usr
|
||||||
|
|
||||||
mv ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/metainfo/org.unmojang.FjordLauncher.metainfo.xml ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/metainfo/org.unmojang.FjordLauncher.appdata.xml
|
mv ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/metainfo/org.unmojang.FjordLauncher.metainfo.xml ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/metainfo/org.fjordlauncher.FjordLauncher.appdata.xml
|
||||||
export "NO_APPSTREAM=1" # we have to skip appstream checking because appstream on ubuntu 20.04 is outdated
|
export "NO_APPSTREAM=1" # we have to skip appstream checking because appstream on ubuntu 20.04 is outdated
|
||||||
|
|
||||||
export OUTPUT="FjordLauncher-Linux-x86_64.AppImage"
|
export OUTPUT="FjordLauncher-Linux-x86_64.AppImage"
|
||||||
@ -558,76 +545,81 @@ jobs:
|
|||||||
|
|
||||||
mv "FjordLauncher-Linux-x86_64.AppImage" "FjordLauncher-Linux-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage"
|
mv "FjordLauncher-Linux-x86_64.AppImage" "FjordLauncher-Linux-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage"
|
||||||
|
|
||||||
|
- name: Package (Linux, portable)
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_PORTABLE_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DLauncher_BUILD_ARTIFACT=Linux-Qt${{ matrix.qt_ver }} -DINSTALL_BUNDLE=full -G Ninja
|
||||||
|
cmake --install ${{ env.BUILD_DIR }}
|
||||||
|
cmake --install ${{ env.BUILD_DIR }} --component portable
|
||||||
|
|
||||||
|
mkdir ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
||||||
|
cp /lib/x86_64-linux-gnu/libbz2.so.1.0 ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
||||||
|
cp /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0 ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
||||||
|
cp /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
||||||
|
cp /usr/lib/x86_64-linux-gnu/libssl.so.1.1 ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
||||||
|
cp /usr/lib/x86_64-linux-gnu/libffi.so.7 ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
||||||
|
mv ${{ env.INSTALL_PORTABLE_DIR }}/bin/*.so* ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
||||||
|
|
||||||
|
for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt
|
||||||
|
cd ${{ env.INSTALL_PORTABLE_DIR }}
|
||||||
|
tar -czf ../FjordLauncher-portable.tar.gz *
|
||||||
|
|
||||||
##
|
##
|
||||||
# UPLOAD BUILDS
|
# UPLOAD BUILDS
|
||||||
##
|
##
|
||||||
|
|
||||||
- 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: FjordLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: FjordLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: FjordLauncher.zip
|
path: FjordLauncher.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: FjordLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: FjordLauncher-${{ 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: FjordLauncher-${{ matrix.name }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: FjordLauncher-${{ 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: FjordLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: FjordLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: FjordLauncher-Setup.exe
|
path: FjordLauncher-Setup.exe
|
||||||
|
|
||||||
- name: Upload binary tarball (Linux, Qt 5)
|
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: FjordLauncher-${{ runner.os }}-Qt5-${{ env.VERSION }}-${{ inputs.build_type }}
|
|
||||||
path: FjordLauncher.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: FjordLauncher-${{ runner.os }}-Qt5-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: FjordLauncher-${{ runner.os }}-Qt5-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: FjordLauncher-portable.tar.gz
|
path: FjordLauncher-portable.tar.gz
|
||||||
|
|
||||||
- name: Upload binary tarball (Linux, Qt 6)
|
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver !=5
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: FjordLauncher-${{ runner.os }}-Qt6-${{ env.VERSION }}-${{ inputs.build_type }}
|
|
||||||
path: FjordLauncher.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: FjordLauncher-${{ runner.os }}-Qt6-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: FjordLauncher-${{ runner.os }}-Qt6-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: FjordLauncher-portable.tar.gz
|
path: FjordLauncher-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: FjordLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
name: FjordLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||||
path: FjordLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
path: FjordLauncher-${{ 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: FjordLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage.zsync
|
name: FjordLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage.zsync
|
||||||
path: FjordLauncher-Linux-x86_64.AppImage.zsync
|
path: FjordLauncher-Linux-x86_64.AppImage.zsync
|
||||||
@ -641,23 +633,67 @@ jobs:
|
|||||||
flatpak:
|
flatpak:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: bilelmoussaoui/flatpak-github-actions:kde-5.15-23.08
|
image: bilelmoussaoui/flatpak-github-actions:kde-6.7
|
||||||
options: --privileged
|
options: --privileged
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
if: inputs.build_type == 'Release'
|
if: inputs.build_type == 'Debug'
|
||||||
with:
|
with:
|
||||||
submodules: "true"
|
submodules: "true"
|
||||||
- name: Build Flatpak (Linux)
|
- name: Build Flatpak (Linux)
|
||||||
if: inputs.build_type == 'Release'
|
if: inputs.build_type == 'Debug'
|
||||||
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
||||||
with:
|
with:
|
||||||
bundle: "FjordLauncher.flatpak"
|
bundle: "Fjord Launcher.flatpak"
|
||||||
manifest-path: flatpak/org.unmojang.FjordLauncher.yml
|
manifest-path: flatpak/org.unmojang.FjordLauncher.yml
|
||||||
- name: Upload Flatpak (Linux)
|
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
nix:
|
||||||
uses: actions/upload-artifact@v3
|
name: Nix (${{ matrix.system }})
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: ubuntu-22.04
|
||||||
|
system: x86_64-linux
|
||||||
|
|
||||||
|
- os: macos-13
|
||||||
|
system: x86_64-darwin
|
||||||
|
|
||||||
|
- os: macos-14
|
||||||
|
system: aarch64-darwin
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Nix
|
||||||
|
uses: cachix/install-nix-action@v30
|
||||||
|
|
||||||
|
# For PRs
|
||||||
|
- name: Setup Nix Magic Cache
|
||||||
|
uses: DeterminateSystems/magic-nix-cache-action@v8
|
||||||
|
|
||||||
|
# For in-tree builds
|
||||||
|
- name: Setup Cachix
|
||||||
|
uses: cachix/cachix-action@v15
|
||||||
with:
|
with:
|
||||||
name: FjordLauncher-${{ runner.os }}-x86_64.flatpak
|
name: fjordlauncher
|
||||||
path: FjordLauncher.flatpak
|
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||||
|
|
||||||
|
- name: Run flake checks
|
||||||
|
run: |
|
||||||
|
nix flake check --print-build-logs --show-trace
|
||||||
|
|
||||||
|
- name: Build debug package
|
||||||
|
if: ${{ inputs.build_type == 'Debug' }}
|
||||||
|
run: |
|
||||||
|
nix build --print-build-logs .#fjordlauncher-debug
|
||||||
|
|
||||||
|
- name: Build release package
|
||||||
|
if: ${{ inputs.build_type != 'Debug' }}
|
||||||
|
run: |
|
||||||
|
nix build --print-build-logs .#fjordlauncher
|
||||||
|
6
.github/workflows/codeql.yml
vendored
6
.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
|
||||||
@ -23,7 +23,7 @@ jobs:
|
|||||||
run:
|
run:
|
||||||
sudo apt-get -y update
|
sudo apt-get -y update
|
||||||
|
|
||||||
sudo apt-get -y install ninja-build extra-cmake-modules scdoc qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5
|
sudo apt-get -y install ninja-build extra-cmake-modules scdoc qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 libqt5networkauth5 libqt5networkauth5-dev
|
||||||
|
|
||||||
- name: Configure and Build
|
- name: Configure and Build
|
||||||
run: |
|
run: |
|
||||||
@ -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
|
||||||
|
1
.github/workflows/trigger_builds.yml
vendored
1
.github/workflows/trigger_builds.yml
vendored
@ -38,5 +38,6 @@ jobs:
|
|||||||
APPLE_NOTARIZE_APPLE_ID: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }}
|
APPLE_NOTARIZE_APPLE_ID: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }}
|
||||||
APPLE_NOTARIZE_TEAM_ID: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }}
|
APPLE_NOTARIZE_TEAM_ID: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }}
|
||||||
APPLE_NOTARIZE_PASSWORD: ${{ secrets.APPLE_NOTARIZE_PASSWORD }}
|
APPLE_NOTARIZE_PASSWORD: ${{ secrets.APPLE_NOTARIZE_PASSWORD }}
|
||||||
|
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||||
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 }}
|
||||||
|
9
.github/workflows/trigger_release.yml
vendored
9
.github/workflows/trigger_release.yml
vendored
@ -22,6 +22,7 @@ jobs:
|
|||||||
APPLE_NOTARIZE_APPLE_ID: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }}
|
APPLE_NOTARIZE_APPLE_ID: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }}
|
||||||
APPLE_NOTARIZE_TEAM_ID: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }}
|
APPLE_NOTARIZE_TEAM_ID: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }}
|
||||||
APPLE_NOTARIZE_PASSWORD: ${{ secrets.APPLE_NOTARIZE_PASSWORD }}
|
APPLE_NOTARIZE_PASSWORD: ${{ secrets.APPLE_NOTARIZE_PASSWORD }}
|
||||||
|
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||||
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 }}
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ jobs:
|
|||||||
submodules: "true"
|
submodules: "true"
|
||||||
path: "FjordLauncher-source"
|
path: "FjordLauncher-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,9 +47,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mv ${{ github.workspace }}/FjordLauncher-source FjordLauncher-${{ env.VERSION }}
|
mv ${{ github.workspace }}/FjordLauncher-source FjordLauncher-${{ env.VERSION }}
|
||||||
mv FjordLauncher-Linux-Qt6-Portable*/FjordLauncher-portable.tar.gz FjordLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
mv FjordLauncher-Linux-Qt6-Portable*/FjordLauncher-portable.tar.gz FjordLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
||||||
mv FjordLauncher-Linux-Qt6*/FjordLauncher.tar.gz FjordLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz
|
|
||||||
mv FjordLauncher-Linux-Qt5-Portable*/FjordLauncher-portable.tar.gz FjordLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz
|
mv FjordLauncher-Linux-Qt5-Portable*/FjordLauncher-portable.tar.gz FjordLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz
|
||||||
mv FjordLauncher-Linux-Qt5*/FjordLauncher.tar.gz FjordLauncher-Linux-Qt5-${{ env.VERSION }}.tar.gz
|
|
||||||
mv FjordLauncher-*.AppImage/FjordLauncher-*.AppImage FjordLauncher-Linux-x86_64.AppImage
|
mv FjordLauncher-*.AppImage/FjordLauncher-*.AppImage FjordLauncher-Linux-x86_64.AppImage
|
||||||
mv FjordLauncher-*.AppImage.zsync/FjordLauncher-*.AppImage.zsync FjordLauncher-Linux-x86_64.AppImage.zsync
|
mv FjordLauncher-*.AppImage.zsync/FjordLauncher-*.AppImage.zsync FjordLauncher-Linux-x86_64.AppImage.zsync
|
||||||
mv FjordLauncher-macOS-Legacy*/FjordLauncher.zip FjordLauncher-macOS-Legacy-${{ env.VERSION }}.zip
|
mv FjordLauncher-macOS-Legacy*/FjordLauncher.zip FjordLauncher-macOS-Legacy-${{ env.VERSION }}.zip
|
||||||
@ -84,7 +83,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 }}
|
||||||
@ -92,11 +91,9 @@ jobs:
|
|||||||
draft: true
|
draft: true
|
||||||
prerelease: false
|
prerelease: false
|
||||||
files: |
|
files: |
|
||||||
FjordLauncher-Linux-Qt5-${{ env.VERSION }}.tar.gz
|
|
||||||
FjordLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz
|
FjordLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz
|
||||||
FjordLauncher-Linux-x86_64.AppImage
|
FjordLauncher-Linux-x86_64.AppImage
|
||||||
FjordLauncher-Linux-x86_64.AppImage.zsync
|
FjordLauncher-Linux-x86_64.AppImage.zsync
|
||||||
FjordLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz
|
|
||||||
FjordLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
FjordLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
||||||
FjordLauncher-Windows-MinGW-w64-${{ env.VERSION }}.zip
|
FjordLauncher-Windows-MinGW-w64-${{ env.VERSION }}.zip
|
||||||
FjordLauncher-Windows-MinGW-w64-Portable-${{ env.VERSION }}.zip
|
FjordLauncher-Windows-MinGW-w64-Portable-${{ env.VERSION }}.zip
|
||||||
|
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@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30
|
||||||
|
|
||||||
- uses: DeterminateSystems/update-flake-lock@v20
|
- uses: DeterminateSystems/update-flake-lock@v24
|
||||||
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"
|
||||||
|
3
BUILD.md
3
BUILD.md
@ -1,3 +0,0 @@
|
|||||||
# Build Instructions
|
|
||||||
|
|
||||||
Full build instructions are available on [the website](https://prismlauncher.org/wiki/development/build-instructions/).
|
|
@ -99,7 +99,7 @@ if ((CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebI
|
|||||||
message(STATUS "Address Sanitizer enabled for Debug builds, Turn it off with -DDEBUG_ADDRESS_SANITIZER=off")
|
message(STATUS "Address Sanitizer enabled for Debug builds, Turn it off with -DDEBUG_ADDRESS_SANITIZER=off")
|
||||||
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||||
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||||
# using clang with clang-cl front end
|
# using clang with clang-cl front end
|
||||||
message(STATUS "Address Sanitizer available on Clang MSVC frontend")
|
message(STATUS "Address Sanitizer available on Clang MSVC frontend")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /Oy-")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /Oy-")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /Oy-")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /Oy-")
|
||||||
@ -176,11 +176,13 @@ endif()
|
|||||||
set(Launcher_NEWS_RSS_URL "" CACHE STRING "URL to fetch Prism Launcher's news RSS feed from.")
|
set(Launcher_NEWS_RSS_URL "" CACHE STRING "URL to fetch Prism Launcher's news RSS feed from.")
|
||||||
set(Launcher_NEWS_OPEN_URL "https://prismlauncher.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
|
set(Launcher_NEWS_OPEN_URL "https://prismlauncher.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
|
||||||
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(Launcher_LOGIN_CALLBACK_URL "https://prismlauncher.org/successful-login" CACHE STRING "URL that gets opened when the user successfully logins.")
|
||||||
|
set(Launcher_FMLLIBS_BASE_URL "https://files.prismlauncher.org/fmllibs/" CACHE STRING "URL for FML Libraries.")
|
||||||
|
|
||||||
######## Set version numbers ########
|
######## Set version numbers ########
|
||||||
set(Launcher_VERSION_MAJOR 8)
|
set(Launcher_VERSION_MAJOR 9)
|
||||||
set(Launcher_VERSION_MINOR 4)
|
set(Launcher_VERSION_MINOR 0)
|
||||||
set(Launcher_VERSION_PATCH 3)
|
set(Launcher_VERSION_PATCH 0)
|
||||||
|
|
||||||
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_PATCH}")
|
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_PATCH}")
|
||||||
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_PATCH}.0")
|
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_PATCH}.0")
|
||||||
@ -206,6 +208,7 @@ set(Launcher_BUG_TRACKER_URL "https://github.com/unmojang/FjordLauncher/issues"
|
|||||||
|
|
||||||
# Translations Platform URL
|
# Translations Platform URL
|
||||||
set(Launcher_TRANSLATIONS_URL "https://hosted.weblate.org/projects/prismlauncher/launcher/" CACHE STRING "URL for the translations platform.")
|
set(Launcher_TRANSLATIONS_URL "https://hosted.weblate.org/projects/prismlauncher/launcher/" CACHE STRING "URL for the translations platform.")
|
||||||
|
set(Launcher_TRANSLATION_FILES_URL "https://i18n.prismlauncher.org/" CACHE STRING "URL for the translations files.")
|
||||||
|
|
||||||
# Matrix Space
|
# Matrix Space
|
||||||
set(Launcher_MATRIX_URL "" CACHE STRING "URL to the Matrix Space")
|
set(Launcher_MATRIX_URL "" CACHE STRING "URL to the Matrix Space")
|
||||||
@ -220,6 +223,19 @@ set(Launcher_SUBREDDIT_URL "" CACHE STRING "URL for the subreddit.")
|
|||||||
set(Launcher_FORCE_BUNDLED_LIBS OFF CACHE BOOL "Prevent using system libraries, if they are available as submodules")
|
set(Launcher_FORCE_BUNDLED_LIBS OFF CACHE BOOL "Prevent using system libraries, if they are available as submodules")
|
||||||
set(Launcher_QT_VERSION_MAJOR "6" CACHE STRING "Major Qt version to build against")
|
set(Launcher_QT_VERSION_MAJOR "6" CACHE STRING "Major Qt version to build against")
|
||||||
|
|
||||||
|
# Java downloader
|
||||||
|
set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT ON)
|
||||||
|
|
||||||
|
# Although we recommend enabling this, we cannot guarantee binary compatibility on
|
||||||
|
# differing Linux/BSD/etc distributions. Downstream packagers should be explicitly opt-ing into this
|
||||||
|
# feature if they know it will work with their distribution.
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Java downloader
|
||||||
|
option(Launcher_ENABLE_JAVA_DOWNLOADER "Build the java downloader feature" ${Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT})
|
||||||
|
|
||||||
# Native libraries
|
# Native libraries
|
||||||
if(UNIX AND APPLE)
|
if(UNIX AND APPLE)
|
||||||
set(Launcher_GLFW_LIBRARY_NAME "libglfw.dylib" CACHE STRING "Name of native glfw library")
|
set(Launcher_GLFW_LIBRARY_NAME "libglfw.dylib" CACHE STRING "Name of native glfw library")
|
||||||
@ -275,7 +291,7 @@ endif()
|
|||||||
include(QtVersionlessBackport)
|
include(QtVersionlessBackport)
|
||||||
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
|
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
|
||||||
set(QT_VERSION_MAJOR 5)
|
set(QT_VERSION_MAJOR 5)
|
||||||
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml)
|
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml NetworkAuth)
|
||||||
|
|
||||||
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
||||||
find_package(QuaZip-Qt5 1.3 QUIET)
|
find_package(QuaZip-Qt5 1.3 QUIET)
|
||||||
@ -289,7 +305,7 @@ if(Launcher_QT_VERSION_MAJOR EQUAL 5)
|
|||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNICODE -D_UNICODE")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNICODE -D_UNICODE")
|
||||||
elseif(Launcher_QT_VERSION_MAJOR EQUAL 6)
|
elseif(Launcher_QT_VERSION_MAJOR EQUAL 6)
|
||||||
set(QT_VERSION_MAJOR 6)
|
set(QT_VERSION_MAJOR 6)
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml Core5Compat)
|
find_package(Qt6 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml Core5Compat NetworkAuth)
|
||||||
list(APPEND Launcher_QT_LIBS Qt6::Core5Compat)
|
list(APPEND Launcher_QT_LIBS Qt6::Core5Compat)
|
||||||
|
|
||||||
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
||||||
@ -410,7 +426,19 @@ elseif(UNIX)
|
|||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_mrpack_MIMEInfo} DESTINATION ${KDE_INSTALL_MIMEDIR})
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_mrpack_MIMEInfo} DESTINATION ${KDE_INSTALL_MIMEDIR})
|
||||||
|
|
||||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/launcher/qtlogging.ini" DESTINATION "share/${Launcher_Name}")
|
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/launcher/qtlogging.ini" DESTINATION "share/${Launcher_Name}")
|
||||||
|
|
||||||
|
if (INSTALL_BUNDLE STREQUAL full)
|
||||||
|
set(PLUGIN_DEST_DIR "plugins")
|
||||||
|
set(BUNDLE_DEST_DIR ".")
|
||||||
|
set(RESOURCES_DEST_DIR ".")
|
||||||
|
|
||||||
|
# Apps to bundle
|
||||||
|
set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${Launcher_APP_BINARY_NAME}")
|
||||||
|
|
||||||
|
# directories to look for dependencies
|
||||||
|
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||||
|
endif()
|
||||||
|
|
||||||
if(Launcher_ManPage)
|
if(Launcher_ManPage)
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION "${KDE_INSTALL_MANDIR}/man6")
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION "${KDE_INSTALL_MANDIR}/man6")
|
||||||
endif()
|
endif()
|
||||||
@ -460,7 +488,7 @@ if(FORCE_BUNDLED_ZLIB)
|
|||||||
set(SKIP_INSTALL_ALL ON)
|
set(SKIP_INSTALL_ALL ON)
|
||||||
add_subdirectory(libraries/zlib EXCLUDE_FROM_ALL)
|
add_subdirectory(libraries/zlib EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
# On OS where unistd.h exists, zlib's generated header defines `Z_HAVE_UNISTD_H`, while the included header does not.
|
# On OS where unistd.h exists, zlib's generated header defines `Z_HAVE_UNISTD_H`, while the included header does not.
|
||||||
# We cannot safely undo the rename on those systems, and they generally have packages for zlib anyway.
|
# We cannot safely undo the rename on those systems, and they generally have packages for zlib anyway.
|
||||||
check_include_file(unistd.h NEED_GENERATED_ZCONF)
|
check_include_file(unistd.h NEED_GENERATED_ZCONF)
|
||||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib/zconf.h.included" AND NOT NEED_GENERATED_ZCONF)
|
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib/zconf.h.included" AND NOT NEED_GENERATED_ZCONF)
|
||||||
@ -497,14 +525,15 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
if(NOT cmark_FOUND)
|
if(NOT cmark_FOUND)
|
||||||
message(STATUS "Using bundled cmark")
|
message(STATUS "Using bundled cmark")
|
||||||
|
set(ORIGINAL_BUILD_TESTING ${BUILD_TESTING})
|
||||||
set(BUILD_TESTING 0)
|
set(BUILD_TESTING 0)
|
||||||
set(BUILD_SHARED_LIBS 0)
|
set(BUILD_SHARED_LIBS 0)
|
||||||
add_subdirectory(libraries/cmark EXCLUDE_FROM_ALL) # Markdown parser
|
add_subdirectory(libraries/cmark EXCLUDE_FROM_ALL) # Markdown parser
|
||||||
add_library(cmark::cmark ALIAS cmark)
|
add_library(cmark::cmark ALIAS cmark)
|
||||||
|
set(BUILD_TESTING ${ORIGINAL_BUILD_TESTING})
|
||||||
else()
|
else()
|
||||||
message(STATUS "Using system cmark")
|
message(STATUS "Using system cmark")
|
||||||
endif()
|
endif()
|
||||||
add_subdirectory(libraries/katabasis) # An OAuth2 library that tried to do too much
|
|
||||||
add_subdirectory(libraries/gamemode)
|
add_subdirectory(libraries/gamemode)
|
||||||
add_subdirectory(libraries/murmur2) # Hash for usage with the CurseForge API
|
add_subdirectory(libraries/murmur2) # Hash for usage with the CurseForge API
|
||||||
if (NOT ghc_filesystem_FOUND)
|
if (NOT ghc_filesystem_FOUND)
|
||||||
|
26
COPYING.md
26
COPYING.md
@ -401,32 +401,6 @@
|
|||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
## O2 (Katabasis fork)
|
|
||||||
|
|
||||||
Copyright (c) 2012, Akos Polster
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
## Gamemode
|
## Gamemode
|
||||||
|
|
||||||
Copyright (c) 2017-2022, Feral Interactive
|
Copyright (c) 2017-2022, Feral Interactive
|
||||||
|
@ -102,7 +102,12 @@ AppImages are available in the [releases section](https://github.com/unmojang/Fj
|
|||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
To build the launcher yourself, follow [the instructions on the Prism Launcher website](https://prismlauncher.org/wiki/development/build-instructions) but clone this repo instead.
|
To build the launcher yourself, follow the instructions on the Prism Launcher website, but clone this repo instead:
|
||||||
|
|
||||||
|
- [Windows](https://prismlauncher.org/wiki/development/build-instructions/windows/)
|
||||||
|
- [Linux](https://prismlauncher.org/wiki/development/build-instructions/linux/)
|
||||||
|
- [MacOS](https://prismlauncher.org/wiki/development/build-instructions/macos/)
|
||||||
|
- [OpenBSD](https://prismlauncher.org/wiki/development/build-instructions/openbsd/)
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
@ -83,6 +83,9 @@ Config::Config()
|
|||||||
UPDATER_ENABLED = true;
|
UPDATER_ENABLED = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cmakedefine01 Launcher_ENABLE_JAVA_DOWNLOADER
|
||||||
|
JAVA_DOWNLOADER_ENABLED = Launcher_ENABLE_JAVA_DOWNLOADER;
|
||||||
|
|
||||||
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
|
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
|
||||||
GIT_TAG = "@Launcher_GIT_TAG@";
|
GIT_TAG = "@Launcher_GIT_TAG@";
|
||||||
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
|
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
|
||||||
@ -115,16 +118,19 @@ Config::Config()
|
|||||||
NEWS_RSS_URL = "@Launcher_NEWS_RSS_URL@";
|
NEWS_RSS_URL = "@Launcher_NEWS_RSS_URL@";
|
||||||
NEWS_OPEN_URL = "@Launcher_NEWS_OPEN_URL@";
|
NEWS_OPEN_URL = "@Launcher_NEWS_OPEN_URL@";
|
||||||
HELP_URL = "@Launcher_HELP_URL@";
|
HELP_URL = "@Launcher_HELP_URL@";
|
||||||
|
LOGIN_CALLBACK_URL = "@Launcher_LOGIN_CALLBACK_URL@";
|
||||||
IMGUR_CLIENT_ID = "@Launcher_IMGUR_CLIENT_ID@";
|
IMGUR_CLIENT_ID = "@Launcher_IMGUR_CLIENT_ID@";
|
||||||
MSA_CLIENT_ID = "@Launcher_MSA_CLIENT_ID@";
|
MSA_CLIENT_ID = "@Launcher_MSA_CLIENT_ID@";
|
||||||
FLAME_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
|
FLAME_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
|
||||||
META_URL = "@Launcher_META_URL@";
|
META_URL = "@Launcher_META_URL@";
|
||||||
|
FMLLIBS_BASE_URL = "@Launcher_FMLLIBS_BASE_URL@";
|
||||||
|
|
||||||
GLFW_LIBRARY_NAME = "@Launcher_GLFW_LIBRARY_NAME@";
|
GLFW_LIBRARY_NAME = "@Launcher_GLFW_LIBRARY_NAME@";
|
||||||
OPENAL_LIBRARY_NAME = "@Launcher_OPENAL_LIBRARY_NAME@";
|
OPENAL_LIBRARY_NAME = "@Launcher_OPENAL_LIBRARY_NAME@";
|
||||||
|
|
||||||
BUG_TRACKER_URL = "@Launcher_BUG_TRACKER_URL@";
|
BUG_TRACKER_URL = "@Launcher_BUG_TRACKER_URL@";
|
||||||
TRANSLATIONS_URL = "@Launcher_TRANSLATIONS_URL@";
|
TRANSLATIONS_URL = "@Launcher_TRANSLATIONS_URL@";
|
||||||
|
TRANSLATION_FILES_URL = "@Launcher_TRANSLATION_FILES_URL@";
|
||||||
MATRIX_URL = "@Launcher_MATRIX_URL@";
|
MATRIX_URL = "@Launcher_MATRIX_URL@";
|
||||||
DISCORD_URL = "@Launcher_DISCORD_URL@";
|
DISCORD_URL = "@Launcher_DISCORD_URL@";
|
||||||
SUBREDDIT_URL = "@Launcher_SUBREDDIT_URL@";
|
SUBREDDIT_URL = "@Launcher_SUBREDDIT_URL@";
|
||||||
|
@ -70,6 +70,7 @@ class Config {
|
|||||||
QString VERSION_CHANNEL;
|
QString VERSION_CHANNEL;
|
||||||
|
|
||||||
bool UPDATER_ENABLED = false;
|
bool UPDATER_ENABLED = false;
|
||||||
|
bool JAVA_DOWNLOADER_ENABLED = false;
|
||||||
|
|
||||||
/// A short string identifying this build's platform or distribution.
|
/// A short string identifying this build's platform or distribution.
|
||||||
QString BUILD_PLATFORM;
|
QString BUILD_PLATFORM;
|
||||||
@ -135,6 +136,11 @@ class Config {
|
|||||||
*/
|
*/
|
||||||
QString HELP_URL;
|
QString HELP_URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL that gets opened when the user succesfully logins.
|
||||||
|
*/
|
||||||
|
QString LOGIN_CALLBACK_URL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client ID you can get from Imgur when you register an application
|
* Client ID you can get from Imgur when you register an application
|
||||||
*/
|
*/
|
||||||
@ -173,8 +179,8 @@ class Config {
|
|||||||
QString RESOURCE_BASE = "https://resources.download.minecraft.net/";
|
QString RESOURCE_BASE = "https://resources.download.minecraft.net/";
|
||||||
QString LIBRARY_BASE = "https://libraries.minecraft.net/";
|
QString LIBRARY_BASE = "https://libraries.minecraft.net/";
|
||||||
QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
|
QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
|
||||||
QString FMLLIBS_BASE_URL = "https://files.prismlauncher.org/fmllibs/"; // FIXME: move into CMakeLists
|
QString FMLLIBS_BASE_URL;
|
||||||
QString TRANSLATIONS_BASE_URL = "https://i18n.prismlauncher.org/"; // FIXME: move into CMakeLists
|
QString TRANSLATION_FILES_URL;
|
||||||
|
|
||||||
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";
|
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";
|
||||||
|
|
||||||
|
@ -79,6 +79,14 @@
|
|||||||
<string>curseforge</string>
|
<string>curseforge</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>Prismlauncher</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>prismlauncher</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
23
default.nix
23
default.nix
@ -1,14 +1,9 @@
|
|||||||
(
|
(import (
|
||||||
import
|
let
|
||||||
(
|
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
|
||||||
let
|
in
|
||||||
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
|
fetchTarball {
|
||||||
in
|
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
|
||||||
fetchTarball {
|
sha256 = lock.nodes.flake-compat.locked.narHash;
|
||||||
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
|
}
|
||||||
sha256 = lock.nodes.flake-compat.locked.narHash;
|
) { src = ./.; }).defaultNix
|
||||||
}
|
|
||||||
)
|
|
||||||
{src = ./.;}
|
|
||||||
)
|
|
||||||
.defaultNix
|
|
||||||
|
84
flake.lock
generated
84
flake.lock
generated
@ -16,47 +16,6 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-parts": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs-lib": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1719877454,
|
|
||||||
"narHash": "sha256-g5N1yyOSsPNiOlFfkuI/wcUjmtah+nxdImJqrSATjOU=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"rev": "4e3583423212f9303aa1a6337f8dffb415920e4f",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"gitignore": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"pre-commit-hooks",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1709087332,
|
|
||||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "gitignore.nix",
|
|
||||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "gitignore.nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"libnbtplusplus": {
|
"libnbtplusplus": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
@ -90,55 +49,26 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1719826879,
|
"lastModified": 1729256560,
|
||||||
"narHash": "sha256-xs7PlULe8O1SAcs/9e/HOjeUjBrU5FNtkAF/bSEcFto=",
|
"narHash": "sha256-/uilDXvCIEs3C9l73JTACm4quuHUsIHcns1c+cHUJwA=",
|
||||||
"owner": "nixos",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "b9014df496d5b68bf7c0145d0e9b0f529ce4f2a8",
|
"rev": "4c2fcb090b1f3e5b47eaa7bd33913b574a11e0a0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nixos",
|
"owner": "NixOS",
|
||||||
"ref": "nixpkgs-unstable",
|
"ref": "nixos-unstable",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pre-commit-hooks": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": [
|
|
||||||
"flake-compat"
|
|
||||||
],
|
|
||||||
"gitignore": "gitignore",
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"nixpkgs-stable": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1719259945,
|
|
||||||
"narHash": "sha256-F1h+XIsGKT9TkGO3omxDLEb/9jOOsI6NnzsXFsZhry4=",
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "pre-commit-hooks.nix",
|
|
||||||
"rev": "0ff4381bbb8f7a52ca4a851660fc7a437a4c6e07",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "pre-commit-hooks.nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
"flake-parts": "flake-parts",
|
|
||||||
"libnbtplusplus": "libnbtplusplus",
|
"libnbtplusplus": "libnbtplusplus",
|
||||||
"nix-filter": "nix-filter",
|
"nix-filter": "nix-filter",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs"
|
||||||
"pre-commit-hooks": "pre-commit-hooks"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
147
flake.nix
147
flake.nix
@ -2,53 +2,130 @@
|
|||||||
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 = {
|
nixConfig = {
|
||||||
extra-substituters = ["https://cache.garnix.io"];
|
extra-substituters = ["https://prismlauncher.cachix.org"];
|
||||||
extra-trusted-public-keys = ["cache.garnix.io:CTFPyKSLcx5RMJKfLo5EEPUObbA78b0YQ2DTCJXqr9g="];
|
extra-trusted-public-keys = [
|
||||||
|
"prismlauncher.cachix.org-1:9/n/FGyABA2jLUVfY+DEp4hKds/rwO+SCOtbOkDzd+c="
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
flake-parts = {
|
|
||||||
url = "github:hercules-ci/flake-parts";
|
|
||||||
inputs.nixpkgs-lib.follows = "nixpkgs";
|
|
||||||
};
|
|
||||||
nix-filter.url = "github:numtide/nix-filter";
|
|
||||||
pre-commit-hooks = {
|
|
||||||
url = "github:cachix/pre-commit-hooks.nix";
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.follows = "nixpkgs";
|
|
||||||
nixpkgs-stable.follows = "nixpkgs";
|
|
||||||
flake-compat.follows = "flake-compat";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
flake-compat = {
|
|
||||||
url = "github:edolstra/flake-compat";
|
|
||||||
flake = false;
|
|
||||||
};
|
|
||||||
libnbtplusplus = {
|
libnbtplusplus = {
|
||||||
url = "github:PrismLauncher/libnbtplusplus";
|
url = "github:PrismLauncher/libnbtplusplus";
|
||||||
flake = false;
|
flake = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nix-filter.url = "github:numtide/nix-filter";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Inputs below this are optional and can be removed
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
inputs.fjordlauncher = {
|
||||||
|
url = "github:unmojang/FjordLauncher";
|
||||||
|
inputs = {
|
||||||
|
flake-compat.follows = "";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
|
||||||
|
flake-compat = {
|
||||||
|
url = "github:edolstra/flake-compat";
|
||||||
|
flake = false;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = {
|
outputs = {
|
||||||
flake-parts,
|
self,
|
||||||
pre-commit-hooks,
|
nixpkgs,
|
||||||
|
libnbtplusplus,
|
||||||
|
nix-filter,
|
||||||
...
|
...
|
||||||
} @ inputs:
|
}: let
|
||||||
flake-parts.lib.mkFlake {inherit inputs;} {
|
inherit (nixpkgs) lib;
|
||||||
imports = [
|
|
||||||
pre-commit-hooks.flakeModule
|
|
||||||
|
|
||||||
./nix/dev.nix
|
# While we only officially support aarch and x86_64 on Linux and MacOS,
|
||||||
./nix/distribution.nix
|
# we expose a reasonable amount of other systems for users who want to
|
||||||
];
|
# build for most exotic platforms
|
||||||
|
systems = lib.systems.flakeExposed;
|
||||||
|
|
||||||
systems = [
|
forAllSystems = lib.genAttrs systems;
|
||||||
"x86_64-linux"
|
nixpkgsFor = forAllSystems (system: nixpkgs.legacyPackages.${system});
|
||||||
"aarch64-linux"
|
in {
|
||||||
"x86_64-darwin"
|
checks = forAllSystems (
|
||||||
"aarch64-darwin"
|
system: let
|
||||||
];
|
checks' = nixpkgsFor.${system}.callPackage ./nix/checks.nix {inherit self;};
|
||||||
|
in
|
||||||
|
lib.filterAttrs (_: lib.isDerivation) checks'
|
||||||
|
);
|
||||||
|
|
||||||
|
devShells = forAllSystems (
|
||||||
|
system: let
|
||||||
|
pkgs = nixpkgsFor.${system};
|
||||||
|
in {
|
||||||
|
default = pkgs.mkShell {
|
||||||
|
inputsFrom = [self.packages.${system}.fjordlauncher-unwrapped];
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
ccache
|
||||||
|
ninja
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
formatter = forAllSystems (system: nixpkgsFor.${system}.nixfmt-rfc-style);
|
||||||
|
|
||||||
|
overlays.default = final: prev: let
|
||||||
|
version = builtins.substring 0 8 self.lastModifiedDate or "dirty";
|
||||||
|
in {
|
||||||
|
fjordlauncher-unwrapped = prev.callPackage ./nix/unwrapped.nix {
|
||||||
|
inherit
|
||||||
|
libnbtplusplus
|
||||||
|
nix-filter
|
||||||
|
self
|
||||||
|
version
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
fjordlauncher = final.callPackage ./nix/wrapper.nix {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
packages = forAllSystems (
|
||||||
|
system: let
|
||||||
|
pkgs = nixpkgsFor.${system};
|
||||||
|
|
||||||
|
# Build a scope from our overlay
|
||||||
|
fjordPackages = lib.makeScope pkgs.newScope (final: self.overlays.default final pkgs);
|
||||||
|
|
||||||
|
# Grab our packages from it and set the default
|
||||||
|
packages = {
|
||||||
|
inherit (fjordPackages) fjordlauncher-unwrapped fjordlauncher;
|
||||||
|
default = fjordPackages.fjordlauncher;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
# Only output them if they're available on the current system
|
||||||
|
lib.filterAttrs (_: lib.meta.availableOn pkgs.stdenv.hostPlatform) packages
|
||||||
|
);
|
||||||
|
|
||||||
|
# We put these under legacyPackages as they are meant for CI, not end user consumption
|
||||||
|
legacyPackages = forAllSystems (
|
||||||
|
system: let
|
||||||
|
fjordPackages = self.packages.${system};
|
||||||
|
legacyPackages = self.legacyPackages.${system};
|
||||||
|
in {
|
||||||
|
fjordlauncher-debug = fjordPackages.fjordlauncher.override {
|
||||||
|
fjordlauncher-unwrapped = legacyPackages.fjordlauncher-unwrapped-debug;
|
||||||
|
};
|
||||||
|
|
||||||
|
fjordlauncher-unwrapped-debug = fjordPackages.fjordlauncher-unwrapped.overrideAttrs {
|
||||||
|
cmakeBuildType = "Debug";
|
||||||
|
dontStrip = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,9 @@
|
|||||||
id: org.unmojang.FjordLauncher
|
id: org.unmojang.FjordLauncher
|
||||||
runtime: org.kde.Platform
|
runtime: org.kde.Platform
|
||||||
runtime-version: 5.15-23.08
|
runtime-version: 6.7
|
||||||
sdk: org.kde.Sdk
|
sdk: org.kde.Sdk
|
||||||
sdk-extensions:
|
sdk-extensions:
|
||||||
- org.freedesktop.Sdk.Extension.openjdk17
|
- org.freedesktop.Sdk.Extension.openjdk17
|
||||||
- org.freedesktop.Sdk.Extension.openjdk8
|
|
||||||
add-extensions:
|
|
||||||
com.valvesoftware.Steam.Utility.gamescope:
|
|
||||||
version: stable
|
|
||||||
add-ld-path: lib
|
|
||||||
no-autodownload: true
|
|
||||||
autodelete: false
|
|
||||||
directory: utils/gamescope
|
|
||||||
|
|
||||||
command: fjordlauncher
|
command: fjordlauncher
|
||||||
finish-args:
|
finish-args:
|
||||||
@ -25,9 +17,8 @@ finish-args:
|
|||||||
- --filesystem=xdg-run/app/com.discordapp.Discord:create
|
- --filesystem=xdg-run/app/com.discordapp.Discord:create
|
||||||
# Mod drag&drop
|
# Mod drag&drop
|
||||||
- --filesystem=xdg-download:ro
|
- --filesystem=xdg-download:ro
|
||||||
|
# FTBApp import
|
||||||
cleanup:
|
- --filesystem=~/.ftba:ro
|
||||||
- /lib/libGLU*
|
|
||||||
|
|
||||||
modules:
|
modules:
|
||||||
# Might be needed by some Controller mods (see https://github.com/isXander/Controlify/issues/31)
|
# Might be needed by some Controller mods (see https://github.com/isXander/Controlify/issues/31)
|
||||||
@ -41,31 +32,20 @@ modules:
|
|||||||
builddir: true
|
builddir: true
|
||||||
config-opts:
|
config-opts:
|
||||||
- -DLauncher_BUILD_PLATFORM=flatpak
|
- -DLauncher_BUILD_PLATFORM=flatpak
|
||||||
- -DCMAKE_BUILD_TYPE=Release
|
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||||
- -DLauncher_QT_VERSION_MAJOR=5
|
|
||||||
build-options:
|
build-options:
|
||||||
env:
|
env:
|
||||||
JAVA_HOME: /usr/lib/sdk/openjdk17/jvm/openjdk-17
|
JAVA_HOME: /usr/lib/sdk/openjdk17/jvm/openjdk-17
|
||||||
JAVA_COMPILER: /usr/lib/sdk/openjdk17/jvm/openjdk-17/bin/javac
|
JAVA_COMPILER: /usr/lib/sdk/openjdk17/jvm/openjdk-17/bin/javac
|
||||||
|
run-tests: true
|
||||||
sources:
|
sources:
|
||||||
- type: dir
|
- type: dir
|
||||||
path: ../
|
path: ../
|
||||||
|
|
||||||
- name: openjdk
|
|
||||||
buildsystem: simple
|
|
||||||
build-commands:
|
|
||||||
- mkdir -p /app/jdk/
|
|
||||||
- /usr/lib/sdk/openjdk17/install.sh
|
|
||||||
- mv /app/jre /app/jdk/17
|
|
||||||
- /usr/lib/sdk/openjdk8/install.sh
|
|
||||||
- mv /app/jre /app/jdk/8
|
|
||||||
cleanup:
|
|
||||||
- /jre
|
|
||||||
|
|
||||||
- name: glfw
|
- name: glfw
|
||||||
buildsystem: cmake-ninja
|
buildsystem: cmake-ninja
|
||||||
config-opts:
|
config-opts:
|
||||||
- -DCMAKE_BUILD_TYPE=Release
|
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||||
- -DBUILD_SHARED_LIBS:BOOL=ON
|
- -DBUILD_SHARED_LIBS:BOOL=ON
|
||||||
- -DGLFW_USE_WAYLAND:BOOL=ON
|
- -DGLFW_USE_WAYLAND:BOOL=ON
|
||||||
- -DGLFW_BUILD_DOCS:BOOL=OFF
|
- -DGLFW_BUILD_DOCS:BOOL=OFF
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
builds:
|
|
||||||
exclude:
|
|
||||||
- "*.x86_64-darwin.*"
|
|
||||||
include:
|
|
||||||
- "checks.x86_64-linux.*"
|
|
||||||
- "devShells.*.*"
|
|
||||||
- "packages.*.*"
|
|
@ -44,10 +44,11 @@
|
|||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
|
|
||||||
#include "DataMigrationTask.h"
|
#include "DataMigrationTask.h"
|
||||||
|
#include "java/JavaInstallList.h"
|
||||||
#include "net/PasteUpload.h"
|
#include "net/PasteUpload.h"
|
||||||
#include "pathmatcher/MultiMatcher.h"
|
#include "pathmatcher/MultiMatcher.h"
|
||||||
#include "pathmatcher/SimplePrefixMatcher.h"
|
#include "pathmatcher/SimplePrefixMatcher.h"
|
||||||
#include "settings/INIFile.h"
|
#include "tools/GenericProfiler.h"
|
||||||
#include "ui/InstanceWindow.h"
|
#include "ui/InstanceWindow.h"
|
||||||
#include "ui/MainWindow.h"
|
#include "ui/MainWindow.h"
|
||||||
|
|
||||||
@ -66,8 +67,10 @@
|
|||||||
#include "ui/pages/global/MinecraftPage.h"
|
#include "ui/pages/global/MinecraftPage.h"
|
||||||
#include "ui/pages/global/ProxyPage.h"
|
#include "ui/pages/global/ProxyPage.h"
|
||||||
|
|
||||||
|
#include "ui/setupwizard/AutoJavaWizardPage.h"
|
||||||
#include "ui/setupwizard/JavaWizardPage.h"
|
#include "ui/setupwizard/JavaWizardPage.h"
|
||||||
#include "ui/setupwizard/LanguageWizardPage.h"
|
#include "ui/setupwizard/LanguageWizardPage.h"
|
||||||
|
#include "ui/setupwizard/LoginWizardPage.h"
|
||||||
#include "ui/setupwizard/PasteWizardPage.h"
|
#include "ui/setupwizard/PasteWizardPage.h"
|
||||||
#include "ui/setupwizard/SetupWizard.h"
|
#include "ui/setupwizard/SetupWizard.h"
|
||||||
#include "ui/setupwizard/ThemeWizardPage.h"
|
#include "ui/setupwizard/ThemeWizardPage.h"
|
||||||
@ -106,9 +109,7 @@
|
|||||||
#include "icons/IconList.h"
|
#include "icons/IconList.h"
|
||||||
#include "net/HttpMetaCache.h"
|
#include "net/HttpMetaCache.h"
|
||||||
|
|
||||||
#include "ui/GuiUtil.h"
|
#include "java/JavaInstallList.h"
|
||||||
|
|
||||||
#include "java/JavaUtils.h"
|
|
||||||
|
|
||||||
#include "updater/ExternalUpdater.h"
|
#include "updater/ExternalUpdater.h"
|
||||||
|
|
||||||
@ -129,6 +130,7 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys.h>
|
#include <sys.h>
|
||||||
|
#include "SysInfo.h"
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
@ -154,6 +156,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
|
#include <windows.h>
|
||||||
#include "WindowsConsole.h"
|
#include "WindowsConsole.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -239,6 +242,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
{ { { "d", "dir" }, "Use a custom path as application root (use '.' for current directory)", "directory" },
|
{ { { "d", "dir" }, "Use a custom path as application root (use '.' for current directory)", "directory" },
|
||||||
{ { "l", "launch" }, "Launch the specified instance (by instance ID)", "instance" },
|
{ { "l", "launch" }, "Launch the specified instance (by instance ID)", "instance" },
|
||||||
{ { "s", "server" }, "Join the specified server on launch (only valid in combination with --launch)", "address" },
|
{ { "s", "server" }, "Join the specified server on launch (only valid in combination with --launch)", "address" },
|
||||||
|
{ { "w", "world" }, "Join the specified world on launch (only valid in combination with --launch)", "world" },
|
||||||
{ { "a", "profile" }, "Use the account specified by its profile name (only valid in combination with --launch)", "profile" },
|
{ { "a", "profile" }, "Use the account specified by its profile name (only valid in combination with --launch)", "profile" },
|
||||||
{ "alive", "Write a small '" + liveCheckFile + "' file after the launcher starts" },
|
{ "alive", "Write a small '" + liveCheckFile + "' file after the launcher starts" },
|
||||||
{ { "I", "import" }, "Import instance or resource from specified local path or URL", "url" },
|
{ { "I", "import" }, "Import instance or resource from specified local path or URL", "url" },
|
||||||
@ -253,6 +257,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
m_instanceIdToLaunch = parser.value("launch");
|
m_instanceIdToLaunch = parser.value("launch");
|
||||||
m_serverToJoin = parser.value("server");
|
m_serverToJoin = parser.value("server");
|
||||||
|
m_worldToJoin = parser.value("world");
|
||||||
m_profileToUse = parser.value("profile");
|
m_profileToUse = parser.value("profile");
|
||||||
m_liveCheck = parser.isSet("alive");
|
m_liveCheck = parser.isSet("alive");
|
||||||
|
|
||||||
@ -268,7 +273,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// error if --launch is missing with --server or --profile
|
// error if --launch is missing with --server or --profile
|
||||||
if ((!m_serverToJoin.isEmpty() || !m_profileToUse.isEmpty()) && m_instanceIdToLaunch.isEmpty()) {
|
if (((!m_serverToJoin.isEmpty() || !m_worldToJoin.isEmpty()) || !m_profileToUse.isEmpty()) && m_instanceIdToLaunch.isEmpty()) {
|
||||||
std::cerr << "--server and --profile can only be used in combination with --launch!" << std::endl;
|
std::cerr << "--server and --profile can only be used in combination with --launch!" << std::endl;
|
||||||
m_status = Application::Failed;
|
m_status = Application::Failed;
|
||||||
return;
|
return;
|
||||||
@ -295,12 +300,17 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
QString adjustedBy;
|
QString adjustedBy;
|
||||||
QString dataPath;
|
QString dataPath;
|
||||||
// change folder
|
// change folder
|
||||||
|
QString dataDirEnv;
|
||||||
QString dirParam = parser.value("dir");
|
QString dirParam = parser.value("dir");
|
||||||
if (!dirParam.isEmpty()) {
|
if (!dirParam.isEmpty()) {
|
||||||
// the dir param. it makes multimc data path point to whatever the user specified
|
// the dir param. it makes multimc data path point to whatever the user specified
|
||||||
// on command line
|
// on command line
|
||||||
adjustedBy = "Command line";
|
adjustedBy = "Command line";
|
||||||
dataPath = dirParam;
|
dataPath = dirParam;
|
||||||
|
} else if (dataDirEnv = QProcessEnvironment::systemEnvironment().value(QString("%1_DATA_DIR").arg(BuildConfig.LAUNCHER_NAME.toUpper()));
|
||||||
|
!dataDirEnv.isEmpty()) {
|
||||||
|
adjustedBy = "System environment";
|
||||||
|
dataPath = dataDirEnv;
|
||||||
} else {
|
} else {
|
||||||
QDir foo;
|
QDir foo;
|
||||||
if (DesktopServices::isSnap()) {
|
if (DesktopServices::isSnap()) {
|
||||||
@ -313,7 +323,11 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
adjustedBy = "Persistent data path";
|
adjustedBy = "Persistent data path";
|
||||||
|
|
||||||
#ifndef Q_OS_MACOS
|
#ifndef Q_OS_MACOS
|
||||||
if (QFile::exists(FS::PathCombine(m_rootPath, "portable.txt"))) {
|
if (auto portableUserData = FS::PathCombine(m_rootPath, "UserData"); QDir(portableUserData).exists()) {
|
||||||
|
dataPath = portableUserData;
|
||||||
|
adjustedBy = "Portable user data path";
|
||||||
|
m_portable = true;
|
||||||
|
} else if (QFile::exists(FS::PathCombine(m_rootPath, "portable.txt"))) {
|
||||||
dataPath = m_rootPath;
|
dataPath = m_rootPath;
|
||||||
adjustedBy = "Portable data path";
|
adjustedBy = "Portable data path";
|
||||||
m_portable = true;
|
m_portable = true;
|
||||||
@ -379,6 +393,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
if (!m_serverToJoin.isEmpty()) {
|
if (!m_serverToJoin.isEmpty()) {
|
||||||
launch.args["server"] = m_serverToJoin;
|
launch.args["server"] = m_serverToJoin;
|
||||||
|
} else if (!m_worldToJoin.isEmpty()) {
|
||||||
|
launch.args["world"] = m_worldToJoin;
|
||||||
}
|
}
|
||||||
if (!m_profileToUse.isEmpty()) {
|
if (!m_profileToUse.isEmpty()) {
|
||||||
launch.args["profile"] = m_profileToUse;
|
launch.args["profile"] = m_profileToUse;
|
||||||
@ -394,20 +410,15 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
{
|
{
|
||||||
static const QString baseLogFile = BuildConfig.LAUNCHER_NAME + "-%0.log";
|
static const QString baseLogFile = BuildConfig.LAUNCHER_NAME + "-%0.log";
|
||||||
static const QString logBase = FS::PathCombine("logs", baseLogFile);
|
static const QString logBase = FS::PathCombine("logs", baseLogFile);
|
||||||
auto moveFile = [](const QString& oldName, const QString& newName) {
|
|
||||||
QFile::remove(newName);
|
|
||||||
QFile::copy(oldName, newName);
|
|
||||||
QFile::remove(oldName);
|
|
||||||
};
|
|
||||||
if (FS::ensureFolderPathExists("logs")) { // if this did not fail
|
if (FS::ensureFolderPathExists("logs")) { // if this did not fail
|
||||||
for (auto i = 0; i <= 4; i++)
|
for (auto i = 0; i <= 4; i++)
|
||||||
if (auto oldName = baseLogFile.arg(i);
|
if (auto oldName = baseLogFile.arg(i);
|
||||||
QFile::exists(oldName)) // do not pointlessly delete new files if the old ones are not there
|
QFile::exists(oldName)) // do not pointlessly delete new files if the old ones are not there
|
||||||
moveFile(oldName, logBase.arg(i));
|
FS::move(oldName, logBase.arg(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i = 4; i > 0; i--)
|
for (auto i = 4; i > 0; i--)
|
||||||
moveFile(logBase.arg(i - 1), logBase.arg(i));
|
FS::move(logBase.arg(i - 1), logBase.arg(i));
|
||||||
|
|
||||||
logFile = std::unique_ptr<QFile>(new QFile(logBase.arg(0)));
|
logFile = std::unique_ptr<QFile>(new QFile(logBase.arg(0)));
|
||||||
if (!logFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
if (!logFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||||
@ -447,7 +458,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
// search the dataPath()
|
// search the dataPath()
|
||||||
// seach app data standard path
|
// seach app data standard path
|
||||||
if (!foundLoggingRules && !isPortable() && dirParam.isEmpty()) {
|
if (!foundLoggingRules && !isPortable() && dirParam.isEmpty() && dataDirEnv.isEmpty()) {
|
||||||
logRulesPath = QStandardPaths::locate(QStandardPaths::AppDataLocation, FS::PathCombine("..", logRulesFile));
|
logRulesPath = QStandardPaths::locate(QStandardPaths::AppDataLocation, FS::PathCombine("..", logRulesFile));
|
||||||
if (!logRulesPath.isEmpty()) {
|
if (!logRulesPath.isEmpty()) {
|
||||||
qDebug() << "Found" << logRulesPath << "...";
|
qDebug() << "Found" << logRulesPath << "...";
|
||||||
@ -530,6 +541,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
}
|
}
|
||||||
if (!m_serverToJoin.isEmpty()) {
|
if (!m_serverToJoin.isEmpty()) {
|
||||||
qDebug() << "Address of server to join :" << m_serverToJoin;
|
qDebug() << "Address of server to join :" << m_serverToJoin;
|
||||||
|
} else if (!m_worldToJoin.isEmpty()) {
|
||||||
|
qDebug() << "Name of the world to join :" << m_worldToJoin;
|
||||||
}
|
}
|
||||||
qDebug() << "<> Paths set.";
|
qDebug() << "<> Paths set.";
|
||||||
}
|
}
|
||||||
@ -571,6 +584,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
m_settings->registerSetting("NumberOfConcurrentTasks", 10);
|
m_settings->registerSetting("NumberOfConcurrentTasks", 10);
|
||||||
m_settings->registerSetting("NumberOfConcurrentDownloads", 6);
|
m_settings->registerSetting("NumberOfConcurrentDownloads", 6);
|
||||||
|
m_settings->registerSetting("NumberOfManualRetries", 1);
|
||||||
|
m_settings->registerSetting("RequestTimeout", 60);
|
||||||
|
|
||||||
QString defaultMonospace;
|
QString defaultMonospace;
|
||||||
int defaultSize = 11;
|
int defaultSize = 11;
|
||||||
@ -605,6 +620,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
m_settings->registerSetting("IconsDir", "icons");
|
m_settings->registerSetting("IconsDir", "icons");
|
||||||
m_settings->registerSetting("DownloadsDir", QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
|
m_settings->registerSetting("DownloadsDir", QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
|
||||||
m_settings->registerSetting("DownloadsDirWatchRecursive", false);
|
m_settings->registerSetting("DownloadsDirWatchRecursive", false);
|
||||||
|
m_settings->registerSetting("SkinsDir", "skins");
|
||||||
|
m_settings->registerSetting("JavaDir", "java");
|
||||||
|
|
||||||
// Editors
|
// Editors
|
||||||
m_settings->registerSetting("JsonEditor", QString());
|
m_settings->registerSetting("JsonEditor", QString());
|
||||||
@ -633,7 +650,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
// Memory
|
// Memory
|
||||||
m_settings->registerSetting({ "MinMemAlloc", "MinMemoryAlloc" }, 512);
|
m_settings->registerSetting({ "MinMemAlloc", "MinMemoryAlloc" }, 512);
|
||||||
m_settings->registerSetting({ "MaxMemAlloc", "MaxMemoryAlloc" }, suitableMaxMem());
|
m_settings->registerSetting({ "MaxMemAlloc", "MaxMemoryAlloc" }, SysInfo::suitableMaxMem());
|
||||||
m_settings->registerSetting("PermGen", 128);
|
m_settings->registerSetting("PermGen", 128);
|
||||||
|
|
||||||
// Java Settings
|
// Java Settings
|
||||||
@ -647,6 +664,10 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
m_settings->registerSetting("JvmArgs", "");
|
m_settings->registerSetting("JvmArgs", "");
|
||||||
m_settings->registerSetting("IgnoreJavaCompatibility", false);
|
m_settings->registerSetting("IgnoreJavaCompatibility", false);
|
||||||
m_settings->registerSetting("IgnoreJavaWizard", false);
|
m_settings->registerSetting("IgnoreJavaWizard", false);
|
||||||
|
auto defaultEnableAutoJava = m_settings->get("JavaPath").toString().isEmpty();
|
||||||
|
m_settings->registerSetting("AutomaticJavaSwitch", defaultEnableAutoJava);
|
||||||
|
m_settings->registerSetting("AutomaticJavaDownload", defaultEnableAutoJava);
|
||||||
|
m_settings->registerSetting("UserAskedAboutAutomaticJavaDownload", false);
|
||||||
|
|
||||||
// Legacy settings
|
// Legacy settings
|
||||||
m_settings->registerSetting("OnlineFixes", true);
|
m_settings->registerSetting("OnlineFixes", true);
|
||||||
@ -657,10 +678,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);
|
||||||
@ -671,6 +693,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
// Minecraft mods
|
// Minecraft mods
|
||||||
m_settings->registerSetting("ModMetadataDisabled", false);
|
m_settings->registerSetting("ModMetadataDisabled", false);
|
||||||
m_settings->registerSetting("ModDependenciesDisabled", false);
|
m_settings->registerSetting("ModDependenciesDisabled", false);
|
||||||
|
m_settings->registerSetting("SkipModpackUpdatePrompt", false);
|
||||||
|
|
||||||
// Missing authlib-injector behavior
|
// Missing authlib-injector behavior
|
||||||
m_settings->registerSetting("MissingAuthlibInjectorBehavior", MissingAuthlibInjectorBehavior::Ask);
|
m_settings->registerSetting("MissingAuthlibInjectorBehavior", MissingAuthlibInjectorBehavior::Ask);
|
||||||
@ -687,6 +710,9 @@ 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("ToolbarsLocked", false);
|
m_settings->registerSetting("ToolbarsLocked", false);
|
||||||
|
|
||||||
@ -773,6 +799,9 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
// FTBApp instances
|
// FTBApp instances
|
||||||
m_settings->registerSetting("FTBAppInstancesPath", "");
|
m_settings->registerSetting("FTBAppInstancesPath", "");
|
||||||
|
|
||||||
|
// Custom Technic Client ID
|
||||||
|
m_settings->registerSetting("TechnicClientID", "");
|
||||||
|
|
||||||
// Init page provider
|
// Init page provider
|
||||||
{
|
{
|
||||||
m_globalSettingsProvider = std::make_shared<GenericPageProvider>(tr("Settings"));
|
m_globalSettingsProvider = std::make_shared<GenericPageProvider>(tr("Settings"));
|
||||||
@ -826,7 +855,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
m_icons.reset(new IconList(instFolders, setting->get().toString()));
|
m_icons.reset(new IconList(instFolders, setting->get().toString()));
|
||||||
connect(setting.get(), &Setting::SettingChanged,
|
connect(setting.get(), &Setting::SettingChanged,
|
||||||
[&](const Setting&, QVariant value) { m_icons->directoryChanged(value.toString()); });
|
[&](const Setting&, QVariant value) { m_icons->directoryChanged(value.toString()); });
|
||||||
qDebug() << "<> Instance icons intialized.";
|
qDebug() << "<> Instance icons initialized.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Themes
|
// Themes
|
||||||
@ -863,25 +892,19 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
{
|
{
|
||||||
m_metacache.reset(new HttpMetaCache("metacache"));
|
m_metacache.reset(new HttpMetaCache("metacache"));
|
||||||
m_metacache->addBase("asset_indexes", QDir("assets/indexes").absolutePath());
|
m_metacache->addBase("asset_indexes", QDir("assets/indexes").absolutePath());
|
||||||
m_metacache->addBase("asset_objects", QDir("assets/objects").absolutePath());
|
|
||||||
m_metacache->addBase("versions", QDir("versions").absolutePath());
|
|
||||||
m_metacache->addBase("libraries", QDir("libraries").absolutePath());
|
m_metacache->addBase("libraries", QDir("libraries").absolutePath());
|
||||||
m_metacache->addBase("minecraftforge", QDir("mods/minecraftforge").absolutePath());
|
|
||||||
m_metacache->addBase("fmllibs", QDir("mods/minecraftforge/libs").absolutePath());
|
m_metacache->addBase("fmllibs", QDir("mods/minecraftforge/libs").absolutePath());
|
||||||
m_metacache->addBase("liteloader", QDir("mods/liteloader").absolutePath());
|
|
||||||
m_metacache->addBase("general", QDir("cache").absolutePath());
|
m_metacache->addBase("general", QDir("cache").absolutePath());
|
||||||
m_metacache->addBase("ATLauncherPacks", QDir("cache/ATLauncherPacks").absolutePath());
|
m_metacache->addBase("ATLauncherPacks", QDir("cache/ATLauncherPacks").absolutePath());
|
||||||
m_metacache->addBase("FTBPacks", QDir("cache/FTBPacks").absolutePath());
|
m_metacache->addBase("FTBPacks", QDir("cache/FTBPacks").absolutePath());
|
||||||
m_metacache->addBase("ModpacksCHPacks", QDir("cache/ModpacksCHPacks").absolutePath());
|
|
||||||
m_metacache->addBase("TechnicPacks", QDir("cache/TechnicPacks").absolutePath());
|
m_metacache->addBase("TechnicPacks", QDir("cache/TechnicPacks").absolutePath());
|
||||||
m_metacache->addBase("FlamePacks", QDir("cache/FlamePacks").absolutePath());
|
m_metacache->addBase("FlamePacks", QDir("cache/FlamePacks").absolutePath());
|
||||||
m_metacache->addBase("FlameMods", QDir("cache/FlameMods").absolutePath());
|
m_metacache->addBase("FlameMods", QDir("cache/FlameMods").absolutePath());
|
||||||
m_metacache->addBase("ModrinthPacks", QDir("cache/ModrinthPacks").absolutePath());
|
m_metacache->addBase("ModrinthPacks", QDir("cache/ModrinthPacks").absolutePath());
|
||||||
m_metacache->addBase("ModrinthModpacks", QDir("cache/ModrinthModpacks").absolutePath());
|
m_metacache->addBase("ModrinthModpacks", QDir("cache/ModrinthModpacks").absolutePath());
|
||||||
m_metacache->addBase("root", QDir::currentPath());
|
|
||||||
m_metacache->addBase("translations", QDir("translations").absolutePath());
|
m_metacache->addBase("translations", QDir("translations").absolutePath());
|
||||||
m_metacache->addBase("icons", QDir("cache/icons").absolutePath());
|
|
||||||
m_metacache->addBase("meta", QDir("meta").absolutePath());
|
m_metacache->addBase("meta", QDir("meta").absolutePath());
|
||||||
|
m_metacache->addBase("java", QDir("cache/java").absolutePath());
|
||||||
m_metacache->Load();
|
m_metacache->Load();
|
||||||
qDebug() << "<> Cache initialized.";
|
qDebug() << "<> Cache initialized.";
|
||||||
}
|
}
|
||||||
@ -892,6 +915,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
// FIXME: what to do with these?
|
// FIXME: what to do with these?
|
||||||
m_profilers.insert("jprofiler", std::shared_ptr<BaseProfilerFactory>(new JProfilerFactory()));
|
m_profilers.insert("jprofiler", std::shared_ptr<BaseProfilerFactory>(new JProfilerFactory()));
|
||||||
m_profilers.insert("jvisualvm", std::shared_ptr<BaseProfilerFactory>(new JVisualVMFactory()));
|
m_profilers.insert("jvisualvm", std::shared_ptr<BaseProfilerFactory>(new JVisualVMFactory()));
|
||||||
|
m_profilers.insert("generic", std::shared_ptr<BaseProfilerFactory>(new GenericProfilerFactory()));
|
||||||
for (auto profiler : m_profilers.values()) {
|
for (auto profiler : m_profilers.values()) {
|
||||||
profiler->registerSettings(m_settings);
|
profiler->registerSettings(m_settings);
|
||||||
}
|
}
|
||||||
@ -1004,7 +1028,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
"\n"
|
"\n"
|
||||||
"You are now running %1 .\n"
|
"You are now running %1 .\n"
|
||||||
"Check the Fjord Launcher updater log at: \n"
|
"Check the Fjord Launcher updater log at: \n"
|
||||||
"%1\n"
|
"%2\n"
|
||||||
"for details.")
|
"for details.")
|
||||||
.arg(BuildConfig.printableVersionString())
|
.arg(BuildConfig.printableVersionString())
|
||||||
.arg(update_log_path);
|
.arg(update_log_path);
|
||||||
@ -1020,7 +1044,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// notify user if /tmp is mounted with `noexec` (#1693)
|
// notify user if /tmp is mounted with `noexec` (#1693)
|
||||||
{
|
QString jvmArgs = m_settings->get("JvmArgs").toString();
|
||||||
|
if (jvmArgs.indexOf("java.io.tmpdir") == -1) { /* java.io.tmpdir is a valid workaround, so don't annoy */
|
||||||
bool is_tmp_noexec = false;
|
bool is_tmp_noexec = false;
|
||||||
|
|
||||||
#if defined(Q_OS_LINUX)
|
#if defined(Q_OS_LINUX)
|
||||||
@ -1040,7 +1065,11 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
if (is_tmp_noexec) {
|
if (is_tmp_noexec) {
|
||||||
auto infoMsg =
|
auto infoMsg =
|
||||||
tr("Your /tmp directory is currently mounted with the 'noexec' flag enabled.\n"
|
tr("Your /tmp directory is currently mounted with the 'noexec' flag enabled.\n"
|
||||||
"Some versions of Minecraft may not launch.\n");
|
"Some versions of Minecraft may not launch.\n"
|
||||||
|
"\n"
|
||||||
|
"You may solve this issue by remounting /tmp as 'exec' or setting "
|
||||||
|
"the java.io.tmpdir JVM argument to a writeable directory in a "
|
||||||
|
"filesystem where the 'exec' flag is set (e.g., /home/user/.local/tmp)\n");
|
||||||
auto msgBox = new QMessageBox(QMessageBox::Information, tr("Incompatible system configuration"), infoMsg, QMessageBox::Ok);
|
auto msgBox = new QMessageBox(QMessageBox::Information, tr("Incompatible system configuration"), infoMsg, QMessageBox::Ok);
|
||||||
msgBox->setDefaultButton(QMessageBox::Ok);
|
msgBox->setDefaultButton(QMessageBox::Ok);
|
||||||
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
@ -1078,13 +1107,15 @@ bool Application::createSetupWizard()
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}();
|
}();
|
||||||
|
bool askjava = BuildConfig.JAVA_DOWNLOADER_ENABLED && !javaRequired && !m_settings->get("AutomaticJavaDownload").toBool() &&
|
||||||
|
!m_settings->get("AutomaticJavaSwitch").toBool() && !m_settings->get("UserAskedAboutAutomaticJavaDownload").toBool();
|
||||||
bool languageRequired = settings()->get("Language").toString().isEmpty();
|
bool languageRequired = settings()->get("Language").toString().isEmpty();
|
||||||
bool pasteInterventionRequired = settings()->get("PastebinURL") != "";
|
bool pasteInterventionRequired = settings()->get("PastebinURL") != "";
|
||||||
bool validWidgets = m_themeManager->isValidApplicationTheme(settings()->get("ApplicationTheme").toString());
|
bool validWidgets = m_themeManager->isValidApplicationTheme(settings()->get("ApplicationTheme").toString());
|
||||||
bool validIcons = m_themeManager->isValidIconTheme(settings()->get("IconTheme").toString());
|
bool validIcons = m_themeManager->isValidIconTheme(settings()->get("IconTheme").toString());
|
||||||
|
bool login = !m_accounts->anyAccountIsValid() && capabilities() & Application::SupportsMSA;
|
||||||
bool themeInterventionRequired = !validWidgets || !validIcons;
|
bool themeInterventionRequired = !validWidgets || !validIcons;
|
||||||
bool wizardRequired = javaRequired || languageRequired || pasteInterventionRequired || themeInterventionRequired;
|
bool wizardRequired = javaRequired || languageRequired || pasteInterventionRequired || themeInterventionRequired || askjava || login;
|
||||||
|
|
||||||
if (wizardRequired) {
|
if (wizardRequired) {
|
||||||
// set default theme after going into theme wizard
|
// set default theme after going into theme wizard
|
||||||
if (!validIcons)
|
if (!validIcons)
|
||||||
@ -1101,6 +1132,8 @@ bool Application::createSetupWizard()
|
|||||||
|
|
||||||
if (javaRequired) {
|
if (javaRequired) {
|
||||||
m_setupWizard->addPage(new JavaWizardPage(m_setupWizard));
|
m_setupWizard->addPage(new JavaWizardPage(m_setupWizard));
|
||||||
|
} else if (askjava) {
|
||||||
|
m_setupWizard->addPage(new AutoJavaWizardPage(m_setupWizard));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pasteInterventionRequired) {
|
if (pasteInterventionRequired) {
|
||||||
@ -1111,11 +1144,14 @@ bool Application::createSetupWizard()
|
|||||||
m_setupWizard->addPage(new ThemeWizardPage(m_setupWizard));
|
m_setupWizard->addPage(new ThemeWizardPage(m_setupWizard));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (login) {
|
||||||
|
m_setupWizard->addPage(new LoginWizardPage(m_setupWizard));
|
||||||
|
}
|
||||||
connect(m_setupWizard, &QDialog::finished, this, &Application::setupWizardFinished);
|
connect(m_setupWizard, &QDialog::finished, this, &Application::setupWizardFinished);
|
||||||
m_setupWizard->show();
|
m_setupWizard->show();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
return wizardRequired || login;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Application::updaterEnabled()
|
bool Application::updaterEnabled()
|
||||||
@ -1171,14 +1207,17 @@ void Application::performMainStartupAction()
|
|||||||
if (!m_instanceIdToLaunch.isEmpty()) {
|
if (!m_instanceIdToLaunch.isEmpty()) {
|
||||||
auto inst = instances()->getInstanceById(m_instanceIdToLaunch);
|
auto inst = instances()->getInstanceById(m_instanceIdToLaunch);
|
||||||
if (inst) {
|
if (inst) {
|
||||||
MinecraftServerTargetPtr serverToJoin = nullptr;
|
MinecraftTarget::Ptr targetToJoin = nullptr;
|
||||||
MinecraftAccountPtr accountToUse = nullptr;
|
MinecraftAccountPtr accountToUse = nullptr;
|
||||||
|
|
||||||
qDebug() << "<> Instance" << m_instanceIdToLaunch << "launching";
|
qDebug() << "<> Instance" << m_instanceIdToLaunch << "launching";
|
||||||
if (!m_serverToJoin.isEmpty()) {
|
if (!m_serverToJoin.isEmpty()) {
|
||||||
// FIXME: validate the server string
|
// FIXME: validate the server string
|
||||||
serverToJoin.reset(new MinecraftServerTarget(MinecraftServerTarget::parse(m_serverToJoin)));
|
targetToJoin.reset(new MinecraftTarget(MinecraftTarget::parse(m_serverToJoin, false)));
|
||||||
qDebug() << " Launching with server" << m_serverToJoin;
|
qDebug() << " Launching with server" << m_serverToJoin;
|
||||||
|
} else if (!m_worldToJoin.isEmpty()) {
|
||||||
|
targetToJoin.reset(new MinecraftTarget(MinecraftTarget::parse(m_worldToJoin, true)));
|
||||||
|
qDebug() << " Launching with world" << m_worldToJoin;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_profileToUse.isEmpty()) {
|
if (!m_profileToUse.isEmpty()) {
|
||||||
@ -1189,7 +1228,7 @@ void Application::performMainStartupAction()
|
|||||||
qDebug() << " Launching with account" << m_profileToUse;
|
qDebug() << " Launching with account" << m_profileToUse;
|
||||||
}
|
}
|
||||||
|
|
||||||
launch(inst, true, false, serverToJoin, accountToUse);
|
launch(inst, true, false, targetToJoin, accountToUse);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1245,6 +1284,12 @@ void Application::performMainStartupAction()
|
|||||||
qDebug() << "<> Updater started.";
|
qDebug() << "<> Updater started.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ // delete instances tmp dirctory
|
||||||
|
auto instDir = m_settings->get("InstanceDir").toString();
|
||||||
|
const QString tempRoot = FS::PathCombine(instDir, ".tmp");
|
||||||
|
FS::deletePath(tempRoot);
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_urlsToImport.isEmpty()) {
|
if (!m_urlsToImport.isEmpty()) {
|
||||||
qDebug() << "<> Importing from url:" << m_urlsToImport;
|
qDebug() << "<> Importing from url:" << m_urlsToImport;
|
||||||
m_mainWindow->processURLs(m_urlsToImport);
|
m_mainWindow->processURLs(m_urlsToImport);
|
||||||
@ -1276,16 +1321,23 @@ Application::~Application()
|
|||||||
|
|
||||||
void Application::messageReceived(const QByteArray& message)
|
void Application::messageReceived(const QByteArray& message)
|
||||||
{
|
{
|
||||||
if (status() != Initialized) {
|
|
||||||
qDebug() << "Received message" << message << "while still initializing. It will be ignored.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ApplicationMessage received;
|
ApplicationMessage received;
|
||||||
received.parse(message);
|
received.parse(message);
|
||||||
|
|
||||||
auto& command = received.command;
|
auto& command = received.command;
|
||||||
|
|
||||||
|
if (status() != Initialized) {
|
||||||
|
bool isLoginAtempt = false;
|
||||||
|
if (command == "import") {
|
||||||
|
QString url = received.args["url"];
|
||||||
|
isLoginAtempt = !url.isEmpty() && normalizeImportUrl(url).scheme() == BuildConfig.LAUNCHER_APP_BINARY_NAME;
|
||||||
|
}
|
||||||
|
if (!isLoginAtempt) {
|
||||||
|
qDebug() << "Received message" << message << "while still initializing. It will be ignored.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (command == "activate") {
|
if (command == "activate") {
|
||||||
showMainWindow();
|
showMainWindow();
|
||||||
} else if (command == "import") {
|
} else if (command == "import") {
|
||||||
@ -1298,6 +1350,7 @@ void Application::messageReceived(const QByteArray& message)
|
|||||||
} else if (command == "launch") {
|
} else if (command == "launch") {
|
||||||
QString id = received.args["id"];
|
QString id = received.args["id"];
|
||||||
QString server = received.args["server"];
|
QString server = received.args["server"];
|
||||||
|
QString world = received.args["world"];
|
||||||
QString profile = received.args["profile"];
|
QString profile = received.args["profile"];
|
||||||
|
|
||||||
InstancePtr instance;
|
InstancePtr instance;
|
||||||
@ -1312,11 +1365,12 @@ void Application::messageReceived(const QByteArray& message)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MinecraftServerTargetPtr serverObject = nullptr;
|
MinecraftTarget::Ptr serverObject = nullptr;
|
||||||
if (!server.isEmpty()) {
|
if (!server.isEmpty()) {
|
||||||
serverObject = std::make_shared<MinecraftServerTarget>(MinecraftServerTarget::parse(server));
|
serverObject = std::make_shared<MinecraftTarget>(MinecraftTarget::parse(server, false));
|
||||||
|
} else if (!world.isEmpty()) {
|
||||||
|
serverObject = std::make_shared<MinecraftTarget>(MinecraftTarget::parse(world, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
MinecraftAccountPtr accountObject;
|
MinecraftAccountPtr accountObject;
|
||||||
if (!profile.isEmpty()) {
|
if (!profile.isEmpty()) {
|
||||||
accountObject = accounts()->getAccountByProfileName(profile);
|
accountObject = accounts()->getAccountByProfileName(profile);
|
||||||
@ -1365,11 +1419,7 @@ bool Application::openJsonEditor(const QString& filename)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Application::launch(InstancePtr instance,
|
bool Application::launch(InstancePtr instance, bool online, bool demo, MinecraftTarget::Ptr targetToJoin, MinecraftAccountPtr accountToUse)
|
||||||
bool online,
|
|
||||||
bool demo,
|
|
||||||
MinecraftServerTargetPtr serverToJoin,
|
|
||||||
MinecraftAccountPtr accountToUse)
|
|
||||||
{
|
{
|
||||||
if (m_updateRunning) {
|
if (m_updateRunning) {
|
||||||
qDebug() << "Cannot launch instances while an update is running. Please try again when updates are completed.";
|
qDebug() << "Cannot launch instances while an update is running. Please try again when updates are completed.";
|
||||||
@ -1387,7 +1437,7 @@ bool Application::launch(InstancePtr instance,
|
|||||||
controller->setOnline(online);
|
controller->setOnline(online);
|
||||||
controller->setDemo(demo);
|
controller->setDemo(demo);
|
||||||
controller->setProfiler(profilers().value(instance->settings()->get("Profiler").toString(), nullptr).get());
|
controller->setProfiler(profilers().value(instance->settings()->get("Profiler").toString(), nullptr).get());
|
||||||
controller->setServerToJoin(serverToJoin);
|
controller->setTargetToJoin(targetToJoin);
|
||||||
controller->setAccountToUse(accountToUse);
|
controller->setAccountToUse(accountToUse);
|
||||||
if (window) {
|
if (window) {
|
||||||
controller->setParentWidget(window);
|
controller->setParentWidget(window);
|
||||||
@ -1766,20 +1816,6 @@ QString Application::getUserAgentUncached()
|
|||||||
return BuildConfig.USER_AGENT_UNCACHED;
|
return BuildConfig.USER_AGENT_UNCACHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Application::suitableMaxMem()
|
|
||||||
{
|
|
||||||
float totalRAM = (float)Sys::getSystemRam() / (float)Sys::mebibyte;
|
|
||||||
int maxMemoryAlloc;
|
|
||||||
|
|
||||||
// If totalRAM < 6GB, use (totalRAM / 1.5), else 4GB
|
|
||||||
if (totalRAM < (4096 * 1.5))
|
|
||||||
maxMemoryAlloc = (int)(totalRAM / 1.5);
|
|
||||||
else
|
|
||||||
maxMemoryAlloc = 4096;
|
|
||||||
|
|
||||||
return maxMemoryAlloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Application::handleDataMigration(const QString& currentData,
|
bool Application::handleDataMigration(const QString& currentData,
|
||||||
const QString& oldData,
|
const QString& oldData,
|
||||||
const QString& name,
|
const QString& name,
|
||||||
@ -1886,3 +1922,8 @@ QUrl Application::normalizeImportUrl(QString const& url)
|
|||||||
return QUrl::fromUserInput(url);
|
return QUrl::fromUserInput(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QString Application::javaPath()
|
||||||
|
{
|
||||||
|
return m_settings->get("JavaDir").toString();
|
||||||
|
}
|
||||||
|
@ -47,8 +47,7 @@
|
|||||||
|
|
||||||
#include <BaseInstance.h>
|
#include <BaseInstance.h>
|
||||||
|
|
||||||
#include "minecraft/launch/MinecraftServerTarget.h"
|
#include "minecraft/launch/MinecraftTarget.h"
|
||||||
#include "ui/themes/CatPack.h"
|
|
||||||
|
|
||||||
class LaunchController;
|
class LaunchController;
|
||||||
class LocalPeer;
|
class LocalPeer;
|
||||||
@ -82,6 +81,12 @@ class Index;
|
|||||||
#endif
|
#endif
|
||||||
#define APPLICATION (static_cast<Application*>(QCoreApplication::instance()))
|
#define APPLICATION (static_cast<Application*>(QCoreApplication::instance()))
|
||||||
|
|
||||||
|
// Used for checking if is a test
|
||||||
|
#if defined(APPLICATION_DYN)
|
||||||
|
#undef APPLICATION_DYN
|
||||||
|
#endif
|
||||||
|
#define APPLICATION_DYN (dynamic_cast<Application*>(QCoreApplication::instance()))
|
||||||
|
|
||||||
class Application : public QApplication {
|
class Application : public QApplication {
|
||||||
// friends for the purpose of limiting access to deprecated stuff
|
// friends for the purpose of limiting access to deprecated stuff
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -162,6 +167,9 @@ class Application : public QApplication {
|
|||||||
/// the data path the application is using
|
/// the data path the application is using
|
||||||
const QString& dataRoot() { return m_dataPath; }
|
const QString& dataRoot() { return m_dataPath; }
|
||||||
|
|
||||||
|
/// the java installed path the application is using
|
||||||
|
const QString javaPath();
|
||||||
|
|
||||||
bool isPortable() { return m_portable; }
|
bool isPortable() { return m_portable; }
|
||||||
|
|
||||||
const Capabilities capabilities() { return m_capabilities; }
|
const Capabilities capabilities() { return m_capabilities; }
|
||||||
@ -180,8 +188,6 @@ class Application : public QApplication {
|
|||||||
|
|
||||||
void ShowGlobalSettings(class QWidget* parent, QString open_page = QString());
|
void ShowGlobalSettings(class QWidget* parent, QString open_page = QString());
|
||||||
|
|
||||||
int suitableMaxMem();
|
|
||||||
|
|
||||||
bool updaterEnabled();
|
bool updaterEnabled();
|
||||||
QString updaterBinaryName();
|
QString updaterBinaryName();
|
||||||
|
|
||||||
@ -193,6 +199,8 @@ class Application : public QApplication {
|
|||||||
void globalSettingsClosed();
|
void globalSettingsClosed();
|
||||||
int currentCatChanged(int index);
|
int currentCatChanged(int index);
|
||||||
|
|
||||||
|
void oauthReplyRecieved(QVariantMap);
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
void clickedOnDock();
|
void clickedOnDock();
|
||||||
#endif
|
#endif
|
||||||
@ -201,7 +209,7 @@ class Application : public QApplication {
|
|||||||
bool launch(InstancePtr instance,
|
bool launch(InstancePtr instance,
|
||||||
bool online = true,
|
bool online = true,
|
||||||
bool demo = false,
|
bool demo = false,
|
||||||
MinecraftServerTargetPtr serverToJoin = nullptr,
|
MinecraftTarget::Ptr targetToJoin = nullptr,
|
||||||
MinecraftAccountPtr accountToUse = nullptr);
|
MinecraftAccountPtr accountToUse = nullptr);
|
||||||
bool kill(InstancePtr instance);
|
bool kill(InstancePtr instance);
|
||||||
void closeCurrentWindow();
|
void closeCurrentWindow();
|
||||||
@ -289,6 +297,7 @@ class Application : public QApplication {
|
|||||||
QString m_detectedOpenALPath;
|
QString m_detectedOpenALPath;
|
||||||
QString m_instanceIdToLaunch;
|
QString m_instanceIdToLaunch;
|
||||||
QString m_serverToJoin;
|
QString m_serverToJoin;
|
||||||
|
QString m_worldToJoin;
|
||||||
QString m_profileToUse;
|
QString m_profileToUse;
|
||||||
bool m_liveCheck = false;
|
bool m_liveCheck = false;
|
||||||
QList<QUrl> m_urlsToImport;
|
QList<QUrl> m_urlsToImport;
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
|
||||||
#include "BaseInstaller.h"
|
#include "BaseInstaller.h"
|
||||||
|
#include "FileSystem.h"
|
||||||
#include "minecraft/MinecraftInstance.h"
|
#include "minecraft/MinecraftInstance.h"
|
||||||
|
|
||||||
BaseInstaller::BaseInstaller() {}
|
BaseInstaller::BaseInstaller() {}
|
||||||
@ -42,7 +43,7 @@ bool BaseInstaller::add(MinecraftInstance* to)
|
|||||||
|
|
||||||
bool BaseInstaller::remove(MinecraftInstance* from)
|
bool BaseInstaller::remove(MinecraftInstance* from)
|
||||||
{
|
{
|
||||||
return QFile::remove(filename(from->instanceRoot()));
|
return FS::deletePath(filename(from->instanceRoot()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BaseInstaller::filename(const QString& root) const
|
QString BaseInstaller::filename(const QString& root) const
|
||||||
|
@ -269,13 +269,18 @@ void BaseInstance::setRunning(bool running)
|
|||||||
|
|
||||||
m_isRunning = running;
|
m_isRunning = running;
|
||||||
|
|
||||||
if (!m_settings->get("RecordGameTime").toBool()) {
|
emit runningStatusChanged(running);
|
||||||
emit runningStatusChanged(running);
|
}
|
||||||
|
|
||||||
|
void BaseInstance::setMinecraftRunning(bool running)
|
||||||
|
{
|
||||||
|
if (!settings()->get("RecordGameTime").toBool()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (running) {
|
if (running) {
|
||||||
m_timeStarted = QDateTime::currentDateTime();
|
m_timeStarted = QDateTime::currentDateTime();
|
||||||
|
setLastLaunch(m_timeStarted.toMSecsSinceEpoch());
|
||||||
} else {
|
} else {
|
||||||
QDateTime timeEnded = QDateTime::currentDateTime();
|
QDateTime timeEnded = QDateTime::currentDateTime();
|
||||||
|
|
||||||
@ -285,8 +290,6 @@ void BaseInstance::setRunning(bool running)
|
|||||||
|
|
||||||
emit propertiesChanged(this);
|
emit propertiesChanged(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit runningStatusChanged(running);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t BaseInstance::totalTimePlayed() const
|
int64_t BaseInstance::totalTimePlayed() const
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
#include "net/Mode.h"
|
#include "net/Mode.h"
|
||||||
|
|
||||||
#include "RuntimeContext.h"
|
#include "RuntimeContext.h"
|
||||||
#include "minecraft/launch/MinecraftServerTarget.h"
|
#include "minecraft/launch/MinecraftTarget.h"
|
||||||
|
|
||||||
class QDir;
|
class QDir;
|
||||||
class Task;
|
class Task;
|
||||||
@ -104,6 +104,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
/// be unique.
|
/// be unique.
|
||||||
virtual QString id() const;
|
virtual QString id() const;
|
||||||
|
|
||||||
|
void setMinecraftRunning(bool running);
|
||||||
void setRunning(bool running);
|
void setRunning(bool running);
|
||||||
bool isRunning() const;
|
bool isRunning() const;
|
||||||
int64_t totalTimePlayed() const;
|
int64_t totalTimePlayed() const;
|
||||||
@ -180,10 +181,10 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
virtual void loadSpecificSettings() = 0;
|
virtual void loadSpecificSettings() = 0;
|
||||||
|
|
||||||
/// returns a valid update task
|
/// returns a valid update task
|
||||||
virtual Task::Ptr createUpdateTask(Net::Mode mode) = 0;
|
virtual QList<Task::Ptr> createUpdateTask() = 0;
|
||||||
|
|
||||||
/// returns a valid launcher (task container)
|
/// returns a valid launcher (task container)
|
||||||
virtual shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) = 0;
|
virtual shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftTarget::Ptr targetToJoin) = 0;
|
||||||
|
|
||||||
/// returns the current launch task (if any)
|
/// returns the current launch task (if any)
|
||||||
shared_qobject_ptr<LaunchTask> getLaunchTask();
|
shared_qobject_ptr<LaunchTask> getLaunchTask();
|
||||||
@ -214,7 +215,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
|
|
||||||
virtual QString typeName() const = 0;
|
virtual QString typeName() const = 0;
|
||||||
|
|
||||||
void updateRuntimeContext();
|
virtual void updateRuntimeContext();
|
||||||
RuntimeContext runtimeContext() const { return m_runtimeContext; }
|
RuntimeContext runtimeContext() const { return m_runtimeContext; }
|
||||||
|
|
||||||
bool hasVersionBroken() const { return m_hasBrokenVersion; }
|
bool hasVersionBroken() const { return m_hasBrokenVersion; }
|
||||||
@ -255,7 +256,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
/**
|
/**
|
||||||
* 'print' a verbose description of the instance into a QStringList
|
* 'print' a verbose description of the instance into a QStringList
|
||||||
*/
|
*/
|
||||||
virtual QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) = 0;
|
virtual QStringList verboseDescription(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin) = 0;
|
||||||
|
|
||||||
Status currentStatus() const;
|
Status currentStatus() const;
|
||||||
|
|
||||||
|
@ -78,6 +78,14 @@ QVariant BaseVersionList::data(const QModelIndex& index, int role) const
|
|||||||
case TypeRole:
|
case TypeRole:
|
||||||
return version->typeString();
|
return version->typeString();
|
||||||
|
|
||||||
|
case JavaMajorRole: {
|
||||||
|
auto major = version->name();
|
||||||
|
if (major.startsWith("java")) {
|
||||||
|
major = "Java " + major.mid(4);
|
||||||
|
}
|
||||||
|
return major;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
@ -110,6 +118,8 @@ QHash<int, QByteArray> BaseVersionList::roleNames() const
|
|||||||
roles.insert(TypeRole, "type");
|
roles.insert(TypeRole, "type");
|
||||||
roles.insert(BranchRole, "branch");
|
roles.insert(BranchRole, "branch");
|
||||||
roles.insert(PathRole, "path");
|
roles.insert(PathRole, "path");
|
||||||
roles.insert(ArchitectureRole, "architecture");
|
roles.insert(JavaNameRole, "javaName");
|
||||||
|
roles.insert(CPUArchitectureRole, "architecture");
|
||||||
|
roles.insert(JavaMajorRole, "javaMajor");
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,9 @@ class BaseVersionList : public QAbstractListModel {
|
|||||||
TypeRole,
|
TypeRole,
|
||||||
BranchRole,
|
BranchRole,
|
||||||
PathRole,
|
PathRole,
|
||||||
ArchitectureRole,
|
JavaNameRole,
|
||||||
|
JavaMajorRole,
|
||||||
|
CPUArchitectureRole,
|
||||||
SortRole
|
SortRole
|
||||||
};
|
};
|
||||||
using RoleList = QList<int>;
|
using RoleList = QList<int>;
|
||||||
|
@ -24,6 +24,8 @@ set(CORE_SOURCES
|
|||||||
NullInstance.h
|
NullInstance.h
|
||||||
MMCZip.h
|
MMCZip.h
|
||||||
MMCZip.cpp
|
MMCZip.cpp
|
||||||
|
Untar.h
|
||||||
|
Untar.cpp
|
||||||
StringUtils.h
|
StringUtils.h
|
||||||
StringUtils.cpp
|
StringUtils.cpp
|
||||||
QVariantUtils.h
|
QVariantUtils.h
|
||||||
@ -135,7 +137,6 @@ set(NET_SOURCES
|
|||||||
net/MetaCacheSink.h
|
net/MetaCacheSink.h
|
||||||
net/Logging.h
|
net/Logging.h
|
||||||
net/Logging.cpp
|
net/Logging.cpp
|
||||||
net/NetAction.h
|
|
||||||
net/NetJob.cpp
|
net/NetJob.cpp
|
||||||
net/NetJob.h
|
net/NetJob.h
|
||||||
net/NetUtils.h
|
net/NetUtils.h
|
||||||
@ -148,7 +149,6 @@ set(NET_SOURCES
|
|||||||
net/HeaderProxy.h
|
net/HeaderProxy.h
|
||||||
net/RawHeaderProxy.h
|
net/RawHeaderProxy.h
|
||||||
net/ApiHeaderProxy.h
|
net/ApiHeaderProxy.h
|
||||||
net/StaticHeaderProxy.h
|
|
||||||
net/ApiDownload.h
|
net/ApiDownload.h
|
||||||
net/ApiDownload.cpp
|
net/ApiDownload.cpp
|
||||||
net/ApiUpload.cpp
|
net/ApiUpload.cpp
|
||||||
@ -169,16 +169,18 @@ set(LAUNCH_SOURCES
|
|||||||
launch/steps/PreLaunchCommand.h
|
launch/steps/PreLaunchCommand.h
|
||||||
launch/steps/TextPrint.cpp
|
launch/steps/TextPrint.cpp
|
||||||
launch/steps/TextPrint.h
|
launch/steps/TextPrint.h
|
||||||
launch/steps/Update.cpp
|
|
||||||
launch/steps/Update.h
|
|
||||||
launch/steps/QuitAfterGameStop.cpp
|
launch/steps/QuitAfterGameStop.cpp
|
||||||
launch/steps/QuitAfterGameStop.h
|
launch/steps/QuitAfterGameStop.h
|
||||||
|
launch/steps/PrintServers.cpp
|
||||||
|
launch/steps/PrintServers.h
|
||||||
launch/LaunchStep.cpp
|
launch/LaunchStep.cpp
|
||||||
launch/LaunchStep.h
|
launch/LaunchStep.h
|
||||||
launch/LaunchTask.cpp
|
launch/LaunchTask.cpp
|
||||||
launch/LaunchTask.h
|
launch/LaunchTask.h
|
||||||
launch/LogModel.cpp
|
launch/LogModel.cpp
|
||||||
launch/LogModel.h
|
launch/LogModel.h
|
||||||
|
launch/TaskStepWrapper.cpp
|
||||||
|
launch/TaskStepWrapper.h
|
||||||
)
|
)
|
||||||
|
|
||||||
# Old update system
|
# Old update system
|
||||||
@ -214,18 +216,18 @@ set(ICONS_SOURCES
|
|||||||
|
|
||||||
# Support for Minecraft instances and launch
|
# Support for Minecraft instances and launch
|
||||||
set(MINECRAFT_SOURCES
|
set(MINECRAFT_SOURCES
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
minecraft/Logging.h
|
||||||
|
minecraft/Logging.cpp
|
||||||
|
|
||||||
# Minecraft support
|
# Minecraft support
|
||||||
minecraft/auth/AccountData.cpp
|
minecraft/auth/AccountData.cpp
|
||||||
minecraft/auth/AccountData.h
|
minecraft/auth/AccountData.h
|
||||||
minecraft/auth/AccountList.cpp
|
minecraft/auth/AccountList.cpp
|
||||||
minecraft/auth/AccountList.h
|
minecraft/auth/AccountList.h
|
||||||
minecraft/auth/AccountTask.cpp
|
|
||||||
minecraft/auth/AccountTask.h
|
|
||||||
minecraft/auth/AuthRequest.cpp
|
|
||||||
minecraft/auth/AuthRequest.h
|
|
||||||
minecraft/auth/AuthSession.cpp
|
minecraft/auth/AuthSession.cpp
|
||||||
minecraft/auth/AuthSession.h
|
minecraft/auth/AuthSession.h
|
||||||
minecraft/auth/AuthStep.cpp
|
|
||||||
minecraft/auth/AuthStep.h
|
minecraft/auth/AuthStep.h
|
||||||
minecraft/auth/MinecraftAccount.cpp
|
minecraft/auth/MinecraftAccount.cpp
|
||||||
minecraft/auth/MinecraftAccount.h
|
minecraft/auth/MinecraftAccount.h
|
||||||
@ -234,35 +236,21 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/auth/Yggdrasil.cpp
|
minecraft/auth/Yggdrasil.cpp
|
||||||
minecraft/auth/Yggdrasil.h
|
minecraft/auth/Yggdrasil.h
|
||||||
|
|
||||||
minecraft/auth/flows/AuthFlow.cpp
|
minecraft/auth/AuthFlow.cpp
|
||||||
minecraft/auth/flows/AuthFlow.h
|
minecraft/auth/AuthFlow.h
|
||||||
minecraft/auth/flows/AuthlibInjector.cpp
|
|
||||||
minecraft/auth/flows/AuthlibInjector.h
|
|
||||||
minecraft/auth/flows/Mojang.cpp
|
|
||||||
minecraft/auth/flows/Mojang.h
|
|
||||||
minecraft/auth/flows/MSA.cpp
|
|
||||||
minecraft/auth/flows/MSA.h
|
|
||||||
minecraft/auth/flows/Offline.cpp
|
|
||||||
minecraft/auth/flows/Offline.h
|
|
||||||
|
|
||||||
minecraft/auth/steps/AuthlibInjectorMetadataStep.cpp
|
|
||||||
minecraft/auth/steps/AuthlibInjectorMetadataStep.h
|
|
||||||
minecraft/auth/steps/EntitlementsStep.cpp
|
minecraft/auth/steps/EntitlementsStep.cpp
|
||||||
minecraft/auth/steps/EntitlementsStep.h
|
minecraft/auth/steps/EntitlementsStep.h
|
||||||
minecraft/auth/steps/GetSkinStep.cpp
|
minecraft/auth/steps/GetSkinStep.cpp
|
||||||
minecraft/auth/steps/GetSkinStep.h
|
minecraft/auth/steps/GetSkinStep.h
|
||||||
minecraft/auth/steps/LauncherLoginStep.cpp
|
minecraft/auth/steps/LauncherLoginStep.cpp
|
||||||
minecraft/auth/steps/LauncherLoginStep.h
|
minecraft/auth/steps/LauncherLoginStep.h
|
||||||
minecraft/auth/steps/MigrationEligibilityStep.cpp
|
|
||||||
minecraft/auth/steps/MigrationEligibilityStep.h
|
|
||||||
minecraft/auth/steps/MinecraftProfileStep.cpp
|
minecraft/auth/steps/MinecraftProfileStep.cpp
|
||||||
minecraft/auth/steps/MinecraftProfileStep.h
|
minecraft/auth/steps/MinecraftProfileStep.h
|
||||||
minecraft/auth/steps/MinecraftProfileStepMojang.cpp
|
minecraft/auth/steps/MSADeviceCodeStep.cpp
|
||||||
minecraft/auth/steps/MinecraftProfileStepMojang.h
|
minecraft/auth/steps/MSADeviceCodeStep.h
|
||||||
minecraft/auth/steps/MSAStep.cpp
|
minecraft/auth/steps/MSAStep.cpp
|
||||||
minecraft/auth/steps/MSAStep.h
|
minecraft/auth/steps/MSAStep.h
|
||||||
minecraft/auth/steps/OfflineStep.cpp
|
|
||||||
minecraft/auth/steps/OfflineStep.h
|
|
||||||
minecraft/auth/steps/XboxAuthorizationStep.cpp
|
minecraft/auth/steps/XboxAuthorizationStep.cpp
|
||||||
minecraft/auth/steps/XboxAuthorizationStep.h
|
minecraft/auth/steps/XboxAuthorizationStep.h
|
||||||
minecraft/auth/steps/XboxProfileStep.cpp
|
minecraft/auth/steps/XboxProfileStep.cpp
|
||||||
@ -294,8 +282,8 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/launch/ExtractNatives.h
|
minecraft/launch/ExtractNatives.h
|
||||||
minecraft/launch/LauncherPartLaunch.cpp
|
minecraft/launch/LauncherPartLaunch.cpp
|
||||||
minecraft/launch/LauncherPartLaunch.h
|
minecraft/launch/LauncherPartLaunch.h
|
||||||
minecraft/launch/MinecraftServerTarget.cpp
|
minecraft/launch/MinecraftTarget.cpp
|
||||||
minecraft/launch/MinecraftServerTarget.h
|
minecraft/launch/MinecraftTarget.h
|
||||||
minecraft/launch/PrintInstanceInfo.cpp
|
minecraft/launch/PrintInstanceInfo.cpp
|
||||||
minecraft/launch/PrintInstanceInfo.h
|
minecraft/launch/PrintInstanceInfo.h
|
||||||
minecraft/launch/ReconstructAssets.cpp
|
minecraft/launch/ReconstructAssets.cpp
|
||||||
@ -304,6 +292,8 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/launch/ScanModFolders.h
|
minecraft/launch/ScanModFolders.h
|
||||||
minecraft/launch/VerifyJavaInstall.cpp
|
minecraft/launch/VerifyJavaInstall.cpp
|
||||||
minecraft/launch/VerifyJavaInstall.h
|
minecraft/launch/VerifyJavaInstall.h
|
||||||
|
minecraft/launch/AutoInstallJava.cpp
|
||||||
|
minecraft/launch/AutoInstallJava.h
|
||||||
|
|
||||||
minecraft/GradleSpecifier.h
|
minecraft/GradleSpecifier.h
|
||||||
minecraft/MinecraftInstance.cpp
|
minecraft/MinecraftInstance.cpp
|
||||||
@ -318,8 +308,6 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/ComponentUpdateTask.h
|
minecraft/ComponentUpdateTask.h
|
||||||
minecraft/MinecraftLoadAndCheck.h
|
minecraft/MinecraftLoadAndCheck.h
|
||||||
minecraft/MinecraftLoadAndCheck.cpp
|
minecraft/MinecraftLoadAndCheck.cpp
|
||||||
minecraft/MinecraftUpdate.h
|
|
||||||
minecraft/MinecraftUpdate.cpp
|
|
||||||
minecraft/MojangVersionFormat.cpp
|
minecraft/MojangVersionFormat.cpp
|
||||||
minecraft/MojangVersionFormat.h
|
minecraft/MojangVersionFormat.h
|
||||||
minecraft/Rule.cpp
|
minecraft/Rule.cpp
|
||||||
@ -395,13 +383,17 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/AssetsUtils.h
|
minecraft/AssetsUtils.h
|
||||||
minecraft/AssetsUtils.cpp
|
minecraft/AssetsUtils.cpp
|
||||||
|
|
||||||
# Minecraft services
|
# Minecraft skins
|
||||||
minecraft/services/CapeChange.cpp
|
minecraft/skins/CapeChange.cpp
|
||||||
minecraft/services/CapeChange.h
|
minecraft/skins/CapeChange.h
|
||||||
minecraft/services/SkinUpload.cpp
|
minecraft/skins/SkinUpload.cpp
|
||||||
minecraft/services/SkinUpload.h
|
minecraft/skins/SkinUpload.h
|
||||||
minecraft/services/SkinDelete.cpp
|
minecraft/skins/SkinDelete.cpp
|
||||||
minecraft/services/SkinDelete.h
|
minecraft/skins/SkinDelete.h
|
||||||
|
minecraft/skins/SkinModel.cpp
|
||||||
|
minecraft/skins/SkinModel.h
|
||||||
|
minecraft/skins/SkinList.cpp
|
||||||
|
minecraft/skins/SkinList.h
|
||||||
|
|
||||||
minecraft/Agent.h)
|
minecraft/Agent.h)
|
||||||
|
|
||||||
@ -446,8 +438,6 @@ set(SETTINGS_SOURCES
|
|||||||
set(JAVA_SOURCES
|
set(JAVA_SOURCES
|
||||||
java/JavaChecker.h
|
java/JavaChecker.h
|
||||||
java/JavaChecker.cpp
|
java/JavaChecker.cpp
|
||||||
java/JavaCheckerJob.h
|
|
||||||
java/JavaCheckerJob.cpp
|
|
||||||
java/JavaInstall.h
|
java/JavaInstall.h
|
||||||
java/JavaInstall.cpp
|
java/JavaInstall.cpp
|
||||||
java/JavaInstallList.h
|
java/JavaInstallList.h
|
||||||
@ -456,6 +446,20 @@ set(JAVA_SOURCES
|
|||||||
java/JavaUtils.cpp
|
java/JavaUtils.cpp
|
||||||
java/JavaVersion.h
|
java/JavaVersion.h
|
||||||
java/JavaVersion.cpp
|
java/JavaVersion.cpp
|
||||||
|
|
||||||
|
java/JavaMetadata.h
|
||||||
|
java/JavaMetadata.cpp
|
||||||
|
java/download/ArchiveDownloadTask.cpp
|
||||||
|
java/download/ArchiveDownloadTask.h
|
||||||
|
java/download/ManifestDownloadTask.cpp
|
||||||
|
java/download/ManifestDownloadTask.h
|
||||||
|
java/download/SymlinkTask.cpp
|
||||||
|
java/download/SymlinkTask.h
|
||||||
|
|
||||||
|
ui/java/InstallJavaDialog.h
|
||||||
|
ui/java/InstallJavaDialog.cpp
|
||||||
|
ui/java/VersionList.h
|
||||||
|
ui/java/VersionList.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(TRANSLATIONS_SOURCES
|
set(TRANSLATIONS_SOURCES
|
||||||
@ -477,6 +481,8 @@ set(TOOLS_SOURCES
|
|||||||
tools/JVisualVM.h
|
tools/JVisualVM.h
|
||||||
tools/MCEditTool.cpp
|
tools/MCEditTool.cpp
|
||||||
tools/MCEditTool.h
|
tools/MCEditTool.h
|
||||||
|
tools/GenericProfiler.cpp
|
||||||
|
tools/GenericProfiler.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(META_SOURCES
|
set(META_SOURCES
|
||||||
@ -623,7 +629,7 @@ set(PRISMUPDATER_SOURCES
|
|||||||
updater/prismupdater/UpdaterDialogs.cpp
|
updater/prismupdater/UpdaterDialogs.cpp
|
||||||
updater/prismupdater/GitHubRelease.h
|
updater/prismupdater/GitHubRelease.h
|
||||||
updater/prismupdater/GitHubRelease.cpp
|
updater/prismupdater/GitHubRelease.cpp
|
||||||
|
|
||||||
Json.h
|
Json.h
|
||||||
Json.cpp
|
Json.cpp
|
||||||
FileSystem.h
|
FileSystem.h
|
||||||
@ -640,7 +646,7 @@ set(PRISMUPDATER_SOURCES
|
|||||||
# Zip
|
# Zip
|
||||||
MMCZip.h
|
MMCZip.h
|
||||||
MMCZip.cpp
|
MMCZip.cpp
|
||||||
|
|
||||||
# Time
|
# Time
|
||||||
MMCTime.h
|
MMCTime.h
|
||||||
MMCTime.cpp
|
MMCTime.cpp
|
||||||
@ -655,7 +661,6 @@ set(PRISMUPDATER_SOURCES
|
|||||||
net/HttpMetaCache.h
|
net/HttpMetaCache.h
|
||||||
net/Logging.h
|
net/Logging.h
|
||||||
net/Logging.cpp
|
net/Logging.cpp
|
||||||
net/NetAction.h
|
|
||||||
net/NetRequest.cpp
|
net/NetRequest.cpp
|
||||||
net/NetRequest.h
|
net/NetRequest.h
|
||||||
net/NetJob.cpp
|
net/NetJob.cpp
|
||||||
@ -684,6 +689,22 @@ ecm_qt_declare_logging_category(CORE_SOURCES
|
|||||||
EXPORT "${Launcher_Name}"
|
EXPORT "${Launcher_Name}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ecm_qt_export_logging_category(
|
||||||
|
IDENTIFIER instanceProfileC
|
||||||
|
CATEGORY_NAME "launcher.instance.profile"
|
||||||
|
DEFAULT_SEVERITY Debug
|
||||||
|
DESCRIPTION "Profile actions"
|
||||||
|
EXPORT "${Launcher_Name}"
|
||||||
|
)
|
||||||
|
|
||||||
|
ecm_qt_export_logging_category(
|
||||||
|
IDENTIFIER instanceProfileResolveC
|
||||||
|
CATEGORY_NAME "launcher.instance.profile.resolve"
|
||||||
|
DEFAULT_SEVERITY Debug
|
||||||
|
DESCRIPTION "Profile component resolusion actions"
|
||||||
|
EXPORT "${Launcher_Name}"
|
||||||
|
)
|
||||||
|
|
||||||
ecm_qt_export_logging_category(
|
ecm_qt_export_logging_category(
|
||||||
IDENTIFIER taskLogC
|
IDENTIFIER taskLogC
|
||||||
CATEGORY_NAME "launcher.task"
|
CATEGORY_NAME "launcher.task"
|
||||||
@ -696,7 +717,7 @@ ecm_qt_export_logging_category(
|
|||||||
IDENTIFIER taskNetLogC
|
IDENTIFIER taskNetLogC
|
||||||
CATEGORY_NAME "launcher.task.net"
|
CATEGORY_NAME "launcher.task.net"
|
||||||
DEFAULT_SEVERITY Debug
|
DEFAULT_SEVERITY Debug
|
||||||
DESCRIPTION "task network action"
|
DESCRIPTION "Task network action"
|
||||||
EXPORT "${Launcher_Name}"
|
EXPORT "${Launcher_Name}"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -704,14 +725,14 @@ ecm_qt_export_logging_category(
|
|||||||
IDENTIFIER taskDownloadLogC
|
IDENTIFIER taskDownloadLogC
|
||||||
CATEGORY_NAME "launcher.task.net.download"
|
CATEGORY_NAME "launcher.task.net.download"
|
||||||
DEFAULT_SEVERITY Debug
|
DEFAULT_SEVERITY Debug
|
||||||
DESCRIPTION "task network download actions"
|
DESCRIPTION "Task network download actions"
|
||||||
EXPORT "${Launcher_Name}"
|
EXPORT "${Launcher_Name}"
|
||||||
)
|
)
|
||||||
ecm_qt_export_logging_category(
|
ecm_qt_export_logging_category(
|
||||||
IDENTIFIER taskUploadLogC
|
IDENTIFIER taskUploadLogC
|
||||||
CATEGORY_NAME "launcher.task.net.upload"
|
CATEGORY_NAME "launcher.task.net.upload"
|
||||||
DEFAULT_SEVERITY Debug
|
DEFAULT_SEVERITY Debug
|
||||||
DESCRIPTION "task network upload actions"
|
DESCRIPTION "Task network upload actions"
|
||||||
EXPORT "${Launcher_Name}"
|
EXPORT "${Launcher_Name}"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -782,6 +803,8 @@ SET(LAUNCHER_SOURCES
|
|||||||
DataMigrationTask.cpp
|
DataMigrationTask.cpp
|
||||||
ApplicationMessage.h
|
ApplicationMessage.h
|
||||||
ApplicationMessage.cpp
|
ApplicationMessage.cpp
|
||||||
|
SysInfo.h
|
||||||
|
SysInfo.cpp
|
||||||
|
|
||||||
# GUI - general utilities
|
# GUI - general utilities
|
||||||
DesktopServices.h
|
DesktopServices.h
|
||||||
@ -820,16 +843,12 @@ SET(LAUNCHER_SOURCES
|
|||||||
# GUI - windows
|
# GUI - windows
|
||||||
ui/GuiUtil.h
|
ui/GuiUtil.h
|
||||||
ui/GuiUtil.cpp
|
ui/GuiUtil.cpp
|
||||||
ui/ColorCache.h
|
|
||||||
ui/ColorCache.cpp
|
|
||||||
ui/MainWindow.h
|
ui/MainWindow.h
|
||||||
ui/MainWindow.cpp
|
ui/MainWindow.cpp
|
||||||
ui/InstanceWindow.h
|
ui/InstanceWindow.h
|
||||||
ui/InstanceWindow.cpp
|
ui/InstanceWindow.cpp
|
||||||
|
|
||||||
# FIXME: maybe find a better home for this.
|
# FIXME: maybe find a better home for this.
|
||||||
SkinUtils.cpp
|
|
||||||
SkinUtils.h
|
|
||||||
FileIgnoreProxy.cpp
|
FileIgnoreProxy.cpp
|
||||||
FileIgnoreProxy.h
|
FileIgnoreProxy.h
|
||||||
FastFileIconProvider.cpp
|
FastFileIconProvider.cpp
|
||||||
@ -847,6 +866,10 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/setupwizard/PasteWizardPage.h
|
ui/setupwizard/PasteWizardPage.h
|
||||||
ui/setupwizard/ThemeWizardPage.cpp
|
ui/setupwizard/ThemeWizardPage.cpp
|
||||||
ui/setupwizard/ThemeWizardPage.h
|
ui/setupwizard/ThemeWizardPage.h
|
||||||
|
ui/setupwizard/AutoJavaWizardPage.cpp
|
||||||
|
ui/setupwizard/AutoJavaWizardPage.h
|
||||||
|
ui/setupwizard/LoginWizardPage.cpp
|
||||||
|
ui/setupwizard/LoginWizardPage.h
|
||||||
|
|
||||||
# GUI - themes
|
# GUI - themes
|
||||||
ui/themes/FusionTheme.cpp
|
ui/themes/FusionTheme.cpp
|
||||||
@ -964,6 +987,9 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/pages/modplatform/ShaderPackPage.cpp
|
ui/pages/modplatform/ShaderPackPage.cpp
|
||||||
ui/pages/modplatform/ShaderPackModel.cpp
|
ui/pages/modplatform/ShaderPackModel.cpp
|
||||||
|
|
||||||
|
|
||||||
|
ui/pages/modplatform/ModpackProviderBasePage.h
|
||||||
|
|
||||||
ui/pages/modplatform/atlauncher/AtlFilterModel.cpp
|
ui/pages/modplatform/atlauncher/AtlFilterModel.cpp
|
||||||
ui/pages/modplatform/atlauncher/AtlFilterModel.h
|
ui/pages/modplatform/atlauncher/AtlFilterModel.h
|
||||||
ui/pages/modplatform/atlauncher/AtlListModel.cpp
|
ui/pages/modplatform/atlauncher/AtlListModel.cpp
|
||||||
@ -1067,8 +1093,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/dialogs/ReviewMessageBox.h
|
ui/dialogs/ReviewMessageBox.h
|
||||||
ui/dialogs/VersionSelectDialog.cpp
|
ui/dialogs/VersionSelectDialog.cpp
|
||||||
ui/dialogs/VersionSelectDialog.h
|
ui/dialogs/VersionSelectDialog.h
|
||||||
ui/dialogs/SkinUploadDialog.cpp
|
|
||||||
ui/dialogs/SkinUploadDialog.h
|
|
||||||
ui/dialogs/ResourceDownloadDialog.cpp
|
ui/dialogs/ResourceDownloadDialog.cpp
|
||||||
ui/dialogs/ResourceDownloadDialog.h
|
ui/dialogs/ResourceDownloadDialog.h
|
||||||
ui/dialogs/ScrollMessageBox.cpp
|
ui/dialogs/ScrollMessageBox.cpp
|
||||||
@ -1082,7 +1106,12 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/dialogs/InstallLoaderDialog.cpp
|
ui/dialogs/InstallLoaderDialog.cpp
|
||||||
ui/dialogs/InstallLoaderDialog.h
|
ui/dialogs/InstallLoaderDialog.h
|
||||||
|
|
||||||
|
ui/dialogs/skins/SkinManageDialog.cpp
|
||||||
|
ui/dialogs/skins/SkinManageDialog.h
|
||||||
|
|
||||||
# GUI - widgets
|
# GUI - widgets
|
||||||
|
ui/widgets/CheckComboBox.cpp
|
||||||
|
ui/widgets/CheckComboBox.h
|
||||||
ui/widgets/Common.cpp
|
ui/widgets/Common.cpp
|
||||||
ui/widgets/Common.h
|
ui/widgets/Common.h
|
||||||
ui/widgets/CustomCommands.cpp
|
ui/widgets/CustomCommands.cpp
|
||||||
@ -1167,6 +1196,8 @@ endif()
|
|||||||
qt_wrap_ui(LAUNCHER_UI
|
qt_wrap_ui(LAUNCHER_UI
|
||||||
ui/MainWindow.ui
|
ui/MainWindow.ui
|
||||||
ui/setupwizard/PasteWizardPage.ui
|
ui/setupwizard/PasteWizardPage.ui
|
||||||
|
ui/setupwizard/AutoJavaWizardPage.ui
|
||||||
|
ui/setupwizard/LoginWizardPage.ui
|
||||||
ui/setupwizard/ThemeWizardPage.ui
|
ui/setupwizard/ThemeWizardPage.ui
|
||||||
ui/pages/global/AccountListPage.ui
|
ui/pages/global/AccountListPage.ui
|
||||||
ui/pages/global/JavaPage.ui
|
ui/pages/global/JavaPage.ui
|
||||||
@ -1212,7 +1243,6 @@ qt_wrap_ui(LAUNCHER_UI
|
|||||||
ui/dialogs/NewComponentDialog.ui
|
ui/dialogs/NewComponentDialog.ui
|
||||||
ui/dialogs/NewsDialog.ui
|
ui/dialogs/NewsDialog.ui
|
||||||
ui/dialogs/ProfileSelectDialog.ui
|
ui/dialogs/ProfileSelectDialog.ui
|
||||||
ui/dialogs/SkinUploadDialog.ui
|
|
||||||
ui/dialogs/ExportInstanceDialog.ui
|
ui/dialogs/ExportInstanceDialog.ui
|
||||||
ui/dialogs/ExportPackDialog.ui
|
ui/dialogs/ExportPackDialog.ui
|
||||||
ui/dialogs/ExportToModListDialog.ui
|
ui/dialogs/ExportToModListDialog.ui
|
||||||
@ -1228,6 +1258,8 @@ qt_wrap_ui(LAUNCHER_UI
|
|||||||
ui/dialogs/ScrollMessageBox.ui
|
ui/dialogs/ScrollMessageBox.ui
|
||||||
ui/dialogs/BlockedModsDialog.ui
|
ui/dialogs/BlockedModsDialog.ui
|
||||||
ui/dialogs/ChooseProviderDialog.ui
|
ui/dialogs/ChooseProviderDialog.ui
|
||||||
|
|
||||||
|
ui/dialogs/skins/SkinManageDialog.ui
|
||||||
)
|
)
|
||||||
|
|
||||||
qt_wrap_ui(PRISM_UPDATE_UI
|
qt_wrap_ui(PRISM_UPDATE_UI
|
||||||
@ -1269,14 +1301,10 @@ include(CompilerWarnings)
|
|||||||
|
|
||||||
# Add executable
|
# Add executable
|
||||||
add_library(Launcher_logic STATIC ${LOGIC_SOURCES} ${LAUNCHER_SOURCES} ${LAUNCHER_UI} ${LAUNCHER_RESOURCES})
|
add_library(Launcher_logic STATIC ${LOGIC_SOURCES} ${LAUNCHER_SOURCES} ${LAUNCHER_UI} ${LAUNCHER_RESOURCES})
|
||||||
if(BUILD_TESTING)
|
|
||||||
target_compile_definitions(Launcher_logic PUBLIC LAUNCHER_TEST)
|
|
||||||
endif()
|
|
||||||
set_project_warnings(Launcher_logic
|
set_project_warnings(Launcher_logic
|
||||||
"${Launcher_MSVC_WARNINGS}"
|
"${Launcher_MSVC_WARNINGS}"
|
||||||
"${Launcher_CLANG_WARNINGS}"
|
"${Launcher_CLANG_WARNINGS}"
|
||||||
"${Launcher_GCC_WARNINGS}")
|
"${Launcher_GCC_WARNINGS}")
|
||||||
target_compile_definitions(Launcher_logic PUBLIC LAUNCHER_APPLICATION)
|
|
||||||
target_include_directories(Launcher_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(Launcher_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
target_compile_definitions(Launcher_logic PUBLIC LAUNCHER_APPLICATION)
|
target_compile_definitions(Launcher_logic PUBLIC LAUNCHER_APPLICATION)
|
||||||
target_link_libraries(Launcher_logic
|
target_link_libraries(Launcher_logic
|
||||||
@ -1287,7 +1315,6 @@ target_link_libraries(Launcher_logic
|
|||||||
tomlplusplus::tomlplusplus
|
tomlplusplus::tomlplusplus
|
||||||
qdcss
|
qdcss
|
||||||
BuildConfig
|
BuildConfig
|
||||||
Katabasis
|
|
||||||
Qt${QT_VERSION_MAJOR}::Widgets
|
Qt${QT_VERSION_MAJOR}::Widgets
|
||||||
ghcFilesystem::ghc_filesystem
|
ghcFilesystem::ghc_filesystem
|
||||||
)
|
)
|
||||||
@ -1305,6 +1332,7 @@ target_link_libraries(Launcher_logic
|
|||||||
Qt${QT_VERSION_MAJOR}::Concurrent
|
Qt${QT_VERSION_MAJOR}::Concurrent
|
||||||
Qt${QT_VERSION_MAJOR}::Gui
|
Qt${QT_VERSION_MAJOR}::Gui
|
||||||
Qt${QT_VERSION_MAJOR}::Widgets
|
Qt${QT_VERSION_MAJOR}::Widgets
|
||||||
|
Qt${QT_VERSION_MAJOR}::NetworkAuth
|
||||||
${Launcher_QT_LIBS}
|
${Launcher_QT_LIBS}
|
||||||
)
|
)
|
||||||
target_link_libraries(Launcher_logic
|
target_link_libraries(Launcher_logic
|
||||||
@ -1375,13 +1403,12 @@ if(Launcher_BUILD_UPDATER)
|
|||||||
Qt${QT_VERSION_MAJOR}::Network
|
Qt${QT_VERSION_MAJOR}::Network
|
||||||
${Launcher_QT_LIBS}
|
${Launcher_QT_LIBS}
|
||||||
cmark::cmark
|
cmark::cmark
|
||||||
Katabasis
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable("${Launcher_Name}_updater" WIN32 updater/prismupdater/updater_main.cpp)
|
add_executable("${Launcher_Name}_updater" WIN32 updater/prismupdater/updater_main.cpp)
|
||||||
target_sources("${Launcher_Name}_updater" PRIVATE updater/prismupdater/updater.exe.manifest)
|
target_sources("${Launcher_Name}_updater" PRIVATE updater/prismupdater/updater.exe.manifest)
|
||||||
target_link_libraries("${Launcher_Name}_updater" prism_updater_logic)
|
target_link_libraries("${Launcher_Name}_updater" prism_updater_logic)
|
||||||
|
|
||||||
if(DEFINED Launcher_APP_BINARY_NAME)
|
if(DEFINED Launcher_APP_BINARY_NAME)
|
||||||
set_target_properties("${Launcher_Name}_updater" PROPERTIES OUTPUT_NAME "${Launcher_APP_BINARY_NAME}_updater")
|
set_target_properties("${Launcher_Name}_updater" PROPERTIES OUTPUT_NAME "${Launcher_APP_BINARY_NAME}_updater")
|
||||||
endif()
|
endif()
|
||||||
@ -1540,7 +1567,6 @@ if(INSTALL_BUNDLE STREQUAL "full")
|
|||||||
CONFIGURATIONS Debug RelWithDebInfo ""
|
CONFIGURATIONS Debug RelWithDebInfo ""
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
COMPONENT Runtime
|
COMPONENT Runtime
|
||||||
PATTERN "*qopensslbackend*" EXCLUDE
|
|
||||||
PATTERN "*qcertonlybackend*" EXCLUDE
|
PATTERN "*qcertonlybackend*" EXCLUDE
|
||||||
)
|
)
|
||||||
install(
|
install(
|
||||||
@ -1551,10 +1577,78 @@ if(INSTALL_BUNDLE STREQUAL "full")
|
|||||||
REGEX "dd\\." EXCLUDE
|
REGEX "dd\\." EXCLUDE
|
||||||
REGEX "_debug\\." EXCLUDE
|
REGEX "_debug\\." EXCLUDE
|
||||||
REGEX "\\.dSYM" EXCLUDE
|
REGEX "\\.dSYM" EXCLUDE
|
||||||
PATTERN "*qopensslbackend*" EXCLUDE
|
|
||||||
PATTERN "*qcertonlybackend*" EXCLUDE
|
PATTERN "*qcertonlybackend*" EXCLUDE
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
# Wayland support
|
||||||
|
if(EXISTS "${QT_PLUGINS_DIR}/wayland-graphics-integration-client")
|
||||||
|
install(
|
||||||
|
DIRECTORY "${QT_PLUGINS_DIR}/wayland-graphics-integration-client"
|
||||||
|
CONFIGURATIONS Debug RelWithDebInfo ""
|
||||||
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
|
COMPONENT Runtime
|
||||||
|
)
|
||||||
|
install(
|
||||||
|
DIRECTORY "${QT_PLUGINS_DIR}/wayland-graphics-integration-client"
|
||||||
|
CONFIGURATIONS Release MinSizeRel
|
||||||
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
|
COMPONENT Runtime
|
||||||
|
REGEX "dd\\." EXCLUDE
|
||||||
|
REGEX "_debug\\." EXCLUDE
|
||||||
|
REGEX "\\.dSYM" EXCLUDE
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
if(EXISTS "${QT_PLUGINS_DIR}/wayland-graphics-integration-server")
|
||||||
|
install(
|
||||||
|
DIRECTORY "${QT_PLUGINS_DIR}/wayland-graphics-integration-server"
|
||||||
|
CONFIGURATIONS Debug RelWithDebInfo ""
|
||||||
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
|
COMPONENT Runtime
|
||||||
|
)
|
||||||
|
install(
|
||||||
|
DIRECTORY "${QT_PLUGINS_DIR}/wayland-graphics-integration-server"
|
||||||
|
CONFIGURATIONS Release MinSizeRel
|
||||||
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
|
COMPONENT Runtime
|
||||||
|
REGEX "dd\\." EXCLUDE
|
||||||
|
REGEX "_debug\\." EXCLUDE
|
||||||
|
REGEX "\\.dSYM" EXCLUDE
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
if(EXISTS "${QT_PLUGINS_DIR}/wayland-decoration-client")
|
||||||
|
install(
|
||||||
|
DIRECTORY "${QT_PLUGINS_DIR}/wayland-decoration-client"
|
||||||
|
CONFIGURATIONS Debug RelWithDebInfo ""
|
||||||
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
|
COMPONENT Runtime
|
||||||
|
)
|
||||||
|
install(
|
||||||
|
DIRECTORY "${QT_PLUGINS_DIR}/wayland-decoration-client"
|
||||||
|
CONFIGURATIONS Release MinSizeRel
|
||||||
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
|
COMPONENT Runtime
|
||||||
|
REGEX "dd\\." EXCLUDE
|
||||||
|
REGEX "_debug\\." EXCLUDE
|
||||||
|
REGEX "\\.dSYM" EXCLUDE
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
if(EXISTS "${QT_PLUGINS_DIR}/wayland-shell-integration")
|
||||||
|
install(
|
||||||
|
DIRECTORY "${QT_PLUGINS_DIR}/wayland-shell-integration"
|
||||||
|
CONFIGURATIONS Debug RelWithDebInfo ""
|
||||||
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
|
COMPONENT Runtime
|
||||||
|
)
|
||||||
|
install(
|
||||||
|
DIRECTORY "${QT_PLUGINS_DIR}/wayland-shell-integration"
|
||||||
|
CONFIGURATIONS Release MinSizeRel
|
||||||
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
|
COMPONENT Runtime
|
||||||
|
REGEX "dd\\." EXCLUDE
|
||||||
|
REGEX "_debug\\." EXCLUDE
|
||||||
|
REGEX "\\.dSYM" EXCLUDE
|
||||||
|
)
|
||||||
|
endif()
|
||||||
configure_file(
|
configure_file(
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in"
|
"${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in"
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake"
|
"${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake"
|
||||||
|
@ -29,29 +29,18 @@
|
|||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
|
|
||||||
CreateAuthlibInjectorAccount::CreateAuthlibInjectorAccount(QUrl url, MinecraftAccountPtr account, QString username)
|
CreateAuthlibInjectorAccount::CreateAuthlibInjectorAccount(QUrl url, MinecraftAccountPtr account, QString username)
|
||||||
: NetAction(), m_url(url), m_account(account), m_username(username)
|
: NetRequest(), m_url(url), m_account(account), m_username(username)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void CreateAuthlibInjectorAccount::executeTask()
|
QNetworkReply* CreateAuthlibInjectorAccount::getReply(QNetworkRequest& request)
|
||||||
{
|
{
|
||||||
m_state = State::Running;
|
setStatus(tr("Getting authlib-injector server details"));
|
||||||
QNetworkRequest request(m_url);
|
return m_network->get(request);
|
||||||
QNetworkReply* rep = APPLICATION->network()->get(request);
|
|
||||||
|
|
||||||
m_reply.reset(rep);
|
|
||||||
connect(rep, &QNetworkReply::finished, this, &CreateAuthlibInjectorAccount::downloadFinished);
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15
|
|
||||||
connect(rep, &QNetworkReply::errorOccurred, this, &CreateAuthlibInjectorAccount::downloadError);
|
|
||||||
#else
|
|
||||||
connect(rep, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &CreateAuthlibInjectorAccount::downloadError);
|
|
||||||
#endif
|
|
||||||
connect(rep, &QNetworkReply::sslErrors, this, &CreateAuthlibInjectorAccount::sslErrors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateAuthlibInjectorAccount::downloadError(QNetworkReply::NetworkError error)
|
CreateAuthlibInjectorAccount::Ptr CreateAuthlibInjectorAccount::make(QUrl url, MinecraftAccountPtr account, QString username)
|
||||||
{
|
{
|
||||||
qDebug() << m_reply->errorString();
|
return CreateAuthlibInjectorAccount::Ptr(new CreateAuthlibInjectorAccount(url, account, username));
|
||||||
m_state = State::Failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateAuthlibInjectorAccount::downloadFinished()
|
void CreateAuthlibInjectorAccount::downloadFinished()
|
||||||
|
@ -19,28 +19,22 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "minecraft/auth/MinecraftAccount.h"
|
#include "minecraft/auth/MinecraftAccount.h"
|
||||||
#include "net/NetAction.h"
|
#include "net/NetRequest.h"
|
||||||
|
|
||||||
typedef shared_qobject_ptr<class CreateAuthlibInjectorAccount> CreateAuthlibInjectorAccountPtr;
|
class CreateAuthlibInjectorAccount : public Net::NetRequest {
|
||||||
class CreateAuthlibInjectorAccount : public NetAction {
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit CreateAuthlibInjectorAccount(QUrl url, MinecraftAccountPtr account, QString username);
|
using Ptr = shared_qobject_ptr<CreateAuthlibInjectorAccount>;
|
||||||
static CreateAuthlibInjectorAccountPtr make(QUrl url, MinecraftAccountPtr account, QString username)
|
CreateAuthlibInjectorAccount(QUrl url, MinecraftAccountPtr account, QString username);
|
||||||
{
|
virtual ~CreateAuthlibInjectorAccount() = default;
|
||||||
return CreateAuthlibInjectorAccountPtr(new CreateAuthlibInjectorAccount(url, account, username));
|
|
||||||
}
|
static CreateAuthlibInjectorAccount::Ptr make(QUrl url, MinecraftAccountPtr account, QString username);
|
||||||
|
|
||||||
MinecraftAccountPtr getAccount();
|
MinecraftAccountPtr getAccount();
|
||||||
|
|
||||||
void init() override {};
|
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) override {}
|
virtual QNetworkReply* getReply(QNetworkRequest&) override;
|
||||||
void downloadError(QNetworkReply::NetworkError error) override;
|
void downloadFinished();
|
||||||
void downloadFinished() override;
|
|
||||||
void downloadReadyRead() override {}
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void executeTask() override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QUrl m_url;
|
QUrl m_url;
|
||||||
|
@ -276,6 +276,9 @@ bool ensureFolderPathExists(const QFileInfo folderPath)
|
|||||||
{
|
{
|
||||||
QDir dir;
|
QDir dir;
|
||||||
QString ensuredPath = folderPath.filePath();
|
QString ensuredPath = folderPath.filePath();
|
||||||
|
if (folderPath.exists())
|
||||||
|
return true;
|
||||||
|
|
||||||
bool success = dir.mkpath(ensuredPath);
|
bool success = dir.mkpath(ensuredPath);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
@ -647,6 +650,19 @@ void ExternalLinkFileProcess::runLinkFile()
|
|||||||
qDebug() << "Process exited";
|
qDebug() << "Process exited";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool moveByCopy(const QString& source, const QString& dest)
|
||||||
|
{
|
||||||
|
if (!copy(source, dest)()) { // copy
|
||||||
|
qDebug() << "Copy of" << source << "to" << dest << "failed!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!deletePath(source)) { // remove original
|
||||||
|
qDebug() << "Deletion of" << source << "failed!";
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool move(const QString& source, const QString& dest)
|
bool move(const QString& source, const QString& dest)
|
||||||
{
|
{
|
||||||
std::error_code err;
|
std::error_code err;
|
||||||
@ -654,13 +670,14 @@ bool move(const QString& source, const QString& dest)
|
|||||||
ensureFilePathExists(dest);
|
ensureFilePathExists(dest);
|
||||||
fs::rename(StringUtils::toStdString(source), StringUtils::toStdString(dest), err);
|
fs::rename(StringUtils::toStdString(source), StringUtils::toStdString(dest), err);
|
||||||
|
|
||||||
if (err) {
|
if (err.value() != 0) {
|
||||||
qWarning() << "Failed to move file:" << QString::fromStdString(err.message());
|
if (moveByCopy(source, dest))
|
||||||
qDebug() << "Source file:" << source;
|
return true;
|
||||||
qDebug() << "Destination file:" << dest;
|
qDebug() << "Move of" << source << "to" << dest << "failed!";
|
||||||
|
qWarning() << "Failed to move file:" << QString::fromStdString(err.message()) << QString::number(err.value());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
return err.value() == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deletePath(QString path)
|
bool deletePath(QString path)
|
||||||
@ -904,6 +921,10 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
|
|||||||
if (destination.isEmpty()) {
|
if (destination.isEmpty()) {
|
||||||
destination = PathCombine(getDesktopDir(), RemoveInvalidFilenameChars(name));
|
destination = PathCombine(getDesktopDir(), RemoveInvalidFilenameChars(name));
|
||||||
}
|
}
|
||||||
|
if (!ensureFilePathExists(destination)) {
|
||||||
|
qWarning() << "Destination path can't be created!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#if defined(Q_OS_MACOS)
|
#if defined(Q_OS_MACOS)
|
||||||
// Create the Application
|
// Create the Application
|
||||||
QDir applicationDirectory =
|
QDir applicationDirectory =
|
||||||
@ -1677,4 +1698,30 @@ QString getPathNameInLocal8bit(const QString& file)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
QString getUniqueResourceName(const QString& filePath)
|
||||||
|
{
|
||||||
|
auto newFileName = filePath;
|
||||||
|
if (!newFileName.endsWith(".disabled")) {
|
||||||
|
return newFileName; // prioritize enabled mods
|
||||||
|
}
|
||||||
|
newFileName.chop(9);
|
||||||
|
if (!QFile::exists(newFileName)) {
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
QFileInfo fileInfo(filePath);
|
||||||
|
auto baseName = fileInfo.completeBaseName();
|
||||||
|
auto path = fileInfo.absolutePath();
|
||||||
|
|
||||||
|
int counter = 1;
|
||||||
|
do {
|
||||||
|
if (counter == 1) {
|
||||||
|
newFileName = FS::PathCombine(path, baseName + ".duplicate");
|
||||||
|
} else {
|
||||||
|
newFileName = FS::PathCombine(path, baseName + ".duplicate" + QString::number(counter));
|
||||||
|
}
|
||||||
|
counter++;
|
||||||
|
} while (QFile::exists(newFileName));
|
||||||
|
|
||||||
|
return newFileName;
|
||||||
|
}
|
||||||
} // namespace FS
|
} // namespace FS
|
||||||
|
@ -72,7 +72,7 @@ void appendSafe(const QString& filename, const QByteArray& data);
|
|||||||
void append(const QString& filename, const QByteArray& data);
|
void append(const QString& filename, const QByteArray& data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* read data from a file safely\
|
* read data from a file safely
|
||||||
*/
|
*/
|
||||||
QByteArray read(const QString& filename);
|
QByteArray read(const QString& filename);
|
||||||
|
|
||||||
@ -240,6 +240,7 @@ class create_link : public QObject {
|
|||||||
bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
|
bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
|
||||||
|
|
||||||
int totalLinked() { return m_linked; }
|
int totalLinked() { return m_linked; }
|
||||||
|
int totalToLink() { return static_cast<int>(m_links_to_make.size()); }
|
||||||
|
|
||||||
void runPrivileged() { runPrivileged(QString()); }
|
void runPrivileged() { runPrivileged(QString()); }
|
||||||
void runPrivileged(const QString& offset);
|
void runPrivileged(const QString& offset);
|
||||||
@ -559,4 +560,6 @@ uintmax_t hardLinkCount(const QString& path);
|
|||||||
QString getPathNameInLocal8bit(const QString& file);
|
QString getPathNameInLocal8bit(const QString& file);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
QString getUniqueResourceName(const QString& filePath);
|
||||||
|
|
||||||
} // namespace FS
|
} // namespace FS
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
#include "Filter.h"
|
#include "Filter.h"
|
||||||
|
|
||||||
Filter::~Filter() {}
|
|
||||||
|
|
||||||
ContainsFilter::ContainsFilter(const QString& pattern) : pattern(pattern) {}
|
ContainsFilter::ContainsFilter(const QString& pattern) : pattern(pattern) {}
|
||||||
ContainsFilter::~ContainsFilter() {}
|
|
||||||
bool ContainsFilter::accepts(const QString& value)
|
bool ContainsFilter::accepts(const QString& value)
|
||||||
{
|
{
|
||||||
return value.contains(pattern);
|
return value.contains(pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactFilter::ExactFilter(const QString& pattern) : pattern(pattern) {}
|
ExactFilter::ExactFilter(const QString& pattern) : pattern(pattern) {}
|
||||||
ExactFilter::~ExactFilter() {}
|
|
||||||
bool ExactFilter::accepts(const QString& value)
|
bool ExactFilter::accepts(const QString& value)
|
||||||
{
|
{
|
||||||
return value == pattern;
|
return value == pattern;
|
||||||
@ -27,10 +23,15 @@ RegexpFilter::RegexpFilter(const QString& regexp, bool invert) : invert(invert)
|
|||||||
pattern.setPattern(regexp);
|
pattern.setPattern(regexp);
|
||||||
pattern.optimize();
|
pattern.optimize();
|
||||||
}
|
}
|
||||||
RegexpFilter::~RegexpFilter() {}
|
|
||||||
bool RegexpFilter::accepts(const QString& value)
|
bool RegexpFilter::accepts(const QString& value)
|
||||||
{
|
{
|
||||||
auto match = pattern.match(value);
|
auto match = pattern.match(value);
|
||||||
bool matched = match.hasMatch();
|
bool matched = match.hasMatch();
|
||||||
return invert ? (!matched) : (matched);
|
return invert ? (!matched) : (matched);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExactListFilter::ExactListFilter(const QStringList& pattern) : m_pattern(pattern) {}
|
||||||
|
bool ExactListFilter::accepts(const QString& value)
|
||||||
|
{
|
||||||
|
return m_pattern.isEmpty() || m_pattern.contains(value);
|
||||||
|
}
|
@ -5,14 +5,14 @@
|
|||||||
|
|
||||||
class Filter {
|
class Filter {
|
||||||
public:
|
public:
|
||||||
virtual ~Filter();
|
virtual ~Filter() = default;
|
||||||
virtual bool accepts(const QString& value) = 0;
|
virtual bool accepts(const QString& value) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ContainsFilter : public Filter {
|
class ContainsFilter : public Filter {
|
||||||
public:
|
public:
|
||||||
ContainsFilter(const QString& pattern);
|
ContainsFilter(const QString& pattern);
|
||||||
virtual ~ContainsFilter();
|
virtual ~ContainsFilter() = default;
|
||||||
bool accepts(const QString& value) override;
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -22,7 +22,7 @@ class ContainsFilter : public Filter {
|
|||||||
class ExactFilter : public Filter {
|
class ExactFilter : public Filter {
|
||||||
public:
|
public:
|
||||||
ExactFilter(const QString& pattern);
|
ExactFilter(const QString& pattern);
|
||||||
virtual ~ExactFilter();
|
virtual ~ExactFilter() = default;
|
||||||
bool accepts(const QString& value) override;
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -32,7 +32,7 @@ class ExactFilter : public Filter {
|
|||||||
class ExactIfPresentFilter : public Filter {
|
class ExactIfPresentFilter : public Filter {
|
||||||
public:
|
public:
|
||||||
ExactIfPresentFilter(const QString& pattern);
|
ExactIfPresentFilter(const QString& pattern);
|
||||||
~ExactIfPresentFilter() override = default;
|
virtual ~ExactIfPresentFilter() override = default;
|
||||||
bool accepts(const QString& value) override;
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -42,10 +42,20 @@ class ExactIfPresentFilter : public Filter {
|
|||||||
class RegexpFilter : public Filter {
|
class RegexpFilter : public Filter {
|
||||||
public:
|
public:
|
||||||
RegexpFilter(const QString& regexp, bool invert);
|
RegexpFilter(const QString& regexp, bool invert);
|
||||||
virtual ~RegexpFilter();
|
virtual ~RegexpFilter() = default;
|
||||||
bool accepts(const QString& value) override;
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QRegularExpression pattern;
|
QRegularExpression pattern;
|
||||||
bool invert = false;
|
bool invert = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ExactListFilter : public Filter {
|
||||||
|
public:
|
||||||
|
ExactListFilter(const QStringList& pattern = {});
|
||||||
|
virtual ~ExactListFilter() = default;
|
||||||
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStringList m_pattern;
|
||||||
|
};
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
#include "InstanceCopyTask.h"
|
#include "InstanceCopyTask.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
|
#include <memory>
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "NullInstance.h"
|
#include "NullInstance.h"
|
||||||
#include "pathmatcher/RegexpMatcher.h"
|
#include "pathmatcher/RegexpMatcher.h"
|
||||||
#include "settings/INISettingsObject.h"
|
#include "settings/INISettingsObject.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
InstanceCopyTask::InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs)
|
InstanceCopyTask::InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs)
|
||||||
{
|
{
|
||||||
@ -38,38 +40,50 @@ void InstanceCopyTask::executeTask()
|
|||||||
{
|
{
|
||||||
setStatus(tr("Copying instance %1").arg(m_origInstance->name()));
|
setStatus(tr("Copying instance %1").arg(m_origInstance->name()));
|
||||||
|
|
||||||
auto copySaves = [&]() {
|
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this] {
|
||||||
QFileInfo mcDir(FS::PathCombine(m_stagingPath, "minecraft"));
|
|
||||||
QFileInfo dotMCDir(FS::PathCombine(m_stagingPath, ".minecraft"));
|
|
||||||
|
|
||||||
QString staging_mc_dir;
|
|
||||||
if (mcDir.exists() && !dotMCDir.exists())
|
|
||||||
staging_mc_dir = mcDir.filePath();
|
|
||||||
else
|
|
||||||
staging_mc_dir = dotMCDir.filePath();
|
|
||||||
|
|
||||||
FS::copy savesCopy(FS::PathCombine(m_origInstance->gameRoot(), "saves"), FS::PathCombine(staging_mc_dir, "saves"));
|
|
||||||
savesCopy.followSymlinks(true);
|
|
||||||
|
|
||||||
return savesCopy();
|
|
||||||
};
|
|
||||||
|
|
||||||
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this, copySaves] {
|
|
||||||
if (m_useClone) {
|
if (m_useClone) {
|
||||||
FS::clone folderClone(m_origInstance->instanceRoot(), m_stagingPath);
|
FS::clone folderClone(m_origInstance->instanceRoot(), m_stagingPath);
|
||||||
folderClone.matcher(m_matcher.get());
|
folderClone.matcher(m_matcher.get());
|
||||||
|
|
||||||
|
folderClone(true);
|
||||||
|
setProgress(0, folderClone.totalCloned());
|
||||||
|
connect(&folderClone, &FS::clone::fileCloned,
|
||||||
|
[this](QString src, QString dst) { setProgress(m_progress + 1, m_progressTotal); });
|
||||||
return folderClone();
|
return folderClone();
|
||||||
} else if (m_useLinks || m_useHardLinks) {
|
}
|
||||||
|
if (m_useLinks || m_useHardLinks) {
|
||||||
|
std::unique_ptr<FS::copy> savesCopy;
|
||||||
|
if (m_copySaves) {
|
||||||
|
QFileInfo mcDir(FS::PathCombine(m_stagingPath, "minecraft"));
|
||||||
|
QFileInfo dotMCDir(FS::PathCombine(m_stagingPath, ".minecraft"));
|
||||||
|
|
||||||
|
QString staging_mc_dir;
|
||||||
|
if (dotMCDir.exists() && !mcDir.exists())
|
||||||
|
staging_mc_dir = dotMCDir.filePath();
|
||||||
|
else
|
||||||
|
staging_mc_dir = mcDir.filePath();
|
||||||
|
|
||||||
|
savesCopy = std::make_unique<FS::copy>(FS::PathCombine(m_origInstance->gameRoot(), "saves"),
|
||||||
|
FS::PathCombine(staging_mc_dir, "saves"));
|
||||||
|
savesCopy->followSymlinks(true);
|
||||||
|
(*savesCopy)(true);
|
||||||
|
setProgress(0, savesCopy->totalCopied());
|
||||||
|
connect(savesCopy.get(), &FS::copy::fileCopied, [this](QString src) { setProgress(m_progress + 1, m_progressTotal); });
|
||||||
|
}
|
||||||
FS::create_link folderLink(m_origInstance->instanceRoot(), m_stagingPath);
|
FS::create_link folderLink(m_origInstance->instanceRoot(), m_stagingPath);
|
||||||
int depth = m_linkRecursively ? -1 : 0; // we need to at least link the top level instead of the instance folder
|
int depth = m_linkRecursively ? -1 : 0; // we need to at least link the top level instead of the instance folder
|
||||||
folderLink.linkRecursively(true).setMaxDepth(depth).useHardLinks(m_useHardLinks).matcher(m_matcher.get());
|
folderLink.linkRecursively(true).setMaxDepth(depth).useHardLinks(m_useHardLinks).matcher(m_matcher.get());
|
||||||
|
|
||||||
|
folderLink(true);
|
||||||
|
setProgress(0, m_progressTotal + folderLink.totalToLink());
|
||||||
|
connect(&folderLink, &FS::create_link::fileLinked,
|
||||||
|
[this](QString src, QString dst) { setProgress(m_progress + 1, m_progressTotal); });
|
||||||
bool there_were_errors = false;
|
bool there_were_errors = false;
|
||||||
|
|
||||||
if (!folderLink()) {
|
if (!folderLink()) {
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
if (!m_useHardLinks) {
|
if (!m_useHardLinks) {
|
||||||
|
setProgress(0, m_progressTotal);
|
||||||
qDebug() << "EXPECTED: Link failure, Windows requires permissions for symlinks";
|
qDebug() << "EXPECTED: Link failure, Windows requires permissions for symlinks";
|
||||||
|
|
||||||
qDebug() << "attempting to run with privelage";
|
qDebug() << "attempting to run with privelage";
|
||||||
@ -94,13 +108,11 @@ void InstanceCopyTask::executeTask()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_copySaves) {
|
if (savesCopy) {
|
||||||
there_were_errors |= !copySaves();
|
there_were_errors |= !(*savesCopy)();
|
||||||
}
|
}
|
||||||
|
|
||||||
return got_priv_results && !there_were_errors;
|
return got_priv_results && !there_were_errors;
|
||||||
} else {
|
|
||||||
qDebug() << "Link Failed!" << folderLink.getOSError().value() << folderLink.getOSError().message().c_str();
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
qDebug() << "Link Failed!" << folderLink.getOSError().value() << folderLink.getOSError().message().c_str();
|
qDebug() << "Link Failed!" << folderLink.getOSError().value() << folderLink.getOSError().message().c_str();
|
||||||
@ -108,17 +120,19 @@ void InstanceCopyTask::executeTask()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_copySaves) {
|
if (savesCopy) {
|
||||||
there_were_errors |= !copySaves();
|
there_were_errors |= !(*savesCopy)();
|
||||||
}
|
}
|
||||||
|
|
||||||
return !there_were_errors;
|
return !there_were_errors;
|
||||||
} else {
|
|
||||||
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
|
|
||||||
folderCopy.followSymlinks(false).matcher(m_matcher.get());
|
|
||||||
|
|
||||||
return folderCopy();
|
|
||||||
}
|
}
|
||||||
|
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
|
||||||
|
folderCopy.followSymlinks(false).matcher(m_matcher.get());
|
||||||
|
|
||||||
|
folderCopy(true);
|
||||||
|
setProgress(0, folderCopy.totalCopied());
|
||||||
|
connect(&folderCopy, &FS::copy::fileCopied, [this](QString src) { setProgress(m_progress + 1, m_progressTotal); });
|
||||||
|
return folderCopy();
|
||||||
});
|
});
|
||||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &InstanceCopyTask::copyFinished);
|
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &InstanceCopyTask::copyFinished);
|
||||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &InstanceCopyTask::copyAborted);
|
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &InstanceCopyTask::copyAborted);
|
||||||
@ -159,7 +173,11 @@ void InstanceCopyTask::copyFinished()
|
|||||||
allowed_symlinks_file
|
allowed_symlinks_file
|
||||||
.filePath()); // we dont want to modify the original. also make sure the resulting file is not itself a link.
|
.filePath()); // we dont want to modify the original. also make sure the resulting file is not itself a link.
|
||||||
|
|
||||||
FS::write(allowed_symlinks_file.filePath(), allowed_symlinks);
|
try {
|
||||||
|
FS::write(allowed_symlinks_file.filePath(), allowed_symlinks);
|
||||||
|
} catch (const FS::FileSystemException& e) {
|
||||||
|
qCritical() << "Failed to write symlink :" << e.cause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
@ -170,3 +188,14 @@ void InstanceCopyTask::copyAborted()
|
|||||||
emitFailed(tr("Instance folder copy has been aborted."));
|
emitFailed(tr("Instance folder copy has been aborted."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InstanceCopyTask::abort()
|
||||||
|
{
|
||||||
|
if (m_copyFutureWatcher.isRunning()) {
|
||||||
|
m_copyFutureWatcher.cancel();
|
||||||
|
// NOTE: Here we don't do `emitAborted()` because it will be done when `m_copyFutureWatcher` actually cancels, which may not occur
|
||||||
|
// immediately.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
@ -19,6 +19,7 @@ class InstanceCopyTask : public InstanceTask {
|
|||||||
protected:
|
protected:
|
||||||
//! Entry point for tasks.
|
//! Entry point for tasks.
|
||||||
virtual void executeTask() override;
|
virtual void executeTask() override;
|
||||||
|
bool abort() override;
|
||||||
void copyFinished();
|
void copyFinished();
|
||||||
void copyAborted();
|
void copyAborted();
|
||||||
|
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
#include "FileSystem.h"
|
||||||
InstanceCreationTask::InstanceCreationTask() = default;
|
|
||||||
|
|
||||||
void InstanceCreationTask::executeTask()
|
void InstanceCreationTask::executeTask()
|
||||||
{
|
{
|
||||||
@ -39,22 +38,29 @@ void InstanceCreationTask::executeTask()
|
|||||||
// files scheduled to, and we'd better not let the user abort in the middle of it, since it'd
|
// files scheduled to, and we'd better not let the user abort in the middle of it, since it'd
|
||||||
// put the instance in an invalid state.
|
// put the instance in an invalid state.
|
||||||
if (shouldOverride()) {
|
if (shouldOverride()) {
|
||||||
|
bool deleteFailed = false;
|
||||||
|
|
||||||
setAbortable(false);
|
setAbortable(false);
|
||||||
setStatus(tr("Removing old conflicting files..."));
|
setStatus(tr("Removing old conflicting files..."));
|
||||||
qDebug() << "Removing old files";
|
qDebug() << "Removing old files";
|
||||||
|
|
||||||
for (auto path : m_files_to_remove) {
|
for (const QString& path : m_files_to_remove) {
|
||||||
if (!QFile::exists(path))
|
if (!QFile::exists(path))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
qDebug() << "Removing" << path;
|
qDebug() << "Removing" << path;
|
||||||
|
|
||||||
if (!QFile::remove(path)) {
|
if (!QFile::remove(path)) {
|
||||||
qCritical() << "Couldn't remove the old conflicting files.";
|
qCritical() << "Could not remove" << path;
|
||||||
emitFailed(tr("Failed to remove old conflicting files."));
|
deleteFailed = true;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deleteFailed) {
|
||||||
|
emitFailed(tr("Failed to remove old conflicting files."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
class InstanceCreationTask : public InstanceTask {
|
class InstanceCreationTask : public InstanceTask {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
InstanceCreationTask();
|
InstanceCreationTask() = default;
|
||||||
virtual ~InstanceCreationTask() = default;
|
virtual ~InstanceCreationTask() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
|
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <quazip/quazipdir.h>
|
#include <quazip/quazipdir.h>
|
||||||
|
|
||||||
@ -68,15 +69,8 @@ bool InstanceImportTask::abort()
|
|||||||
if (!canAbort())
|
if (!canAbort())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (m_filesNetJob)
|
if (task)
|
||||||
m_filesNetJob->abort();
|
task->abort();
|
||||||
if (m_extractFuture.isRunning()) {
|
|
||||||
// NOTE: The tasks created by QtConcurrent::run() can't actually get cancelled,
|
|
||||||
// but we can use this call to check the state when the extraction finishes.
|
|
||||||
m_extractFuture.cancel();
|
|
||||||
m_extractFuture.waitForFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task::abort();
|
return Task::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +83,6 @@ void InstanceImportTask::executeTask()
|
|||||||
processZipPack();
|
processZipPack();
|
||||||
} else {
|
} else {
|
||||||
setStatus(tr("Downloading modpack:\n%1").arg(m_sourceUrl.toString()));
|
setStatus(tr("Downloading modpack:\n%1").arg(m_sourceUrl.toString()));
|
||||||
m_downloadRequired = true;
|
|
||||||
|
|
||||||
downloadFromUrl();
|
downloadFromUrl();
|
||||||
}
|
}
|
||||||
@ -97,115 +90,132 @@ void InstanceImportTask::executeTask()
|
|||||||
|
|
||||||
void InstanceImportTask::downloadFromUrl()
|
void InstanceImportTask::downloadFromUrl()
|
||||||
{
|
{
|
||||||
const QString path = m_sourceUrl.host() + '/' + m_sourceUrl.path();
|
const QString path(m_sourceUrl.host() + '/' + m_sourceUrl.path());
|
||||||
|
|
||||||
auto entry = APPLICATION->metacache()->resolveEntry("general", path);
|
auto entry = APPLICATION->metacache()->resolveEntry("general", path);
|
||||||
entry->setStale(true);
|
entry->setStale(true);
|
||||||
m_filesNetJob.reset(new NetJob(tr("Modpack download"), APPLICATION->network()));
|
|
||||||
m_filesNetJob->addNetAction(Net::ApiDownload::makeCached(m_sourceUrl, entry));
|
|
||||||
m_archivePath = entry->getFullPath();
|
m_archivePath = entry->getFullPath();
|
||||||
|
|
||||||
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded);
|
auto filesNetJob = makeShared<NetJob>(tr("Modpack download"), APPLICATION->network());
|
||||||
connect(m_filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged);
|
filesNetJob->addNetAction(Net::ApiDownload::makeCached(m_sourceUrl, entry));
|
||||||
connect(m_filesNetJob.get(), &NetJob::stepProgress, this, &InstanceImportTask::propagateStepProgress);
|
|
||||||
connect(m_filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::downloadFailed);
|
connect(filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::processZipPack);
|
||||||
connect(m_filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::downloadAborted);
|
connect(filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::setProgress);
|
||||||
m_filesNetJob->start();
|
connect(filesNetJob.get(), &NetJob::stepProgress, this, &InstanceImportTask::propagateStepProgress);
|
||||||
|
connect(filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::emitFailed);
|
||||||
|
connect(filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::emitAborted);
|
||||||
|
task.reset(filesNetJob);
|
||||||
|
filesNetJob->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceImportTask::downloadSucceeded()
|
QString InstanceImportTask::getRootFromZip(QuaZip* zip, const QString& root)
|
||||||
{
|
{
|
||||||
processZipPack();
|
if (!isRunning()) {
|
||||||
m_filesNetJob.reset();
|
return {};
|
||||||
}
|
}
|
||||||
|
QuaZipDir rootDir(zip, root);
|
||||||
|
for (auto&& fileName : rootDir.entryList(QDir::Files)) {
|
||||||
|
setDetails(fileName);
|
||||||
|
if (fileName == "instance.cfg") {
|
||||||
|
qDebug() << "MultiMC:" << true;
|
||||||
|
m_modpackType = ModpackType::MultiMC;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
if (fileName == "manifest.json") {
|
||||||
|
qDebug() << "Flame:" << true;
|
||||||
|
m_modpackType = ModpackType::Flame;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
void InstanceImportTask::downloadFailed(QString reason)
|
QCoreApplication::processEvents();
|
||||||
{
|
}
|
||||||
emitFailed(reason);
|
|
||||||
m_filesNetJob.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstanceImportTask::downloadProgressChanged(qint64 current, qint64 total)
|
// Recurse the search to non-ignored subfolders
|
||||||
{
|
for (auto&& fileName : rootDir.entryList(QDir::Dirs)) {
|
||||||
setProgress(current, total);
|
if ("overrides/" == fileName)
|
||||||
}
|
continue;
|
||||||
|
|
||||||
void InstanceImportTask::downloadAborted()
|
QString result = getRootFromZip(zip, root + fileName);
|
||||||
{
|
if (!result.isEmpty())
|
||||||
emitAborted();
|
return result;
|
||||||
m_filesNetJob.reset();
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceImportTask::processZipPack()
|
void InstanceImportTask::processZipPack()
|
||||||
{
|
{
|
||||||
setStatus(tr("Extracting modpack"));
|
setStatus(tr("Attempting to determine instance type"));
|
||||||
QDir extractDir(m_stagingPath);
|
QDir extractDir(m_stagingPath);
|
||||||
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
|
||||||
m_packZip.reset(new QuaZip(m_archivePath));
|
auto packZip = std::make_shared<QuaZip>(m_archivePath);
|
||||||
if (!m_packZip->open(QuaZip::mdUnzip)) {
|
if (!packZip->open(QuaZip::mdUnzip)) {
|
||||||
emitFailed(tr("Unable to open supplied modpack zip file."));
|
emitFailed(tr("Unable to open supplied modpack zip file."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QuaZipDir packZipDir(m_packZip.get());
|
QuaZipDir packZipDir(packZip.get());
|
||||||
|
qDebug() << "Attempting to determine instance type";
|
||||||
|
|
||||||
// https://docs.modrinth.com/docs/modpacks/format_definition/#storage
|
|
||||||
bool modrinthFound = packZipDir.exists("/modrinth.index.json");
|
|
||||||
bool technicFound = packZipDir.exists("/bin/modpack.jar") || packZipDir.exists("/bin/version.json");
|
|
||||||
QString root;
|
QString root;
|
||||||
|
|
||||||
// NOTE: Prioritize modpack platforms that aren't searched for recursively.
|
// NOTE: Prioritize modpack platforms that aren't searched for recursively.
|
||||||
// Especially Flame has a very common filename for its manifest, which may appear inside overrides for example
|
// Especially Flame has a very common filename for its manifest, which may appear inside overrides for example
|
||||||
if (modrinthFound) {
|
// https://docs.modrinth.com/docs/modpacks/format_definition/#storage
|
||||||
|
if (packZipDir.exists("/modrinth.index.json")) {
|
||||||
// process as Modrinth pack
|
// process as Modrinth pack
|
||||||
qDebug() << "Modrinth:" << modrinthFound;
|
qDebug() << "Modrinth:" << true;
|
||||||
m_modpackType = ModpackType::Modrinth;
|
m_modpackType = ModpackType::Modrinth;
|
||||||
} else if (technicFound) {
|
} else if (packZipDir.exists("/bin/modpack.jar") || packZipDir.exists("/bin/version.json")) {
|
||||||
// process as Technic pack
|
// process as Technic pack
|
||||||
qDebug() << "Technic:" << technicFound;
|
qDebug() << "Technic:" << true;
|
||||||
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/" };
|
root = getRootFromZip(packZip.get());
|
||||||
|
setDetails("");
|
||||||
if (QString mmcRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg", paths_to_ignore); !mmcRoot.isNull()) {
|
|
||||||
// process as MultiMC instance/pack
|
|
||||||
qDebug() << "MultiMC:" << mmcRoot;
|
|
||||||
root = mmcRoot;
|
|
||||||
m_modpackType = ModpackType::MultiMC;
|
|
||||||
} else if (QString flameRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json", paths_to_ignore);
|
|
||||||
!flameRoot.isNull()) {
|
|
||||||
// process as Flame pack
|
|
||||||
qDebug() << "Flame:" << flameRoot;
|
|
||||||
root = flameRoot;
|
|
||||||
m_modpackType = ModpackType::Flame;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (m_modpackType == ModpackType::Unknown) {
|
if (m_modpackType == ModpackType::Unknown) {
|
||||||
emitFailed(tr("Archive does not contain a recognized modpack type."));
|
emitFailed(tr("Archive does not contain a recognized modpack type."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
setStatus(tr("Extracting modpack"));
|
||||||
|
|
||||||
// make sure we extract just the pack
|
// make sure we extract just the pack
|
||||||
m_extractFuture =
|
auto zipTask = makeShared<MMCZip::ExtractZipTask>(packZip, extractDir, root);
|
||||||
QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractSubDir, m_packZip.get(), root, extractDir.absolutePath());
|
|
||||||
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, &InstanceImportTask::extractFinished);
|
auto progressStep = std::make_shared<TaskStepProgress>();
|
||||||
m_extractFutureWatcher.setFuture(m_extractFuture);
|
connect(zipTask.get(), &Task::finished, this, [this, progressStep] {
|
||||||
|
progressStep->state = TaskStepState::Succeeded;
|
||||||
|
stepProgress(*progressStep);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(zipTask.get(), &Task::succeeded, this, &InstanceImportTask::extractFinished);
|
||||||
|
connect(zipTask.get(), &Task::aborted, this, &InstanceImportTask::emitAborted);
|
||||||
|
connect(zipTask.get(), &Task::failed, this, [this, progressStep](QString reason) {
|
||||||
|
progressStep->state = TaskStepState::Failed;
|
||||||
|
stepProgress(*progressStep);
|
||||||
|
emitFailed(reason);
|
||||||
|
});
|
||||||
|
connect(zipTask.get(), &Task::stepProgress, this, &InstanceImportTask::propagateStepProgress);
|
||||||
|
|
||||||
|
connect(zipTask.get(), &Task::progress, this, [this, progressStep](qint64 current, qint64 total) {
|
||||||
|
progressStep->update(current, total);
|
||||||
|
stepProgress(*progressStep);
|
||||||
|
});
|
||||||
|
connect(zipTask.get(), &Task::status, this, [this, progressStep](QString status) {
|
||||||
|
progressStep->status = status;
|
||||||
|
stepProgress(*progressStep);
|
||||||
|
});
|
||||||
|
task.reset(zipTask);
|
||||||
|
zipTask->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceImportTask::extractFinished()
|
void InstanceImportTask::extractFinished()
|
||||||
{
|
{
|
||||||
m_packZip.reset();
|
|
||||||
|
|
||||||
if (m_extractFuture.isCanceled())
|
|
||||||
return;
|
|
||||||
if (!m_extractFuture.result().has_value()) {
|
|
||||||
emitFailed(tr("Failed to extract modpack"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDir extractDir(m_stagingPath);
|
QDir extractDir(m_stagingPath);
|
||||||
|
|
||||||
qDebug() << "Fixing permissions for extracted pack files...";
|
qDebug() << "Fixing permissions for extracted pack files...";
|
||||||
@ -324,13 +334,15 @@ void InstanceImportTask::processMultiMC()
|
|||||||
m_instIcon = instance.iconKey();
|
m_instIcon = instance.iconKey();
|
||||||
|
|
||||||
auto importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), m_instIcon);
|
auto importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), m_instIcon);
|
||||||
|
if (importIconPath.isNull() || !QFile::exists(importIconPath))
|
||||||
|
importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), "icon.png");
|
||||||
if (!importIconPath.isNull() && QFile::exists(importIconPath)) {
|
if (!importIconPath.isNull() && QFile::exists(importIconPath)) {
|
||||||
// import icon
|
// import icon
|
||||||
auto iconList = APPLICATION->icons();
|
auto iconList = APPLICATION->icons();
|
||||||
if (iconList->iconFileExists(m_instIcon)) {
|
if (iconList->iconFileExists(m_instIcon)) {
|
||||||
iconList->deleteIcon(m_instIcon);
|
iconList->deleteIcon(m_instIcon);
|
||||||
}
|
}
|
||||||
iconList->installIcons({ importIconPath });
|
iconList->installIcon(importIconPath, m_instIcon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
|
@ -39,11 +39,8 @@
|
|||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include "InstanceTask.h"
|
#include "InstanceTask.h"
|
||||||
#include "QObjectPtr.h"
|
|
||||||
#include "modplatform/flame/PackManifest.h"
|
|
||||||
#include "net/NetJob.h"
|
|
||||||
#include "settings/SettingsObject.h"
|
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
class QuaZip;
|
class QuaZip;
|
||||||
@ -54,35 +51,26 @@ class InstanceImportTask : public InstanceTask {
|
|||||||
explicit InstanceImportTask(const QUrl& sourceUrl, QWidget* parent = nullptr, QMap<QString, QString>&& extra_info = {});
|
explicit InstanceImportTask(const QUrl& sourceUrl, QWidget* parent = nullptr, QMap<QString, QString>&& extra_info = {});
|
||||||
|
|
||||||
bool abort() override;
|
bool abort() override;
|
||||||
const QVector<Flame::File>& getBlockedFiles() const { return m_blockedMods; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Entry point for tasks.
|
//! Entry point for tasks.
|
||||||
virtual void executeTask() override;
|
virtual void executeTask() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void processZipPack();
|
|
||||||
void processMultiMC();
|
void processMultiMC();
|
||||||
void processTechnic();
|
void processTechnic();
|
||||||
void processFlame();
|
void processFlame();
|
||||||
void processModrinth();
|
void processModrinth();
|
||||||
|
QString getRootFromZip(QuaZip* zip, const QString& root = "");
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void downloadSucceeded();
|
void processZipPack();
|
||||||
void downloadFailed(QString reason);
|
|
||||||
void downloadProgressChanged(qint64 current, qint64 total);
|
|
||||||
void downloadAborted();
|
|
||||||
void extractFinished();
|
void extractFinished();
|
||||||
|
|
||||||
private: /* data */
|
private: /* data */
|
||||||
NetJob::Ptr m_filesNetJob;
|
|
||||||
QUrl m_sourceUrl;
|
QUrl m_sourceUrl;
|
||||||
QString m_archivePath;
|
QString m_archivePath;
|
||||||
bool m_downloadRequired = false;
|
Task::Ptr task;
|
||||||
std::unique_ptr<QuaZip> m_packZip;
|
|
||||||
QFuture<std::optional<QStringList>> m_extractFuture;
|
|
||||||
QFutureWatcher<std::optional<QStringList>> m_extractFutureWatcher;
|
|
||||||
QVector<Flame::File> m_blockedMods;
|
|
||||||
enum class ModpackType {
|
enum class ModpackType {
|
||||||
Unknown,
|
Unknown,
|
||||||
MultiMC,
|
MultiMC,
|
||||||
|
@ -372,13 +372,13 @@ void InstanceList::undoTrashInstance()
|
|||||||
|
|
||||||
auto top = m_trashHistory.pop();
|
auto top = m_trashHistory.pop();
|
||||||
|
|
||||||
while (QDir(top.polyPath).exists()) {
|
while (QDir(top.path).exists()) {
|
||||||
top.id += "1";
|
top.id += "1";
|
||||||
top.polyPath += "1";
|
top.path += "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "Moving" << top.trashPath << "back to" << top.polyPath;
|
qDebug() << "Moving" << top.trashPath << "back to" << top.path;
|
||||||
QFile(top.trashPath).rename(top.polyPath);
|
QFile(top.trashPath).rename(top.path);
|
||||||
|
|
||||||
m_instanceGroupIndex[top.id] = top.groupName;
|
m_instanceGroupIndex[top.id] = top.groupName;
|
||||||
increaseGroupCount(top.groupName);
|
increaseGroupCount(top.groupName);
|
||||||
@ -635,8 +635,8 @@ InstancePtr InstanceList::loadInstance(const InstanceId& id)
|
|||||||
|
|
||||||
QString inst_type = instanceSettings->get("InstanceType").toString();
|
QString inst_type = instanceSettings->get("InstanceType").toString();
|
||||||
|
|
||||||
// NOTE: Some PolyMC versions didn't save the InstanceType properly. We will just bank on the probability that this is probably a OneSix
|
// NOTE: Some launcher versions didn't save the InstanceType properly. We will just bank on the probability that this is probably a
|
||||||
// instance
|
// OneSix instance
|
||||||
if (inst_type == "OneSix" || inst_type.isEmpty()) {
|
if (inst_type == "OneSix" || inst_type.isEmpty()) {
|
||||||
inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot));
|
inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot));
|
||||||
} else {
|
} else {
|
||||||
@ -710,6 +710,12 @@ void InstanceList::saveGroupList()
|
|||||||
groupsArr.insert(name, groupObj);
|
groupsArr.insert(name, groupObj);
|
||||||
}
|
}
|
||||||
toplevel.insert("groups", groupsArr);
|
toplevel.insert("groups", groupsArr);
|
||||||
|
// empty string represents ungrouped "group"
|
||||||
|
if (m_collapsedGroups.contains("")) {
|
||||||
|
QJsonObject ungrouped;
|
||||||
|
ungrouped.insert("hidden", QJsonValue(true));
|
||||||
|
toplevel.insert("ungrouped", ungrouped);
|
||||||
|
}
|
||||||
QJsonDocument doc(toplevel);
|
QJsonDocument doc(toplevel);
|
||||||
try {
|
try {
|
||||||
FS::write(groupFileName, doc.toJson());
|
FS::write(groupFileName, doc.toJson());
|
||||||
@ -805,6 +811,16 @@ void InstanceList::loadGroupList()
|
|||||||
increaseGroupCount(groupName);
|
increaseGroupCount(groupName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ungroupedHidden = false;
|
||||||
|
if (rootObj.value("ungrouped").isObject()) {
|
||||||
|
QJsonObject ungrouped = rootObj.value("ungrouped").toObject();
|
||||||
|
ungroupedHidden = ungrouped.value("hidden").toBool(false);
|
||||||
|
}
|
||||||
|
if (ungroupedHidden) {
|
||||||
|
// empty string represents ungrouped "group"
|
||||||
|
m_collapsedGroups.insert("");
|
||||||
|
}
|
||||||
m_groupsLoaded = true;
|
m_groupsLoaded = true;
|
||||||
qDebug() << "Group list loaded.";
|
qDebug() << "Group list loaded.";
|
||||||
}
|
}
|
||||||
@ -972,7 +988,6 @@ bool InstanceList::commitStagedInstance(const QString& path,
|
|||||||
if (groupName.isEmpty() && !groupName.isNull())
|
if (groupName.isEmpty() && !groupName.isNull())
|
||||||
groupName = QString();
|
groupName = QString();
|
||||||
|
|
||||||
QDir dir;
|
|
||||||
QString instID;
|
QString instID;
|
||||||
InstancePtr inst;
|
InstancePtr inst;
|
||||||
|
|
||||||
@ -996,7 +1011,7 @@ bool InstanceList::commitStagedInstance(const QString& path,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!dir.rename(path, destination)) {
|
if (!FS::move(path, destination)) {
|
||||||
qWarning() << "Failed to move" << path << "to" << destination;
|
qWarning() << "Failed to move" << path << "to" << destination;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ enum class GroupsState { NotLoaded, Steady, Dirty };
|
|||||||
|
|
||||||
struct TrashHistoryItem {
|
struct TrashHistoryItem {
|
||||||
QString id;
|
QString id;
|
||||||
QString polyPath;
|
QString path;
|
||||||
QString trashPath;
|
QString trashPath;
|
||||||
QString groupName;
|
QString groupName;
|
||||||
};
|
};
|
||||||
|
@ -22,7 +22,7 @@ class InstancePageProvider : protected QObject, public BasePageProvider {
|
|||||||
public:
|
public:
|
||||||
explicit InstancePageProvider(InstancePtr parent) { inst = parent; }
|
explicit InstancePageProvider(InstancePtr parent) { inst = parent; }
|
||||||
|
|
||||||
virtual ~InstancePageProvider() {};
|
virtual ~InstancePageProvider() = default;
|
||||||
virtual QList<BasePage*> getPages() override
|
virtual QList<BasePage*> getPages() override
|
||||||
{
|
{
|
||||||
QList<BasePage*> values;
|
QList<BasePage*> values;
|
||||||
@ -39,7 +39,7 @@ class InstancePageProvider : protected QObject, public BasePageProvider {
|
|||||||
values.append(new TexturePackPage(onesix.get(), onesix->texturePackList()));
|
values.append(new TexturePackPage(onesix.get(), onesix->texturePackList()));
|
||||||
values.append(new ShaderPackPage(onesix.get(), onesix->shaderPackList()));
|
values.append(new ShaderPackPage(onesix.get(), onesix->shaderPackList()));
|
||||||
values.append(new NotesPage(onesix.get()));
|
values.append(new NotesPage(onesix.get()));
|
||||||
values.append(new WorldListPage(onesix.get(), onesix->worldList()));
|
values.append(new WorldListPage(onesix, onesix->worldList()));
|
||||||
values.append(new ServersPage(onesix));
|
values.append(new ServersPage(onesix));
|
||||||
// values.append(new GameOptionsPage(onesix.get()));
|
// values.append(new GameOptionsPage(onesix.get()));
|
||||||
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
|
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "InstanceTask.h"
|
#include "InstanceTask.h"
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "settings/SettingsObject.h"
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
|
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
@ -22,6 +24,9 @@ InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& ol
|
|||||||
|
|
||||||
ShouldUpdate askIfShouldUpdate(QWidget* parent, QString original_version_name)
|
ShouldUpdate askIfShouldUpdate(QWidget* parent, QString original_version_name)
|
||||||
{
|
{
|
||||||
|
if (APPLICATION->settings()->get("SkipModpackUpdatePrompt").toBool())
|
||||||
|
return ShouldUpdate::SkipUpdating;
|
||||||
|
|
||||||
auto info = CustomMessageBox::selectable(
|
auto info = CustomMessageBox::selectable(
|
||||||
parent, QObject::tr("Similar modpack was found!"),
|
parent, QObject::tr("Similar modpack was found!"),
|
||||||
QObject::tr(
|
QObject::tr(
|
||||||
|
@ -63,7 +63,7 @@ bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget* parent)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::javaWasOk(QWidget* parent, const JavaCheckResult& result)
|
void JavaCommon::javaWasOk(QWidget* parent, const JavaChecker::Result& result)
|
||||||
{
|
{
|
||||||
QString text;
|
QString text;
|
||||||
text += QObject::tr(
|
text += QObject::tr(
|
||||||
@ -79,7 +79,7 @@ void JavaCommon::javaWasOk(QWidget* parent, const JavaCheckResult& result)
|
|||||||
CustomMessageBox::selectable(parent, QObject::tr("Java test success"), text, QMessageBox::Information)->show();
|
CustomMessageBox::selectable(parent, QObject::tr("Java test success"), text, QMessageBox::Information)->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::javaArgsWereBad(QWidget* parent, const JavaCheckResult& result)
|
void JavaCommon::javaArgsWereBad(QWidget* parent, const JavaChecker::Result& result)
|
||||||
{
|
{
|
||||||
auto htmlError = result.errorLog;
|
auto htmlError = result.errorLog;
|
||||||
QString text;
|
QString text;
|
||||||
@ -89,7 +89,7 @@ void JavaCommon::javaArgsWereBad(QWidget* parent, const JavaCheckResult& result)
|
|||||||
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
|
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::javaBinaryWasBad(QWidget* parent, const JavaCheckResult& result)
|
void JavaCommon::javaBinaryWasBad(QWidget* parent, const JavaChecker::Result& result)
|
||||||
{
|
{
|
||||||
QString text;
|
QString text;
|
||||||
text += QObject::tr(
|
text += QObject::tr(
|
||||||
@ -116,34 +116,26 @@ void JavaCommon::TestCheck::run()
|
|||||||
emit finished();
|
emit finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checker.reset(new JavaChecker());
|
checker.reset(new JavaChecker(m_path, "", 0, 0, 0, 0, this));
|
||||||
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinished);
|
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinished);
|
||||||
checker->m_path = m_path;
|
checker->start();
|
||||||
checker->performCheck();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::TestCheck::checkFinished(JavaCheckResult result)
|
void JavaCommon::TestCheck::checkFinished(const JavaChecker::Result& result)
|
||||||
{
|
{
|
||||||
if (result.validity != JavaCheckResult::Validity::Valid) {
|
if (result.validity != JavaChecker::Result::Validity::Valid) {
|
||||||
javaBinaryWasBad(m_parent, result);
|
javaBinaryWasBad(m_parent, result);
|
||||||
emit finished();
|
emit finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checker.reset(new JavaChecker());
|
checker.reset(new JavaChecker(m_path, m_args, m_maxMem, m_maxMem, result.javaVersion.requiresPermGen() ? m_permGen : 0, 0, this));
|
||||||
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinishedWithArgs);
|
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinishedWithArgs);
|
||||||
checker->m_path = m_path;
|
checker->start();
|
||||||
checker->m_args = m_args;
|
|
||||||
checker->m_minMem = m_minMem;
|
|
||||||
checker->m_maxMem = m_maxMem;
|
|
||||||
if (result.javaVersion.requiresPermGen()) {
|
|
||||||
checker->m_permGen = m_permGen;
|
|
||||||
}
|
|
||||||
checker->performCheck();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::TestCheck::checkFinishedWithArgs(JavaCheckResult result)
|
void JavaCommon::TestCheck::checkFinishedWithArgs(const JavaChecker::Result& result)
|
||||||
{
|
{
|
||||||
if (result.validity == JavaCheckResult::Validity::Valid) {
|
if (result.validity == JavaChecker::Result::Validity::Valid) {
|
||||||
javaWasOk(m_parent, result);
|
javaWasOk(m_parent, result);
|
||||||
emit finished();
|
emit finished();
|
||||||
return;
|
return;
|
||||||
|
@ -10,11 +10,11 @@ namespace JavaCommon {
|
|||||||
bool checkJVMArgs(QString args, QWidget* parent);
|
bool checkJVMArgs(QString args, QWidget* parent);
|
||||||
|
|
||||||
// Show a dialog saying that the Java binary was usable
|
// Show a dialog saying that the Java binary was usable
|
||||||
void javaWasOk(QWidget* parent, const JavaCheckResult& result);
|
void javaWasOk(QWidget* parent, const JavaChecker::Result& result);
|
||||||
// Show a dialog saying that the Java binary was not usable because of bad options
|
// Show a dialog saying that the Java binary was not usable because of bad options
|
||||||
void javaArgsWereBad(QWidget* parent, const JavaCheckResult& result);
|
void javaArgsWereBad(QWidget* parent, const JavaChecker::Result& result);
|
||||||
// Show a dialog saying that the Java binary was not usable
|
// Show a dialog saying that the Java binary was not usable
|
||||||
void javaBinaryWasBad(QWidget* parent, const JavaCheckResult& result);
|
void javaBinaryWasBad(QWidget* parent, const JavaChecker::Result& result);
|
||||||
// Show a dialog if we couldn't find Java Checker
|
// Show a dialog if we couldn't find Java Checker
|
||||||
void javaCheckNotFound(QWidget* parent);
|
void javaCheckNotFound(QWidget* parent);
|
||||||
|
|
||||||
@ -32,11 +32,11 @@ class TestCheck : public QObject {
|
|||||||
void finished();
|
void finished();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void checkFinished(JavaCheckResult result);
|
void checkFinished(const JavaChecker::Result& result);
|
||||||
void checkFinishedWithArgs(JavaCheckResult result);
|
void checkFinishedWithArgs(const JavaChecker::Result& result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<JavaChecker> checker;
|
JavaChecker::Ptr checker;
|
||||||
QWidget* m_parent = nullptr;
|
QWidget* m_parent = nullptr;
|
||||||
QString m_path;
|
QString m_path;
|
||||||
QString m_args;
|
QString m_args;
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
#include "LaunchController.h"
|
#include "LaunchController.h"
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
#include "launch/steps/PrintServers.h"
|
||||||
#include "minecraft/auth/AccountData.h"
|
#include "minecraft/auth/AccountData.h"
|
||||||
#include "minecraft/auth/AccountList.h"
|
#include "minecraft/auth/AccountList.h"
|
||||||
#include "settings/MissingAuthlibInjectorBehavior.h"
|
#include "settings/MissingAuthlibInjectorBehavior.h"
|
||||||
@ -55,14 +56,12 @@
|
|||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <QRegularExpression>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
#include "JavaCommon.h"
|
#include "JavaCommon.h"
|
||||||
#include "launch/steps/TextPrint.h"
|
#include "launch/steps/TextPrint.h"
|
||||||
#include "meta/Index.h"
|
|
||||||
#include "meta/VersionList.h"
|
|
||||||
#include "minecraft/auth/AccountTask.h"
|
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
LaunchController::LaunchController(QObject* parent) : Task(parent) {}
|
LaunchController::LaunchController(QObject* parent) : Task(parent) {}
|
||||||
@ -90,7 +89,7 @@ void LaunchController::decideAccount()
|
|||||||
|
|
||||||
// Find an account to use.
|
// Find an account to use.
|
||||||
auto accounts = APPLICATION->accounts();
|
auto accounts = APPLICATION->accounts();
|
||||||
if (accounts->count() <= 0) {
|
if (accounts->count() <= 0 || !accounts->anyAccountIsValid()) {
|
||||||
// Tell the user they need to log in at least one account in order to play.
|
// Tell the user they need to log in at least one account in order to play.
|
||||||
auto reply = CustomMessageBox::selectable(m_parentWidget, tr("No Accounts"),
|
auto reply = CustomMessageBox::selectable(m_parentWidget, tr("No Accounts"),
|
||||||
tr("In order to play Minecraft, you must pick your username or log in to an account "
|
tr("In order to play Minecraft, you must pick your username or log in to an account "
|
||||||
@ -133,12 +132,63 @@ void LaunchController::decideAccount()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LaunchController::askPlayDemo()
|
||||||
|
{
|
||||||
|
QMessageBox box(m_parentWidget);
|
||||||
|
box.setWindowTitle(tr("Play demo?"));
|
||||||
|
box.setText(
|
||||||
|
tr("This account does not own Minecraft.\nYou need to purchase the game first to play it.\n\nDo you want to play "
|
||||||
|
"the demo?"));
|
||||||
|
box.setIcon(QMessageBox::Warning);
|
||||||
|
auto demoButton = box.addButton(tr("Play Demo"), QMessageBox::ButtonRole::YesRole);
|
||||||
|
auto cancelButton = box.addButton(tr("Cancel"), QMessageBox::ButtonRole::NoRole);
|
||||||
|
box.setDefaultButton(cancelButton);
|
||||||
|
|
||||||
|
box.exec();
|
||||||
|
return box.clickedButton() == demoButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LaunchController::askOfflineName(QString playerName, bool demo, bool& ok)
|
||||||
|
{
|
||||||
|
// we ask the user for a player name
|
||||||
|
QString message = tr("Choose your offline mode player name.");
|
||||||
|
if (demo) {
|
||||||
|
message = tr("Choose your demo mode player name.");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
|
||||||
|
QString usedname = lastOfflinePlayerName.isEmpty() ? playerName : lastOfflinePlayerName;
|
||||||
|
QString name = QInputDialog::getText(m_parentWidget, tr("Player name"), message, QLineEdit::Normal, usedname, &ok);
|
||||||
|
if (!ok)
|
||||||
|
return {};
|
||||||
|
if (name.length()) {
|
||||||
|
usedname = name;
|
||||||
|
APPLICATION->settings()->set("LastOfflinePlayerName", usedname);
|
||||||
|
}
|
||||||
|
return usedname;
|
||||||
|
}
|
||||||
|
|
||||||
void LaunchController::login()
|
void LaunchController::login()
|
||||||
{
|
{
|
||||||
decideAccount();
|
decideAccount();
|
||||||
|
|
||||||
// if no account is selected, we bail
|
|
||||||
if (!m_accountToUse) {
|
if (!m_accountToUse) {
|
||||||
|
// if no account is selected, ask about demo
|
||||||
|
if (!m_demo) {
|
||||||
|
m_demo = askPlayDemo();
|
||||||
|
}
|
||||||
|
if (m_demo) {
|
||||||
|
// we ask the user for a player name
|
||||||
|
bool ok = false;
|
||||||
|
auto name = askOfflineName("Player", m_demo, ok);
|
||||||
|
if (ok) {
|
||||||
|
m_session = std::make_shared<AuthSession>();
|
||||||
|
m_session->MakeDemo(name, MinecraftAccount::uuidFromUsername(name).toString().remove(QRegularExpression("[{}-]")));
|
||||||
|
launchInstance();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if no account is selected, we bail
|
||||||
emitFailed(tr("No account selected for launch."));
|
emitFailed(tr("No account selected for launch."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -237,7 +287,8 @@ 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) {
|
if ((m_accountToUse->accountType() != AccountType::Offline && m_accountToUse->accountState() == AccountState::Offline) ||
|
||||||
|
m_accountToUse->shouldRefresh()) {
|
||||||
// Force account refresh on the account used to launch the instance updating the AccountState
|
// 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
|
// only on first try and if it is not meant to be offline
|
||||||
auto accounts = APPLICATION->accounts();
|
auto accounts = APPLICATION->accounts();
|
||||||
@ -275,24 +326,12 @@ void LaunchController::login()
|
|||||||
if (!m_session->wants_online) {
|
if (!m_session->wants_online) {
|
||||||
// we ask the user for a player name
|
// we ask the user for a player name
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
auto name = askOfflineName(m_session->player_name, m_session->demo, ok);
|
||||||
QString message = tr("Choose your offline mode player name.");
|
|
||||||
if (m_session->demo) {
|
|
||||||
message = tr("Choose your demo mode player name.");
|
|
||||||
}
|
|
||||||
|
|
||||||
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
|
|
||||||
QString usedname = lastOfflinePlayerName.isEmpty() ? m_session->player_name : lastOfflinePlayerName;
|
|
||||||
QString name = QInputDialog::getText(m_parentWidget, tr("Player name"), message, QLineEdit::Normal, usedname, &ok);
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
tryagain = false;
|
tryagain = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (name.length()) {
|
m_session->MakeOffline(name);
|
||||||
usedname = name;
|
|
||||||
APPLICATION->settings()->set("LastOfflinePlayerName", usedname);
|
|
||||||
}
|
|
||||||
m_session->MakeOffline(usedname);
|
|
||||||
// offline flavored game from here :3
|
// offline flavored game from here :3
|
||||||
}
|
}
|
||||||
if (m_accountToUse->ownsMinecraft()) {
|
if (m_accountToUse->ownsMinecraft()) {
|
||||||
@ -312,20 +351,10 @@ void LaunchController::login()
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// play demo ?
|
// play demo ?
|
||||||
QMessageBox box(m_parentWidget);
|
if (!m_session->demo) {
|
||||||
box.setWindowTitle(tr("Play demo?"));
|
m_session->demo = askPlayDemo();
|
||||||
box.setText(
|
}
|
||||||
tr("This account does not own Minecraft.\nYou need to purchase the game first to play it.\n\nDo you want to play "
|
if (m_session->demo) { // play demo here
|
||||||
"the demo?"));
|
|
||||||
box.setIcon(QMessageBox::Warning);
|
|
||||||
auto demoButton = box.addButton(tr("Play Demo"), QMessageBox::ButtonRole::YesRole);
|
|
||||||
auto cancelButton = box.addButton(tr("Cancel"), QMessageBox::ButtonRole::NoRole);
|
|
||||||
box.setDefaultButton(cancelButton);
|
|
||||||
|
|
||||||
box.exec();
|
|
||||||
if (box.clickedButton() == demoButton) {
|
|
||||||
// play demo here
|
|
||||||
m_session->MakeDemo();
|
|
||||||
launchInstance();
|
launchInstance();
|
||||||
} else {
|
} else {
|
||||||
emitFailed(tr("Launch cancelled - account does not own Minecraft."));
|
emitFailed(tr("Launch cancelled - account does not own Minecraft."));
|
||||||
@ -388,7 +417,7 @@ void LaunchController::launchInstance()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_launcher = m_instance->createLaunchTask(m_session, m_serverToJoin);
|
m_launcher = m_instance->createLaunchTask(m_session, m_targetToJoin);
|
||||||
if (!m_launcher) {
|
if (!m_launcher) {
|
||||||
emitFailed(tr("Couldn't instantiate a launcher."));
|
emitFailed(tr("Couldn't instantiate a launcher."));
|
||||||
return;
|
return;
|
||||||
@ -411,25 +440,8 @@ void LaunchController::launchInstance()
|
|||||||
|
|
||||||
// Prepend Server Status
|
// Prepend Server Status
|
||||||
QStringList servers = { "login.live.com", "session.minecraft.net", "textures.minecraft.net", "api.mojang.com" };
|
QStringList servers = { "login.live.com", "session.minecraft.net", "textures.minecraft.net", "api.mojang.com" };
|
||||||
QString resolved_servers = "";
|
|
||||||
QHostInfo host_info;
|
|
||||||
|
|
||||||
for (QString server : servers) {
|
m_launcher->prependStep(makeShared<PrintServers>(m_launcher.get(), servers));
|
||||||
host_info = QHostInfo::fromName(server);
|
|
||||||
resolved_servers = resolved_servers + server + " resolves to:\n [";
|
|
||||||
if (!host_info.addresses().isEmpty()) {
|
|
||||||
for (QHostAddress address : host_info.addresses()) {
|
|
||||||
resolved_servers = resolved_servers + address.toString();
|
|
||||||
if (!host_info.addresses().endsWith(address)) {
|
|
||||||
resolved_servers = resolved_servers + ", ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
resolved_servers = resolved_servers + "N/A";
|
|
||||||
}
|
|
||||||
resolved_servers = resolved_servers + "]\n\n";
|
|
||||||
}
|
|
||||||
m_launcher->prependStep(makeShared<TextPrint>(m_launcher.get(), resolved_servers, MessageLevel::Launcher));
|
|
||||||
} else {
|
} else {
|
||||||
online_mode = m_demo ? "demo" : "offline";
|
online_mode = m_demo ? "demo" : "offline";
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
#include "minecraft/MinecraftInstance.h"
|
#include "minecraft/MinecraftInstance.h"
|
||||||
#include "minecraft/PackProfile.h"
|
#include "minecraft/PackProfile.h"
|
||||||
#include "minecraft/auth/MinecraftAccount.h"
|
#include "minecraft/auth/MinecraftAccount.h"
|
||||||
#include "minecraft/launch/MinecraftServerTarget.h"
|
#include "minecraft/launch/MinecraftTarget.h"
|
||||||
|
|
||||||
class InstanceWindow;
|
class InstanceWindow;
|
||||||
class LaunchController : public Task {
|
class LaunchController : public Task {
|
||||||
@ -50,7 +50,7 @@ class LaunchController : public Task {
|
|||||||
void executeTask() override;
|
void executeTask() override;
|
||||||
|
|
||||||
LaunchController(QObject* parent = nullptr);
|
LaunchController(QObject* parent = nullptr);
|
||||||
virtual ~LaunchController() {};
|
virtual ~LaunchController() = default;
|
||||||
|
|
||||||
void setInstance(InstancePtr instance) { m_instance = instance; }
|
void setInstance(InstancePtr instance) { m_instance = instance; }
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ class LaunchController : public Task {
|
|||||||
|
|
||||||
void setParentWidget(QWidget* widget) { m_parentWidget = widget; }
|
void setParentWidget(QWidget* widget) { m_parentWidget = widget; }
|
||||||
|
|
||||||
void setServerToJoin(MinecraftServerTargetPtr serverToJoin) { m_serverToJoin = std::move(serverToJoin); }
|
void setTargetToJoin(MinecraftTarget::Ptr targetToJoin) { m_targetToJoin = std::move(targetToJoin); }
|
||||||
|
|
||||||
void setAccountToUse(MinecraftAccountPtr accountToUse) { m_accountToUse = std::move(accountToUse); }
|
void setAccountToUse(MinecraftAccountPtr accountToUse) { m_accountToUse = std::move(accountToUse); }
|
||||||
|
|
||||||
@ -76,6 +76,8 @@ class LaunchController : public Task {
|
|||||||
void login();
|
void login();
|
||||||
void launchInstance();
|
void launchInstance();
|
||||||
void decideAccount();
|
void decideAccount();
|
||||||
|
bool askPlayDemo();
|
||||||
|
QString askOfflineName(QString playerName, bool demo, bool& ok);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void readyForLaunch();
|
void readyForLaunch();
|
||||||
@ -94,5 +96,5 @@ class LaunchController : public Task {
|
|||||||
MinecraftAccountPtr m_accountToUse = nullptr;
|
MinecraftAccountPtr m_accountToUse = nullptr;
|
||||||
AuthSessionPtr m_session;
|
AuthSessionPtr m_session;
|
||||||
shared_qobject_ptr<LaunchTask> m_launcher;
|
shared_qobject_ptr<LaunchTask> m_launcher;
|
||||||
MinecraftServerTargetPtr m_serverToJoin;
|
MinecraftTarget::Ptr m_targetToJoin;
|
||||||
};
|
};
|
||||||
|
@ -39,7 +39,8 @@
|
|||||||
#include <QTextDecoder>
|
#include <QTextDecoder>
|
||||||
#include "MessageLevel.h"
|
#include "MessageLevel.h"
|
||||||
|
|
||||||
LoggedProcess::LoggedProcess(QObject* parent) : QProcess(parent)
|
LoggedProcess::LoggedProcess(const QTextCodec* output_codec, QObject* parent)
|
||||||
|
: QProcess(parent), m_err_decoder(output_codec), m_out_decoder(output_codec)
|
||||||
{
|
{
|
||||||
// QProcess has a strange interface... let's map a lot of those into a few.
|
// QProcess has a strange interface... let's map a lot of those into a few.
|
||||||
connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut);
|
connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut);
|
||||||
|
@ -49,7 +49,7 @@ class LoggedProcess : public QProcess {
|
|||||||
enum State { NotRunning, Starting, FailedToStart, Running, Finished, Crashed, Aborted };
|
enum State { NotRunning, Starting, FailedToStart, Running, Finished, Crashed, Aborted };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit LoggedProcess(QObject* parent = 0);
|
explicit LoggedProcess(const QTextCodec* output_codec = QTextCodec::codecForLocale(), QObject* parent = 0);
|
||||||
virtual ~LoggedProcess();
|
virtual ~LoggedProcess();
|
||||||
|
|
||||||
State state() const;
|
State state() const;
|
||||||
@ -80,8 +80,8 @@ class LoggedProcess : public QProcess {
|
|||||||
QStringList reprocess(const QByteArray& data, QTextDecoder& decoder);
|
QStringList reprocess(const QByteArray& data, QTextDecoder& decoder);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTextDecoder m_err_decoder = QTextDecoder(QTextCodec::codecForLocale());
|
QTextDecoder m_err_decoder;
|
||||||
QTextDecoder m_out_decoder = QTextDecoder(QTextCodec::codecForLocale());
|
QTextDecoder m_out_decoder;
|
||||||
QString m_leftover_line;
|
QString m_leftover_line;
|
||||||
bool m_killed = false;
|
bool m_killed = false;
|
||||||
State m_state = NotRunning;
|
State m_state = NotRunning;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* Prism Launcher - Minecraft Launcher
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QFileInfo>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
#if defined(LAUNCHER_APPLICATION)
|
#if defined(LAUNCHER_APPLICATION)
|
||||||
@ -122,7 +123,7 @@ bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files,
|
|||||||
zip.setUtf8Enabled(true);
|
zip.setUtf8Enabled(true);
|
||||||
QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
|
QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
|
||||||
if (!zip.open(QuaZip::mdCreate)) {
|
if (!zip.open(QuaZip::mdCreate)) {
|
||||||
QFile::remove(fileCompressed);
|
FS::deletePath(fileCompressed);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +131,7 @@ bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files,
|
|||||||
|
|
||||||
zip.close();
|
zip.close();
|
||||||
if (zip.getZipError() != 0) {
|
if (zip.getZipError() != 0) {
|
||||||
QFile::remove(fileCompressed);
|
FS::deletePath(fileCompressed);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +145,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
|
|||||||
QuaZip zipOut(targetJarPath);
|
QuaZip zipOut(targetJarPath);
|
||||||
zipOut.setUtf8Enabled(true);
|
zipOut.setUtf8Enabled(true);
|
||||||
if (!zipOut.open(QuaZip::mdCreate)) {
|
if (!zipOut.open(QuaZip::mdCreate)) {
|
||||||
QFile::remove(targetJarPath);
|
FS::deletePath(targetJarPath);
|
||||||
qCritical() << "Failed to open the minecraft.jar for modding";
|
qCritical() << "Failed to open the minecraft.jar for modding";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -162,7 +163,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
|
|||||||
if (mod->type() == ResourceType::ZIPFILE) {
|
if (mod->type() == ResourceType::ZIPFILE) {
|
||||||
if (!mergeZipFiles(&zipOut, mod->fileinfo(), addedFiles)) {
|
if (!mergeZipFiles(&zipOut, mod->fileinfo(), addedFiles)) {
|
||||||
zipOut.close();
|
zipOut.close();
|
||||||
QFile::remove(targetJarPath);
|
FS::deletePath(targetJarPath);
|
||||||
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -171,7 +172,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
|
|||||||
auto filename = mod->fileinfo();
|
auto filename = mod->fileinfo();
|
||||||
if (!JlCompress::compressFile(&zipOut, filename.absoluteFilePath(), filename.fileName())) {
|
if (!JlCompress::compressFile(&zipOut, filename.absoluteFilePath(), filename.fileName())) {
|
||||||
zipOut.close();
|
zipOut.close();
|
||||||
QFile::remove(targetJarPath);
|
FS::deletePath(targetJarPath);
|
||||||
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -194,7 +195,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
|
|||||||
|
|
||||||
if (!compressDirFiles(&zipOut, parent_dir, files)) {
|
if (!compressDirFiles(&zipOut, parent_dir, files)) {
|
||||||
zipOut.close();
|
zipOut.close();
|
||||||
QFile::remove(targetJarPath);
|
FS::deletePath(targetJarPath);
|
||||||
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -202,7 +203,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
|
|||||||
} else {
|
} else {
|
||||||
// Make sure we do not continue launching when something is missing or undefined...
|
// Make sure we do not continue launching when something is missing or undefined...
|
||||||
zipOut.close();
|
zipOut.close();
|
||||||
QFile::remove(targetJarPath);
|
FS::deletePath(targetJarPath);
|
||||||
qCritical() << "Failed to add unknown mod type" << mod->fileinfo().fileName() << "to the jar.";
|
qCritical() << "Failed to add unknown mod type" << mod->fileinfo().fileName() << "to the jar.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -210,7 +211,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
|
|||||||
|
|
||||||
if (!mergeZipFiles(&zipOut, QFileInfo(sourceJarPath), addedFiles, [](const QString key) { return !key.contains("META-INF"); })) {
|
if (!mergeZipFiles(&zipOut, QFileInfo(sourceJarPath), addedFiles, [](const QString key) { return !key.contains("META-INF"); })) {
|
||||||
zipOut.close();
|
zipOut.close();
|
||||||
QFile::remove(targetJarPath);
|
FS::deletePath(targetJarPath);
|
||||||
qCritical() << "Failed to insert minecraft.jar contents.";
|
qCritical() << "Failed to insert minecraft.jar contents.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -218,7 +219,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
|
|||||||
// Recompress the jar
|
// Recompress the jar
|
||||||
zipOut.close();
|
zipOut.close();
|
||||||
if (zipOut.getZipError() != 0) {
|
if (zipOut.getZipError() != 0) {
|
||||||
QFile::remove(targetJarPath);
|
FS::deletePath(targetJarPath);
|
||||||
qCritical() << "Failed to finalize minecraft.jar!";
|
qCritical() << "Failed to finalize minecraft.jar!";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -330,9 +331,31 @@ std::optional<QStringList> extractSubDir(QuaZip* zip, const QString& subdir, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
extracted.append(target_file_path);
|
extracted.append(target_file_path);
|
||||||
QFile::setPermissions(target_file_path,
|
auto fileInfo = QFileInfo(target_file_path);
|
||||||
QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser);
|
if (fileInfo.isFile()) {
|
||||||
|
auto permissions = fileInfo.permissions();
|
||||||
|
auto maxPermisions = QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser |
|
||||||
|
QFileDevice::Permission::ReadGroup | QFileDevice::Permission::ReadOther;
|
||||||
|
auto minPermisions = QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser;
|
||||||
|
|
||||||
|
auto newPermisions = (permissions & maxPermisions) | minPermisions;
|
||||||
|
if (newPermisions != permissions) {
|
||||||
|
if (!QFile::setPermissions(target_file_path, newPermisions)) {
|
||||||
|
qWarning() << (QObject::tr("Could not fix permissions for %1").arg(target_file_path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (fileInfo.isDir()) {
|
||||||
|
// Ensure the folder has the minimal required permissions
|
||||||
|
QFile::Permissions minimalPermissions = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner | QFile::ReadGroup |
|
||||||
|
QFile::ExeGroup | QFile::ReadOther | QFile::ExeOther;
|
||||||
|
|
||||||
|
QFile::Permissions currentPermissions = fileInfo.permissions();
|
||||||
|
if ((currentPermissions & minimalPermissions) != minimalPermissions) {
|
||||||
|
if (!QFile::setPermissions(target_file_path, minimalPermissions)) {
|
||||||
|
qWarning() << (QObject::tr("Could not fix permissions for %1").arg(target_file_path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
qDebug() << "Extracted file" << relative_file_name << "to" << target_file_path;
|
qDebug() << "Extracted file" << relative_file_name << "to" << target_file_path;
|
||||||
} while (zip->goToNextFile());
|
} while (zip->goToNextFile());
|
||||||
|
|
||||||
@ -466,7 +489,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())
|
||||||
@ -490,10 +513,10 @@ auto ExportToZipTask::exportZip() -> ZipResult
|
|||||||
void ExportToZipTask::finish()
|
void ExportToZipTask::finish()
|
||||||
{
|
{
|
||||||
if (m_build_zip_future.isCanceled()) {
|
if (m_build_zip_future.isCanceled()) {
|
||||||
QFile::remove(m_output_path);
|
FS::deletePath(m_output_path);
|
||||||
emitAborted();
|
emitAborted();
|
||||||
} else if (auto result = m_build_zip_future.result(); result.has_value()) {
|
} else if (auto result = m_build_zip_future.result(); result.has_value()) {
|
||||||
QFile::remove(m_output_path);
|
FS::deletePath(m_output_path);
|
||||||
emitFailed(result.value());
|
emitFailed(result.value());
|
||||||
} else {
|
} else {
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
@ -510,6 +533,138 @@ bool ExportToZipTask::abort()
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
void ExtractZipTask::executeTask()
|
||||||
|
{
|
||||||
|
if (!m_input->isOpen() && !m_input->open(QuaZip::mdUnzip)) {
|
||||||
|
emitFailed(tr("Unable to open supplied zip file."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_zip_future = QtConcurrent::run(QThreadPool::globalInstance(), [this]() { return extractZip(); });
|
||||||
|
connect(&m_zip_watcher, &QFutureWatcher<ZipResult>::finished, this, &ExtractZipTask::finish);
|
||||||
|
m_zip_watcher.setFuture(m_zip_future);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExtractZipTask::extractZip() -> ZipResult
|
||||||
|
{
|
||||||
|
auto target = m_output_dir.absolutePath();
|
||||||
|
auto target_top_dir = QUrl::fromLocalFile(target);
|
||||||
|
|
||||||
|
QStringList extracted;
|
||||||
|
|
||||||
|
qDebug() << "Extracting subdir" << m_subdirectory << "from" << m_input->getZipName() << "to" << target;
|
||||||
|
auto numEntries = m_input->getEntriesCount();
|
||||||
|
if (numEntries < 0) {
|
||||||
|
return ZipResult(tr("Failed to enumerate files in archive"));
|
||||||
|
}
|
||||||
|
if (numEntries == 0) {
|
||||||
|
logWarning(tr("Extracting empty archives seems odd..."));
|
||||||
|
return ZipResult();
|
||||||
|
}
|
||||||
|
if (!m_input->goToFirstFile()) {
|
||||||
|
return ZipResult(tr("Failed to seek to first file in zip"));
|
||||||
|
}
|
||||||
|
|
||||||
|
setStatus("Extracting files...");
|
||||||
|
setProgress(0, numEntries);
|
||||||
|
do {
|
||||||
|
if (m_zip_future.isCanceled())
|
||||||
|
return ZipResult();
|
||||||
|
setProgress(m_progress + 1, m_progressTotal);
|
||||||
|
QString file_name = m_input->getCurrentFileName();
|
||||||
|
if (!file_name.startsWith(m_subdirectory))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto relative_file_name = QDir::fromNativeSeparators(file_name.mid(m_subdirectory.size()));
|
||||||
|
auto original_name = relative_file_name;
|
||||||
|
setStatus("Unziping: " + relative_file_name);
|
||||||
|
|
||||||
|
// Fix subdirs/files ending with a / getting transformed into absolute paths
|
||||||
|
if (relative_file_name.startsWith('/'))
|
||||||
|
relative_file_name = relative_file_name.mid(1);
|
||||||
|
|
||||||
|
// Fix weird "folders with a single file get squashed" thing
|
||||||
|
QString sub_path;
|
||||||
|
if (relative_file_name.contains('/') && !relative_file_name.endsWith('/')) {
|
||||||
|
sub_path = relative_file_name.section('/', 0, -2) + '/';
|
||||||
|
FS::ensureFolderPathExists(FS::PathCombine(target, sub_path));
|
||||||
|
|
||||||
|
relative_file_name = relative_file_name.split('/').last();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString target_file_path;
|
||||||
|
if (relative_file_name.isEmpty()) {
|
||||||
|
target_file_path = target + '/';
|
||||||
|
} else {
|
||||||
|
target_file_path = FS::PathCombine(target_top_dir.toLocalFile(), sub_path, relative_file_name);
|
||||||
|
if (relative_file_name.endsWith('/') && !target_file_path.endsWith('/'))
|
||||||
|
target_file_path += '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!target_top_dir.isParentOf(QUrl::fromLocalFile(target_file_path))) {
|
||||||
|
return ZipResult(tr("Extracting %1 was cancelled, because it was effectively outside of the target path %2")
|
||||||
|
.arg(relative_file_name, target));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!JlCompress::extractFile(m_input.get(), "", target_file_path)) {
|
||||||
|
JlCompress::removeFile(extracted);
|
||||||
|
return ZipResult(tr("Failed to extract file %1 to %2").arg(original_name, target_file_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
extracted.append(target_file_path);
|
||||||
|
auto fileInfo = QFileInfo(target_file_path);
|
||||||
|
if (fileInfo.isFile()) {
|
||||||
|
auto permissions = fileInfo.permissions();
|
||||||
|
auto maxPermisions = QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser |
|
||||||
|
QFileDevice::Permission::ReadGroup | QFileDevice::Permission::ReadOther;
|
||||||
|
auto minPermisions = QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser;
|
||||||
|
|
||||||
|
auto newPermisions = (permissions & maxPermisions) | minPermisions;
|
||||||
|
if (newPermisions != permissions) {
|
||||||
|
if (!QFile::setPermissions(target_file_path, newPermisions)) {
|
||||||
|
logWarning(tr("Could not fix permissions for %1").arg(target_file_path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (fileInfo.isDir()) {
|
||||||
|
// Ensure the folder has the minimal required permissions
|
||||||
|
QFile::Permissions minimalPermissions = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner | QFile::ReadGroup |
|
||||||
|
QFile::ExeGroup | QFile::ReadOther | QFile::ExeOther;
|
||||||
|
|
||||||
|
QFile::Permissions currentPermissions = fileInfo.permissions();
|
||||||
|
if ((currentPermissions & minimalPermissions) != minimalPermissions) {
|
||||||
|
if (!QFile::setPermissions(target_file_path, minimalPermissions)) {
|
||||||
|
logWarning(tr("Could not fix permissions for %1").arg(target_file_path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Extracted file" << relative_file_name << "to" << target_file_path;
|
||||||
|
} while (m_input->goToNextFile());
|
||||||
|
|
||||||
|
return ZipResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractZipTask::finish()
|
||||||
|
{
|
||||||
|
if (m_zip_future.isCanceled()) {
|
||||||
|
emitAborted();
|
||||||
|
} else if (auto result = m_zip_future.result(); result.has_value()) {
|
||||||
|
emitFailed(result.value());
|
||||||
|
} else {
|
||||||
|
emitSucceeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExtractZipTask::abort()
|
||||||
|
{
|
||||||
|
if (m_zip_future.isRunning()) {
|
||||||
|
m_zip_future.cancel();
|
||||||
|
// NOTE: Here we don't do `emitAborted()` because it will be done when `m_build_zip_future` actually cancels, which may not occur
|
||||||
|
// immediately.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
} // namespace MMCZip
|
} // namespace MMCZip
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* Prism Launcher - Minecraft Launcher
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -153,6 +153,7 @@ bool collectFileListRecursively(const QString& rootDir, const QString& subDir, Q
|
|||||||
|
|
||||||
#if defined(LAUNCHER_APPLICATION)
|
#if defined(LAUNCHER_APPLICATION)
|
||||||
class ExportToZipTask : public Task {
|
class ExportToZipTask : public Task {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ExportToZipTask(QString outputPath,
|
ExportToZipTask(QString outputPath,
|
||||||
QDir dir,
|
QDir dir,
|
||||||
@ -205,5 +206,34 @@ class ExportToZipTask : public Task {
|
|||||||
QFuture<ZipResult> m_build_zip_future;
|
QFuture<ZipResult> m_build_zip_future;
|
||||||
QFutureWatcher<ZipResult> m_build_zip_watcher;
|
QFutureWatcher<ZipResult> m_build_zip_watcher;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ExtractZipTask : public Task {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ExtractZipTask(QString input, QDir outputDir, QString subdirectory = "")
|
||||||
|
: ExtractZipTask(std::make_shared<QuaZip>(input), outputDir, subdirectory)
|
||||||
|
{}
|
||||||
|
ExtractZipTask(std::shared_ptr<QuaZip> input, QDir outputDir, QString subdirectory = "")
|
||||||
|
: m_input(input), m_output_dir(outputDir), m_subdirectory(subdirectory)
|
||||||
|
{}
|
||||||
|
virtual ~ExtractZipTask() = default;
|
||||||
|
|
||||||
|
using ZipResult = std::optional<QString>;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void executeTask() override;
|
||||||
|
bool abort() override;
|
||||||
|
|
||||||
|
ZipResult extractZip();
|
||||||
|
void finish();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<QuaZip> m_input;
|
||||||
|
QDir m_output_dir;
|
||||||
|
QString m_subdirectory;
|
||||||
|
|
||||||
|
QFuture<ZipResult> m_zip_future;
|
||||||
|
QFutureWatcher<ZipResult> m_zip_watcher;
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
} // namespace MMCZip
|
} // namespace MMCZip
|
||||||
|
@ -101,7 +101,7 @@ class PixmapCache final : public QObject {
|
|||||||
*/
|
*/
|
||||||
bool _markCacheMissByEviciton()
|
bool _markCacheMissByEviciton()
|
||||||
{
|
{
|
||||||
static constexpr uint maxInt = static_cast<uint>(std::numeric_limits<int>::max());
|
static constexpr uint maxCache = static_cast<uint>(std::numeric_limits<int>::max()) / 4;
|
||||||
static constexpr uint step = 10240;
|
static constexpr uint step = 10240;
|
||||||
static constexpr int oneSecond = 1000;
|
static constexpr int oneSecond = 1000;
|
||||||
|
|
||||||
@ -118,8 +118,8 @@ class PixmapCache final : public QObject {
|
|||||||
if (m_consecutive_fast_evicitons >= m_consecutive_fast_evicitons_threshold) {
|
if (m_consecutive_fast_evicitons >= m_consecutive_fast_evicitons_threshold) {
|
||||||
// increase the cache size
|
// increase the cache size
|
||||||
uint newSize = _cacheLimit() + step;
|
uint newSize = _cacheLimit() + step;
|
||||||
if (newSize >= maxInt) { // increase it until you overflow :D
|
if (newSize >= maxCache) { // increase it until you overflow :D
|
||||||
newSize = maxInt;
|
newSize = maxCache;
|
||||||
qDebug() << m_consecutive_fast_evicitons
|
qDebug() << m_consecutive_fast_evicitons
|
||||||
<< tr("pixmap cache misses by eviction happened too fast, doing nothing as the cache size reached it's limit");
|
<< tr("pixmap cache misses by eviction happened too fast, doing nothing as the cache size reached it's limit");
|
||||||
} else {
|
} else {
|
||||||
|
@ -40,8 +40,8 @@ namespace MangoHud {
|
|||||||
|
|
||||||
QString getLibraryString()
|
QString getLibraryString()
|
||||||
{
|
{
|
||||||
/*
|
/**
|
||||||
* Check for vulkan layers in this order:
|
* Guess MangoHud install location by searching for vulkan layers in this order:
|
||||||
*
|
*
|
||||||
* $VK_LAYER_PATH
|
* $VK_LAYER_PATH
|
||||||
* $XDG_DATA_DIRS (/usr/local/share/:/usr/share/)
|
* $XDG_DATA_DIRS (/usr/local/share/:/usr/share/)
|
||||||
@ -49,8 +49,9 @@ QString getLibraryString()
|
|||||||
* /etc
|
* /etc
|
||||||
* $XDG_CONFIG_DIRS (/etc/xdg)
|
* $XDG_CONFIG_DIRS (/etc/xdg)
|
||||||
* $XDG_CONFIG_HOME (~/.config)
|
* $XDG_CONFIG_HOME (~/.config)
|
||||||
|
*
|
||||||
|
* @returns Absolute path of libMangoHud.so if found and empty QString otherwise.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
QStringList vkLayerList;
|
QStringList vkLayerList;
|
||||||
{
|
{
|
||||||
QString home = QDir::homePath();
|
QString home = QDir::homePath();
|
||||||
@ -85,7 +86,7 @@ QString getLibraryString()
|
|||||||
vkLayerList << FS::PathCombine(xdgConfigHome, "vulkan", "implicit_layer.d");
|
vkLayerList << FS::PathCombine(xdgConfigHome, "vulkan", "implicit_layer.d");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (QString vkLayer : vkLayerList) {
|
for (const QString& vkLayer : vkLayerList) {
|
||||||
// prefer to use architecture specific vulkan layers
|
// prefer to use architecture specific vulkan layers
|
||||||
QString currentArch = QSysInfo::currentCpuArchitecture();
|
QString currentArch = QSysInfo::currentCpuArchitecture();
|
||||||
|
|
||||||
@ -95,8 +96,8 @@ QString getLibraryString()
|
|||||||
|
|
||||||
QStringList manifestNames = { QString("MangoHud.%1.json").arg(currentArch), "MangoHud.json" };
|
QStringList manifestNames = { QString("MangoHud.%1.json").arg(currentArch), "MangoHud.json" };
|
||||||
|
|
||||||
QString filePath = "";
|
QString filePath{};
|
||||||
for (QString manifestName : manifestNames) {
|
for (const QString& manifestName : manifestNames) {
|
||||||
QString tryPath = FS::PathCombine(vkLayer, manifestName);
|
QString tryPath = FS::PathCombine(vkLayer, manifestName);
|
||||||
if (QFile::exists(tryPath)) {
|
if (QFile::exists(tryPath)) {
|
||||||
filePath = tryPath;
|
filePath = tryPath;
|
||||||
@ -107,14 +108,34 @@ QString getLibraryString()
|
|||||||
if (filePath.isEmpty()) {
|
if (filePath.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
auto conf = Json::requireDocument(filePath, vkLayer);
|
||||||
|
auto confObject = Json::requireObject(conf, vkLayer);
|
||||||
|
auto layer = Json::ensureObject(confObject, "layer");
|
||||||
|
QString libraryName = Json::ensureString(layer, "library_path");
|
||||||
|
|
||||||
auto conf = Json::requireDocument(filePath, vkLayer);
|
if (libraryName.isEmpty()) {
|
||||||
auto confObject = Json::requireObject(conf, vkLayer);
|
continue;
|
||||||
auto layer = Json::ensureObject(confObject, "layer");
|
}
|
||||||
return Json::ensureString(layer, "library_path");
|
if (QFileInfo(libraryName).isAbsolute()) {
|
||||||
|
return libraryName;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __GLIBC__
|
||||||
|
// Check whether mangohud is usable on a glibc based system
|
||||||
|
QString libraryPath = findLibrary(libraryName);
|
||||||
|
if (!libraryPath.isEmpty()) {
|
||||||
|
return libraryPath;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// Without glibc return recorded shared library as-is.
|
||||||
|
return libraryName;
|
||||||
|
#endif
|
||||||
|
} catch (const Exception& e) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return QString();
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
QString findLibrary(QString libName)
|
QString findLibrary(QString libName)
|
||||||
|
@ -46,14 +46,14 @@ class NullInstance : public BaseInstance {
|
|||||||
{
|
{
|
||||||
setVersionBroken(true);
|
setVersionBroken(true);
|
||||||
}
|
}
|
||||||
virtual ~NullInstance() {};
|
virtual ~NullInstance() = default;
|
||||||
void saveNow() override {}
|
void saveNow() override {}
|
||||||
void loadSpecificSettings() override { setSpecificSettingsLoaded(true); }
|
void loadSpecificSettings() override { setSpecificSettingsLoaded(true); }
|
||||||
QString getStatusbarDescription() override { return tr("Unknown instance type"); };
|
QString getStatusbarDescription() override { return tr("Unknown instance type"); };
|
||||||
QSet<QString> traits() const override { return {}; };
|
QSet<QString> traits() const override { return {}; };
|
||||||
QString instanceConfigFolder() const override { return instanceRoot(); };
|
QString instanceConfigFolder() const override { return instanceRoot(); };
|
||||||
shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr, MinecraftServerTargetPtr) override { return nullptr; }
|
shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr, MinecraftTarget::Ptr) override { return nullptr; }
|
||||||
shared_qobject_ptr<Task> createUpdateTask([[maybe_unused]] Net::Mode mode) override { return nullptr; }
|
QList<Task::Ptr> createUpdateTask() override { return {}; }
|
||||||
QProcessEnvironment createEnvironment() override { return QProcessEnvironment(); }
|
QProcessEnvironment createEnvironment() override { return QProcessEnvironment(); }
|
||||||
QProcessEnvironment createLaunchEnvironment() override { return QProcessEnvironment(); }
|
QProcessEnvironment createLaunchEnvironment() override { return QProcessEnvironment(); }
|
||||||
QMap<QString, QString> getVariables() override { return QMap<QString, QString>(); }
|
QMap<QString, QString> getVariables() override { return QMap<QString, QString>(); }
|
||||||
@ -64,7 +64,7 @@ class NullInstance : public BaseInstance {
|
|||||||
bool canEdit() const override { return false; }
|
bool canEdit() const override { return false; }
|
||||||
bool canLaunch() const override { return false; }
|
bool canLaunch() const override { return false; }
|
||||||
void populateLaunchMenu(QMenu* menu) override {}
|
void populateLaunchMenu(QMenu* menu) override {}
|
||||||
QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override
|
QStringList verboseDescription(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin) override
|
||||||
{
|
{
|
||||||
QStringList out;
|
QStringList out;
|
||||||
out << "Null instance - placeholder.";
|
out << "Null instance - placeholder.";
|
||||||
|
@ -24,7 +24,9 @@
|
|||||||
#include "minecraft/mod/ModFolderModel.h"
|
#include "minecraft/mod/ModFolderModel.h"
|
||||||
#include "minecraft/mod/ResourceFolderModel.h"
|
#include "minecraft/mod/ResourceFolderModel.h"
|
||||||
|
|
||||||
|
#include "modplatform/helpers/HashUtils.h"
|
||||||
#include "net/ApiDownload.h"
|
#include "net/ApiDownload.h"
|
||||||
|
#include "net/ChecksumValidator.h"
|
||||||
|
|
||||||
ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack,
|
ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack,
|
||||||
ModPlatform::IndexedVersion version,
|
ModPlatform::IndexedVersion version,
|
||||||
@ -53,7 +55,29 @@ ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_filesNetJob->addNetAction(Net::ApiDownload::makeFile(m_pack_version.downloadUrl, dir.absoluteFilePath(getFilename())));
|
auto action = Net::ApiDownload::makeFile(m_pack_version.downloadUrl, dir.absoluteFilePath(getFilename()));
|
||||||
|
if (!m_pack_version.hash_type.isEmpty() && !m_pack_version.hash.isEmpty()) {
|
||||||
|
switch (Hashing::algorithmFromString(m_pack_version.hash_type)) {
|
||||||
|
case Hashing::Algorithm::Md4:
|
||||||
|
action->addValidator(new Net::ChecksumValidator(QCryptographicHash::Algorithm::Md4, m_pack_version.hash));
|
||||||
|
break;
|
||||||
|
case Hashing::Algorithm::Md5:
|
||||||
|
action->addValidator(new Net::ChecksumValidator(QCryptographicHash::Algorithm::Md5, m_pack_version.hash));
|
||||||
|
break;
|
||||||
|
case Hashing::Algorithm::Sha1:
|
||||||
|
action->addValidator(new Net::ChecksumValidator(QCryptographicHash::Algorithm::Sha1, m_pack_version.hash));
|
||||||
|
break;
|
||||||
|
case Hashing::Algorithm::Sha256:
|
||||||
|
action->addValidator(new Net::ChecksumValidator(QCryptographicHash::Algorithm::Sha256, m_pack_version.hash));
|
||||||
|
break;
|
||||||
|
case Hashing::Algorithm::Sha512:
|
||||||
|
action->addValidator(new Net::ChecksumValidator(QCryptographicHash::Algorithm::Sha512, m_pack_version.hash));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_filesNetJob->addNetAction(action);
|
||||||
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &ResourceDownloadTask::downloadSucceeded);
|
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &ResourceDownloadTask::downloadSucceeded);
|
||||||
connect(m_filesNetJob.get(), &NetJob::progress, this, &ResourceDownloadTask::downloadProgressChanged);
|
connect(m_filesNetJob.get(), &NetJob::progress, this, &ResourceDownloadTask::downloadProgressChanged);
|
||||||
connect(m_filesNetJob.get(), &NetJob::stepProgress, this, &ResourceDownloadTask::propagateStepProgress);
|
connect(m_filesNetJob.get(), &NetJob::stepProgress, this, &ResourceDownloadTask::propagateStepProgress);
|
||||||
|
@ -20,13 +20,13 @@
|
|||||||
|
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include "SysInfo.h"
|
||||||
#include "settings/SettingsObject.h"
|
#include "settings/SettingsObject.h"
|
||||||
|
|
||||||
struct RuntimeContext {
|
struct RuntimeContext {
|
||||||
QString javaArchitecture;
|
QString javaArchitecture;
|
||||||
QString javaRealArchitecture;
|
QString javaRealArchitecture;
|
||||||
QString javaPath;
|
QString system = SysInfo::currentSystem();
|
||||||
QString system;
|
|
||||||
|
|
||||||
QString mappedJavaRealArchitecture() const
|
QString mappedJavaRealArchitecture() const
|
||||||
{
|
{
|
||||||
@ -45,8 +45,6 @@ struct RuntimeContext {
|
|||||||
{
|
{
|
||||||
javaArchitecture = instanceSettings->get("JavaArchitecture").toString();
|
javaArchitecture = instanceSettings->get("JavaArchitecture").toString();
|
||||||
javaRealArchitecture = instanceSettings->get("JavaRealArchitecture").toString();
|
javaRealArchitecture = instanceSettings->get("JavaRealArchitecture").toString();
|
||||||
javaPath = instanceSettings->get("JavaPath").toString();
|
|
||||||
system = currentSystem();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString getClassifier() const { return system + "-" + mappedJavaRealArchitecture(); }
|
QString getClassifier() const { return system + "-" + mappedJavaRealArchitecture(); }
|
||||||
@ -68,21 +66,4 @@ struct RuntimeContext {
|
|||||||
|
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString currentSystem()
|
|
||||||
{
|
|
||||||
#if defined(Q_OS_LINUX)
|
|
||||||
return "linux";
|
|
||||||
#elif defined(Q_OS_MACOS)
|
|
||||||
return "osx";
|
|
||||||
#elif defined(Q_OS_WINDOWS)
|
|
||||||
return "windows";
|
|
||||||
#elif defined(Q_OS_FREEBSD)
|
|
||||||
return "freebsd";
|
|
||||||
#elif defined(Q_OS_OPENBSD)
|
|
||||||
return "openbsd";
|
|
||||||
#else
|
|
||||||
return "unknown";
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
/* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "SkinUtils.h"
|
|
||||||
#include "Application.h"
|
|
||||||
#include "net/HttpMetaCache.h"
|
|
||||||
|
|
||||||
#include <QFile>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QPainter>
|
|
||||||
|
|
||||||
namespace SkinUtils {
|
|
||||||
/*
|
|
||||||
* Given a username, return a pixmap of the cached skin (if it exists), QPixmap() otherwise
|
|
||||||
*/
|
|
||||||
QPixmap getFaceFromCache(QString username, int height, int width)
|
|
||||||
{
|
|
||||||
QFile fskin(APPLICATION->metacache()->resolveEntry("skins", username + ".png")->getFullPath());
|
|
||||||
|
|
||||||
if (fskin.exists()) {
|
|
||||||
QPixmap skinTexture(fskin.fileName());
|
|
||||||
if (!skinTexture.isNull()) {
|
|
||||||
QPixmap skin = QPixmap(8, 8);
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
|
||||||
skin.fill(QColorConstants::Transparent);
|
|
||||||
#else
|
|
||||||
skin.fill(QColor(0, 0, 0, 0));
|
|
||||||
#endif
|
|
||||||
QPainter painter(&skin);
|
|
||||||
painter.drawPixmap(0, 0, skinTexture.copy(8, 8, 8, 8));
|
|
||||||
painter.drawPixmap(0, 0, skinTexture.copy(40, 8, 8, 8));
|
|
||||||
return skin.scaled(height, width, Qt::KeepAspectRatio);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return QPixmap();
|
|
||||||
}
|
|
||||||
} // namespace SkinUtils
|
|
@ -1,22 +0,0 @@
|
|||||||
/* 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
|
|
||||||
|
|
||||||
#include <QPixmap>
|
|
||||||
|
|
||||||
namespace SkinUtils {
|
|
||||||
QPixmap getFaceFromCache(QString id, int height = 64, int width = 64);
|
|
||||||
}
|
|
99
launcher/SysInfo.cpp
Normal file
99
launcher/SysInfo.cpp
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#include <QDebug>
|
||||||
|
#include <QString>
|
||||||
|
#include "sys.h"
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#endif
|
||||||
|
#include <QFile>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
bool rosettaDetect()
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
size_t size = sizeof(ret);
|
||||||
|
if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ret == 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace SysInfo {
|
||||||
|
QString currentSystem()
|
||||||
|
{
|
||||||
|
#if defined(Q_OS_LINUX)
|
||||||
|
return "linux";
|
||||||
|
#elif defined(Q_OS_MACOS)
|
||||||
|
return "osx";
|
||||||
|
#elif defined(Q_OS_WINDOWS)
|
||||||
|
return "windows";
|
||||||
|
#elif defined(Q_OS_FREEBSD)
|
||||||
|
return "freebsd";
|
||||||
|
#elif defined(Q_OS_OPENBSD)
|
||||||
|
return "openbsd";
|
||||||
|
#else
|
||||||
|
return "unknown";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
QString useQTForArch()
|
||||||
|
{
|
||||||
|
#if defined(Q_OS_MACOS) && !defined(Q_PROCESSOR_ARM)
|
||||||
|
if (rosettaDetect()) {
|
||||||
|
return "arm64";
|
||||||
|
} else {
|
||||||
|
return "x86_64";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return QSysInfo::currentCpuArchitecture();
|
||||||
|
}
|
||||||
|
|
||||||
|
int suitableMaxMem()
|
||||||
|
{
|
||||||
|
float totalRAM = (float)Sys::getSystemRam() / (float)Sys::mebibyte;
|
||||||
|
int maxMemoryAlloc;
|
||||||
|
|
||||||
|
// If totalRAM < 6GB, use (totalRAM / 1.5), else 4GB
|
||||||
|
if (totalRAM < (4096 * 1.5))
|
||||||
|
maxMemoryAlloc = (int)(totalRAM / 1.5);
|
||||||
|
else
|
||||||
|
maxMemoryAlloc = 4096;
|
||||||
|
|
||||||
|
return maxMemoryAlloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString getSupportedJavaArchitecture()
|
||||||
|
{
|
||||||
|
auto sys = currentSystem();
|
||||||
|
auto arch = useQTForArch();
|
||||||
|
if (sys == "windows") {
|
||||||
|
if (arch == "x86_64")
|
||||||
|
return "windows-x64";
|
||||||
|
if (arch == "i386")
|
||||||
|
return "windows-x86";
|
||||||
|
// Unknown, maybe arm, appending arch
|
||||||
|
return "windows-" + arch;
|
||||||
|
}
|
||||||
|
if (sys == "osx") {
|
||||||
|
if (arch == "arm64")
|
||||||
|
return "mac-os-arm64";
|
||||||
|
if (arch.contains("64"))
|
||||||
|
return "mac-os-64";
|
||||||
|
if (arch.contains("86"))
|
||||||
|
return "mac-os-86";
|
||||||
|
// Unknown, maybe something new, appending arch
|
||||||
|
return "mac-os-" + arch;
|
||||||
|
} else if (sys == "linux") {
|
||||||
|
if (arch == "x86_64")
|
||||||
|
return "linux-x64";
|
||||||
|
if (arch == "i386")
|
||||||
|
return "linux-x86";
|
||||||
|
// will work for arm32 arm(64)
|
||||||
|
return "linux-" + arch;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} // namespace SysInfo
|
8
launcher/SysInfo.h
Normal file
8
launcher/SysInfo.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace SysInfo {
|
||||||
|
QString currentSystem();
|
||||||
|
QString useQTForArch();
|
||||||
|
QString getSupportedJavaArchitecture();
|
||||||
|
int suitableMaxMem();
|
||||||
|
} // namespace SysInfo
|
260
launcher/Untar.cpp
Normal file
260
launcher/Untar.cpp
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#include "Untar.h"
|
||||||
|
#include <quagzipfile.h>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QIODevice>
|
||||||
|
#include <QString>
|
||||||
|
#include "FileSystem.h"
|
||||||
|
|
||||||
|
// adaptation of the:
|
||||||
|
// - https://github.com/madler/zlib/blob/develop/contrib/untgz/untgz.c
|
||||||
|
// - https://en.wikipedia.org/wiki/Tar_(computing)
|
||||||
|
// - https://github.com/euroelessar/cutereader/blob/master/karchive/src/ktar.cpp
|
||||||
|
|
||||||
|
#define BLOCKSIZE 512
|
||||||
|
#define SHORTNAMESIZE 100
|
||||||
|
|
||||||
|
enum class TypeFlag : char {
|
||||||
|
Regular = '0', // regular file
|
||||||
|
ARegular = 0, // regular file
|
||||||
|
Link = '1', // link
|
||||||
|
Symlink = '2', // reserved
|
||||||
|
Character = '3', // character special
|
||||||
|
Block = '4', // block special
|
||||||
|
Directory = '5', // directory
|
||||||
|
FIFO = '6', // FIFO special
|
||||||
|
Contiguous = '7', // reserved
|
||||||
|
// Posix stuff
|
||||||
|
GlobalPosixHeader = 'g',
|
||||||
|
ExtendedPosixHeader = 'x',
|
||||||
|
// 'A'– 'Z' Vendor specific extensions(POSIX .1 - 1988)
|
||||||
|
// GNU
|
||||||
|
GNULongLink = 'K', /* long link name */
|
||||||
|
GNULongName = 'L', /* long file name */
|
||||||
|
};
|
||||||
|
|
||||||
|
// struct Header { /* byte offset */
|
||||||
|
// char name[100]; /* 0 */
|
||||||
|
// char mode[8]; /* 100 */
|
||||||
|
// char uid[8]; /* 108 */
|
||||||
|
// char gid[8]; /* 116 */
|
||||||
|
// char size[12]; /* 124 */
|
||||||
|
// char mtime[12]; /* 136 */
|
||||||
|
// char chksum[8]; /* 148 */
|
||||||
|
// TypeFlag typeflag; /* 156 */
|
||||||
|
// char linkname[100]; /* 157 */
|
||||||
|
// char magic[6]; /* 257 */
|
||||||
|
// char version[2]; /* 263 */
|
||||||
|
// char uname[32]; /* 265 */
|
||||||
|
// char gname[32]; /* 297 */
|
||||||
|
// char devmajor[8]; /* 329 */
|
||||||
|
// char devminor[8]; /* 337 */
|
||||||
|
// char prefix[155]; /* 345 */
|
||||||
|
// /* 500 */
|
||||||
|
// };
|
||||||
|
|
||||||
|
bool readLonglink(QIODevice* in, qint64 size, QByteArray& longlink)
|
||||||
|
{
|
||||||
|
qint64 n = 0;
|
||||||
|
size--; // ignore trailing null
|
||||||
|
if (size < 0) {
|
||||||
|
qCritical() << "The filename size is negative";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
longlink.resize(size + (BLOCKSIZE - size % BLOCKSIZE)); // make the size divisible by BLOCKSIZE
|
||||||
|
for (qint64 offset = 0; offset < longlink.size(); offset += BLOCKSIZE) {
|
||||||
|
n = in->read(longlink.data() + offset, BLOCKSIZE);
|
||||||
|
if (n != BLOCKSIZE) {
|
||||||
|
qCritical() << "The expected blocksize was not respected for the name";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
longlink.truncate(qstrlen(longlink.constData()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getOctal(char* buffer, int maxlenght, bool* ok)
|
||||||
|
{
|
||||||
|
return QByteArray(buffer, qstrnlen(buffer, maxlenght)).toInt(ok, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString decodeName(char* name)
|
||||||
|
{
|
||||||
|
return QFile::decodeName(QByteArray(name, qstrnlen(name, 100)));
|
||||||
|
}
|
||||||
|
bool Tar::extract(QIODevice* in, QString dst)
|
||||||
|
{
|
||||||
|
char buffer[BLOCKSIZE];
|
||||||
|
QString name, symlink, firstFolderName;
|
||||||
|
bool doNotReset = false, ok;
|
||||||
|
while (true) {
|
||||||
|
auto n = in->read(buffer, BLOCKSIZE);
|
||||||
|
if (n != BLOCKSIZE) { // allways expect complete blocks
|
||||||
|
qCritical() << "The expected blocksize was not respected";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (buffer[0] == 0) { // end of archive
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int mode = getOctal(buffer + 100, 8, &ok) | QFile::ReadUser | QFile::WriteUser; // hack to ensure write and read permisions
|
||||||
|
if (!ok) {
|
||||||
|
qCritical() << "The file mode can't be read";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// there are names that are exactly 100 bytes long
|
||||||
|
// and neither longlink nor \0 terminated (bug:101472)
|
||||||
|
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
name = decodeName(buffer);
|
||||||
|
if (!firstFolderName.isEmpty() && name.startsWith(firstFolderName)) {
|
||||||
|
name = name.mid(firstFolderName.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (symlink.isEmpty())
|
||||||
|
symlink = decodeName(buffer);
|
||||||
|
qint64 size = getOctal(buffer + 124, 12, &ok);
|
||||||
|
if (!ok) {
|
||||||
|
qCritical() << "The file size can't be read";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (TypeFlag(buffer[156])) {
|
||||||
|
case TypeFlag::Regular:
|
||||||
|
/* fallthrough */
|
||||||
|
case TypeFlag::ARegular: {
|
||||||
|
auto fileName = FS::PathCombine(dst, name);
|
||||||
|
if (!FS::ensureFilePathExists(fileName)) {
|
||||||
|
qCritical() << "Can't ensure the file path to exist: " << fileName;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QFile out(fileName);
|
||||||
|
if (!out.open(QFile::WriteOnly)) {
|
||||||
|
qCritical() << "Can't open file:" << fileName;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
out.setPermissions(QFile::Permissions(mode));
|
||||||
|
while (size > 0) {
|
||||||
|
QByteArray tmp(BLOCKSIZE, 0);
|
||||||
|
n = in->read(tmp.data(), BLOCKSIZE);
|
||||||
|
if (n != BLOCKSIZE) {
|
||||||
|
qCritical() << "The expected blocksize was not respected when reading file";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tmp.truncate(qMin(qint64(BLOCKSIZE), size));
|
||||||
|
out.write(tmp);
|
||||||
|
size -= BLOCKSIZE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeFlag::Directory: {
|
||||||
|
if (firstFolderName.isEmpty()) {
|
||||||
|
firstFolderName = name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto folderPath = FS::PathCombine(dst, name);
|
||||||
|
if (!FS::ensureFolderPathExists(folderPath)) {
|
||||||
|
qCritical() << "Can't ensure that folder exists: " << folderPath;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeFlag::GNULongLink: {
|
||||||
|
doNotReset = true;
|
||||||
|
QByteArray longlink;
|
||||||
|
if (readLonglink(in, size, longlink)) {
|
||||||
|
symlink = QFile::decodeName(longlink.constData());
|
||||||
|
} else {
|
||||||
|
qCritical() << "Failed to read long link";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeFlag::GNULongName: {
|
||||||
|
doNotReset = true;
|
||||||
|
QByteArray longlink;
|
||||||
|
if (readLonglink(in, size, longlink)) {
|
||||||
|
name = QFile::decodeName(longlink.constData());
|
||||||
|
} else {
|
||||||
|
qCritical() << "Failed to read long name";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeFlag::Link:
|
||||||
|
/* fallthrough */
|
||||||
|
case TypeFlag::Symlink: {
|
||||||
|
auto fileName = FS::PathCombine(dst, name);
|
||||||
|
if (!FS::create_link(FS::PathCombine(QFileInfo(fileName).path(), symlink), fileName)()) { // do not use symlinks
|
||||||
|
qCritical() << "Can't create link for:" << fileName << " to:" << FS::PathCombine(QFileInfo(fileName).path(), symlink);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
FS::ensureFilePathExists(fileName);
|
||||||
|
QFile::setPermissions(fileName, QFile::Permissions(mode));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeFlag::Character:
|
||||||
|
/* fallthrough */
|
||||||
|
case TypeFlag::Block:
|
||||||
|
/* fallthrough */
|
||||||
|
case TypeFlag::FIFO:
|
||||||
|
/* fallthrough */
|
||||||
|
case TypeFlag::Contiguous:
|
||||||
|
/* fallthrough */
|
||||||
|
case TypeFlag::GlobalPosixHeader:
|
||||||
|
/* fallthrough */
|
||||||
|
case TypeFlag::ExtendedPosixHeader:
|
||||||
|
/* fallthrough */
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!doNotReset) {
|
||||||
|
name.truncate(0);
|
||||||
|
symlink.truncate(0);
|
||||||
|
}
|
||||||
|
doNotReset = false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GZTar::extract(QString src, QString dst)
|
||||||
|
{
|
||||||
|
QuaGzipFile a(src);
|
||||||
|
if (!a.open(QIODevice::ReadOnly)) {
|
||||||
|
qCritical() << "Can't open tar file:" << src;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Tar::extract(&a, dst);
|
||||||
|
}
|
46
launcher/Untar.h
Normal file
46
launcher/Untar.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
#include <QIODevice>
|
||||||
|
|
||||||
|
// this is a hack used for the java downloader (feel free to remove it in favor of a library)
|
||||||
|
// both extract functions will extract the first folder inside dest(disregarding the prefix)
|
||||||
|
namespace Tar {
|
||||||
|
bool extract(QIODevice* in, QString dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace GZTar {
|
||||||
|
bool extract(QString src, QString dst);
|
||||||
|
}
|
@ -123,8 +123,7 @@ QDebug operator<<(QDebug debug, const Version& v)
|
|||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug.nospace() << " ]"
|
debug.nospace() << " ]" << " }";
|
||||||
<< " }";
|
|
||||||
|
|
||||||
return debug;
|
return debug;
|
||||||
}
|
}
|
||||||
|
@ -114,10 +114,14 @@ QVariant VersionProxyModel::headerData(int section, Qt::Orientation orientation,
|
|||||||
return tr("Branch");
|
return tr("Branch");
|
||||||
case Type:
|
case Type:
|
||||||
return tr("Type");
|
return tr("Type");
|
||||||
case Architecture:
|
case CPUArchitecture:
|
||||||
return tr("Architecture");
|
return tr("Architecture");
|
||||||
case Path:
|
case Path:
|
||||||
return tr("Path");
|
return tr("Path");
|
||||||
|
case JavaName:
|
||||||
|
return tr("Java Name");
|
||||||
|
case JavaMajor:
|
||||||
|
return tr("Major Version");
|
||||||
case Time:
|
case Time:
|
||||||
return tr("Released");
|
return tr("Released");
|
||||||
}
|
}
|
||||||
@ -131,10 +135,14 @@ QVariant VersionProxyModel::headerData(int section, Qt::Orientation orientation,
|
|||||||
return tr("The version's branch");
|
return tr("The version's branch");
|
||||||
case Type:
|
case Type:
|
||||||
return tr("The version's type");
|
return tr("The version's type");
|
||||||
case Architecture:
|
case CPUArchitecture:
|
||||||
return tr("CPU Architecture");
|
return tr("CPU Architecture");
|
||||||
case Path:
|
case Path:
|
||||||
return tr("Filesystem path to this version");
|
return tr("Filesystem path to this version");
|
||||||
|
case JavaName:
|
||||||
|
return tr("The alternative name of the Java version");
|
||||||
|
case JavaMajor:
|
||||||
|
return tr("The Java major version");
|
||||||
case Time:
|
case Time:
|
||||||
return tr("Release date of this version");
|
return tr("Release date of this version");
|
||||||
}
|
}
|
||||||
@ -165,10 +173,14 @@ QVariant VersionProxyModel::data(const QModelIndex& index, int role) const
|
|||||||
return sourceModel()->data(parentIndex, BaseVersionList::BranchRole);
|
return sourceModel()->data(parentIndex, BaseVersionList::BranchRole);
|
||||||
case Type:
|
case Type:
|
||||||
return sourceModel()->data(parentIndex, BaseVersionList::TypeRole);
|
return sourceModel()->data(parentIndex, BaseVersionList::TypeRole);
|
||||||
case Architecture:
|
case CPUArchitecture:
|
||||||
return sourceModel()->data(parentIndex, BaseVersionList::ArchitectureRole);
|
return sourceModel()->data(parentIndex, BaseVersionList::CPUArchitectureRole);
|
||||||
case Path:
|
case Path:
|
||||||
return sourceModel()->data(parentIndex, BaseVersionList::PathRole);
|
return sourceModel()->data(parentIndex, BaseVersionList::PathRole);
|
||||||
|
case JavaName:
|
||||||
|
return sourceModel()->data(parentIndex, BaseVersionList::JavaNameRole);
|
||||||
|
case JavaMajor:
|
||||||
|
return sourceModel()->data(parentIndex, BaseVersionList::JavaMajorRole);
|
||||||
case Time:
|
case Time:
|
||||||
return sourceModel()->data(parentIndex, Meta::VersionList::TimeRole).toDate();
|
return sourceModel()->data(parentIndex, Meta::VersionList::TimeRole).toDate();
|
||||||
default:
|
default:
|
||||||
@ -308,12 +320,18 @@ void VersionProxyModel::setSourceModel(QAbstractItemModel* replacingRaw)
|
|||||||
m_columns.push_back(ParentVersion);
|
m_columns.push_back(ParentVersion);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (roles.contains(BaseVersionList::ArchitectureRole)) {
|
if (roles.contains(BaseVersionList::CPUArchitectureRole)) {
|
||||||
m_columns.push_back(Architecture);
|
m_columns.push_back(CPUArchitecture);
|
||||||
}
|
}
|
||||||
if (roles.contains(BaseVersionList::PathRole)) {
|
if (roles.contains(BaseVersionList::PathRole)) {
|
||||||
m_columns.push_back(Path);
|
m_columns.push_back(Path);
|
||||||
}
|
}
|
||||||
|
if (roles.contains(BaseVersionList::JavaNameRole)) {
|
||||||
|
m_columns.push_back(JavaName);
|
||||||
|
}
|
||||||
|
if (roles.contains(BaseVersionList::JavaMajorRole)) {
|
||||||
|
m_columns.push_back(JavaMajor);
|
||||||
|
}
|
||||||
if (roles.contains(Meta::VersionList::TimeRole)) {
|
if (roles.contains(Meta::VersionList::TimeRole)) {
|
||||||
m_columns.push_back(Time);
|
m_columns.push_back(Time);
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ class VersionFilterModel;
|
|||||||
class VersionProxyModel : public QAbstractProxyModel {
|
class VersionProxyModel : public QAbstractProxyModel {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
enum Column { Name, ParentVersion, Branch, Type, Architecture, Path, Time };
|
enum Column { Name, ParentVersion, Branch, Type, CPUArchitecture, Path, Time, JavaName, JavaMajor };
|
||||||
using FilterMap = QHash<BaseVersionList::ModelRoles, std::shared_ptr<Filter>>;
|
using FilterMap = QHash<BaseVersionList::ModelRoles, std::shared_ptr<Filter>>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -322,7 +322,7 @@ const MMCIcon* IconList::icon(const QString& key) const
|
|||||||
|
|
||||||
bool IconList::deleteIcon(const QString& key)
|
bool IconList::deleteIcon(const QString& key)
|
||||||
{
|
{
|
||||||
return iconFileExists(key) && QFile::remove(icon(key)->getFilePath());
|
return iconFileExists(key) && FS::deletePath(icon(key)->getFilePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IconList::trashIcon(const QString& key)
|
bool IconList::trashIcon(const QString& key)
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
static const QStringList validIconExtensions = { { "svg", "png", "ico", "gif", "jpg", "jpeg" } };
|
static const QStringList validIconExtensions = { { "svg", "png", "ico", "gif", "jpg", "jpeg", "webp" } };
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace IconUtils {
|
namespace IconUtils {
|
||||||
@ -52,8 +52,7 @@ QString findBestIconIn(const QString& folder, const QString& iconKey)
|
|||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
it.next();
|
it.next();
|
||||||
auto fileInfo = it.fileInfo();
|
auto fileInfo = it.fileInfo();
|
||||||
|
if ((fileInfo.completeBaseName() == iconKey || fileInfo.fileName() == iconKey) && isIconSuffix(fileInfo.suffix()))
|
||||||
if (fileInfo.completeBaseName() == iconKey && isIconSuffix(fileInfo.suffix()))
|
|
||||||
return fileInfo.absoluteFilePath();
|
return fileInfo.absoluteFilePath();
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
set(CMAKE_MODULE_PATH "@CMAKE_MODULE_PATH@")
|
set(CMAKE_MODULE_PATH "@CMAKE_MODULE_PATH@")
|
||||||
|
|
||||||
file(GLOB_RECURSE QTPLUGINS "${CMAKE_INSTALL_PREFIX}/@PLUGIN_DEST_DIR@/*@CMAKE_SHARED_LIBRARY_SUFFIX@")
|
file(GLOB_RECURSE QTPLUGINS "${CMAKE_INSTALL_PREFIX}/@PLUGIN_DEST_DIR@/*@CMAKE_SHARED_LIBRARY_SUFFIX@")
|
||||||
function(gp_resolved_file_type_override resolved_file type_var)
|
function(gp_resolved_file_type_override resolved_file type_var)
|
||||||
if(resolved_file MATCHES "^/(usr/)?lib/libQt")
|
if(resolved_file MATCHES "^/(usr/)?lib/libQt")
|
||||||
|
@ -40,14 +40,15 @@
|
|||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
|
||||||
#include "Application.h"
|
|
||||||
#include "Commandline.h"
|
#include "Commandline.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "JavaUtils.h"
|
#include "java/JavaUtils.h"
|
||||||
|
|
||||||
JavaChecker::JavaChecker(QObject* parent) : QObject(parent) {}
|
JavaChecker::JavaChecker(QString path, QString args, int minMem, int maxMem, int permGen, int id, QObject* parent)
|
||||||
|
: Task(parent), m_path(path), m_args(args), m_minMem(minMem), m_maxMem(maxMem), m_permGen(permGen), m_id(id)
|
||||||
|
{}
|
||||||
|
|
||||||
void JavaChecker::performCheck()
|
void JavaChecker::executeTask()
|
||||||
{
|
{
|
||||||
QString checkerJar = JavaUtils::getJavaCheckPath();
|
QString checkerJar = JavaUtils::getJavaCheckPath();
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ void JavaChecker::performCheck()
|
|||||||
if (m_maxMem != 0) {
|
if (m_maxMem != 0) {
|
||||||
args << QString("-Xmx%1m").arg(m_maxMem);
|
args << QString("-Xmx%1m").arg(m_maxMem);
|
||||||
}
|
}
|
||||||
if (m_permGen != 64) {
|
if (m_permGen != 64 && m_permGen != 0) {
|
||||||
args << QString("-XX:PermSize=%1m").arg(m_permGen);
|
args << QString("-XX:PermSize=%1m").arg(m_permGen);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,11 +116,10 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
QProcessPtr _process = process;
|
QProcessPtr _process = process;
|
||||||
process.reset();
|
process.reset();
|
||||||
|
|
||||||
JavaCheckResult result;
|
Result result = {
|
||||||
{
|
m_path,
|
||||||
result.path = m_path;
|
m_id,
|
||||||
result.id = m_id;
|
};
|
||||||
}
|
|
||||||
result.errorLog = m_stderr;
|
result.errorLog = m_stderr;
|
||||||
result.outLog = m_stdout;
|
result.outLog = m_stdout;
|
||||||
qDebug() << "STDOUT" << m_stdout;
|
qDebug() << "STDOUT" << m_stdout;
|
||||||
@ -127,8 +127,9 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
qDebug() << "Java checker finished with status" << status << "exit code" << exitcode;
|
qDebug() << "Java checker finished with status" << status << "exit code" << exitcode;
|
||||||
|
|
||||||
if (status == QProcess::CrashExit || exitcode == 1) {
|
if (status == QProcess::CrashExit || exitcode == 1) {
|
||||||
result.validity = JavaCheckResult::Validity::Errored;
|
result.validity = Result::Validity::Errored;
|
||||||
emit checkFinished(result);
|
emit checkFinished(result);
|
||||||
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,8 +162,9 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!results.contains("os.arch") || !results.contains("java.version") || !results.contains("java.vendor") || !success) {
|
if (!results.contains("os.arch") || !results.contains("java.version") || !results.contains("java.vendor") || !success) {
|
||||||
result.validity = JavaCheckResult::Validity::ReturnedInvalidData;
|
result.validity = Result::Validity::ReturnedInvalidData;
|
||||||
emit checkFinished(result);
|
emit checkFinished(result);
|
||||||
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +173,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
auto java_vendor = results["java.vendor"];
|
auto java_vendor = results["java.vendor"];
|
||||||
bool is_64 = os_arch == "x86_64" || os_arch == "amd64" || os_arch == "aarch64" || os_arch == "arm64";
|
bool is_64 = os_arch == "x86_64" || os_arch == "amd64" || os_arch == "aarch64" || os_arch == "arm64";
|
||||||
|
|
||||||
result.validity = JavaCheckResult::Validity::Valid;
|
result.validity = Result::Validity::Valid;
|
||||||
result.is_64bit = is_64;
|
result.is_64bit = is_64;
|
||||||
result.mojangPlatform = is_64 ? "64" : "32";
|
result.mojangPlatform = is_64 ? "64" : "32";
|
||||||
result.realPlatform = os_arch;
|
result.realPlatform = os_arch;
|
||||||
@ -179,6 +181,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
result.javaVendor = java_vendor;
|
result.javaVendor = java_vendor;
|
||||||
qDebug() << "Java checker succeeded.";
|
qDebug() << "Java checker succeeded.";
|
||||||
emit checkFinished(result);
|
emit checkFinished(result);
|
||||||
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaChecker::error(QProcess::ProcessError err)
|
void JavaChecker::error(QProcess::ProcessError err)
|
||||||
@ -190,15 +193,9 @@ void JavaChecker::error(QProcess::ProcessError err)
|
|||||||
qDebug() << "Native environment:";
|
qDebug() << "Native environment:";
|
||||||
qDebug() << QProcessEnvironment::systemEnvironment().toStringList();
|
qDebug() << QProcessEnvironment::systemEnvironment().toStringList();
|
||||||
killTimer.stop();
|
killTimer.stop();
|
||||||
JavaCheckResult result;
|
emit checkFinished({ m_path, m_id });
|
||||||
{
|
|
||||||
result.path = m_path;
|
|
||||||
result.id = m_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit checkFinished(result);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaChecker::timeout()
|
void JavaChecker::timeout()
|
||||||
|
@ -3,49 +3,51 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "QObjectPtr.h"
|
|
||||||
|
|
||||||
#include "JavaVersion.h"
|
#include "JavaVersion.h"
|
||||||
|
#include "QObjectPtr.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
class JavaChecker;
|
class JavaChecker : public Task {
|
||||||
|
|
||||||
struct JavaCheckResult {
|
|
||||||
QString path;
|
|
||||||
QString mojangPlatform;
|
|
||||||
QString realPlatform;
|
|
||||||
JavaVersion javaVersion;
|
|
||||||
QString javaVendor;
|
|
||||||
QString outLog;
|
|
||||||
QString errorLog;
|
|
||||||
bool is_64bit = false;
|
|
||||||
int id;
|
|
||||||
enum class Validity { Errored, ReturnedInvalidData, Valid } validity = Validity::Errored;
|
|
||||||
};
|
|
||||||
|
|
||||||
using QProcessPtr = shared_qobject_ptr<QProcess>;
|
|
||||||
using JavaCheckerPtr = shared_qobject_ptr<JavaChecker>;
|
|
||||||
class JavaChecker : public QObject {
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit JavaChecker(QObject* parent = 0);
|
using QProcessPtr = shared_qobject_ptr<QProcess>;
|
||||||
void performCheck();
|
using Ptr = shared_qobject_ptr<JavaChecker>;
|
||||||
|
|
||||||
QString m_path;
|
struct Result {
|
||||||
QString m_args;
|
QString path;
|
||||||
int m_id = 0;
|
int id;
|
||||||
int m_minMem = 0;
|
QString mojangPlatform;
|
||||||
int m_maxMem = 0;
|
QString realPlatform;
|
||||||
int m_permGen = 64;
|
JavaVersion javaVersion;
|
||||||
|
QString javaVendor;
|
||||||
|
QString outLog;
|
||||||
|
QString errorLog;
|
||||||
|
bool is_64bit = false;
|
||||||
|
enum class Validity { Errored, ReturnedInvalidData, Valid } validity = Validity::Errored;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit JavaChecker(QString path, QString args, int minMem = 0, int maxMem = 0, int permGen = 0, int id = 0, QObject* parent = 0);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void checkFinished(JavaCheckResult result);
|
void checkFinished(const Result& result);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void executeTask() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QProcessPtr process;
|
QProcessPtr process;
|
||||||
QTimer killTimer;
|
QTimer killTimer;
|
||||||
QString m_stdout;
|
QString m_stdout;
|
||||||
QString m_stderr;
|
QString m_stderr;
|
||||||
public slots:
|
|
||||||
|
QString m_path;
|
||||||
|
QString m_args;
|
||||||
|
int m_minMem = 0;
|
||||||
|
int m_maxMem = 0;
|
||||||
|
int m_permGen = 64;
|
||||||
|
int m_id = 0;
|
||||||
|
|
||||||
|
private slots:
|
||||||
void timeout();
|
void timeout();
|
||||||
void finished(int exitcode, QProcess::ExitStatus);
|
void finished(int exitcode, QProcess::ExitStatus);
|
||||||
void error(QProcess::ProcessError);
|
void error(QProcess::ProcessError);
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
/* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "JavaCheckerJob.h"
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
void JavaCheckerJob::partFinished(JavaCheckResult result)
|
|
||||||
{
|
|
||||||
num_finished++;
|
|
||||||
qDebug() << m_job_name.toLocal8Bit() << "progress:" << num_finished << "/" << javacheckers.size();
|
|
||||||
setProgress(num_finished, javacheckers.size());
|
|
||||||
|
|
||||||
javaresults.replace(result.id, result);
|
|
||||||
|
|
||||||
if (num_finished == javacheckers.size()) {
|
|
||||||
emitSucceeded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JavaCheckerJob::executeTask()
|
|
||||||
{
|
|
||||||
qDebug() << m_job_name.toLocal8Bit() << " started.";
|
|
||||||
for (auto iter : javacheckers) {
|
|
||||||
javaresults.append(JavaCheckResult());
|
|
||||||
connect(iter.get(), &JavaChecker::checkFinished, this, &JavaCheckerJob::partFinished);
|
|
||||||
iter->performCheck();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* Prism Launcher - Minecraft Launcher
|
||||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
*
|
*
|
||||||
* 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
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* Prism Launcher - Minecraft Launcher
|
||||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -40,6 +40,7 @@ struct JavaInstall : public BaseVersion {
|
|||||||
QString arch;
|
QString arch;
|
||||||
QString path;
|
QString path;
|
||||||
bool recommended = false;
|
bool recommended = false;
|
||||||
|
bool is_64bit = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
using JavaInstallPtr = std::shared_ptr<JavaInstall>;
|
using JavaInstallPtr = std::shared_ptr<JavaInstall>;
|
||||||
|
@ -38,13 +38,17 @@
|
|||||||
#include <QtXml>
|
#include <QtXml>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "java/JavaCheckerJob.h"
|
#include "Application.h"
|
||||||
|
#include "java/JavaChecker.h"
|
||||||
#include "java/JavaInstallList.h"
|
#include "java/JavaInstallList.h"
|
||||||
#include "java/JavaUtils.h"
|
#include "java/JavaUtils.h"
|
||||||
#include "minecraft/VersionFilterData.h"
|
#include "tasks/ConcurrentTask.h"
|
||||||
|
|
||||||
JavaInstallList::JavaInstallList(QObject* parent) : BaseVersionList(parent) {}
|
JavaInstallList::JavaInstallList(QObject* parent, bool onlyManagedVersions)
|
||||||
|
: BaseVersionList(parent), m_only_managed_versions(onlyManagedVersions)
|
||||||
|
{}
|
||||||
|
|
||||||
Task::Ptr JavaInstallList::getLoadTask()
|
Task::Ptr JavaInstallList::getLoadTask()
|
||||||
{
|
{
|
||||||
@ -55,7 +59,7 @@ Task::Ptr JavaInstallList::getLoadTask()
|
|||||||
Task::Ptr JavaInstallList::getCurrentTask()
|
Task::Ptr JavaInstallList::getCurrentTask()
|
||||||
{
|
{
|
||||||
if (m_status == Status::InProgress) {
|
if (m_status == Status::InProgress) {
|
||||||
return m_loadTask;
|
return m_load_task;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -64,8 +68,8 @@ void JavaInstallList::load()
|
|||||||
{
|
{
|
||||||
if (m_status != Status::InProgress) {
|
if (m_status != Status::InProgress) {
|
||||||
m_status = Status::InProgress;
|
m_status = Status::InProgress;
|
||||||
m_loadTask.reset(new JavaListLoadTask(this));
|
m_load_task.reset(new JavaListLoadTask(this, m_only_managed_versions));
|
||||||
m_loadTask->start();
|
m_load_task->start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +110,7 @@ QVariant JavaInstallList::data(const QModelIndex& index, int role) const
|
|||||||
return version->recommended;
|
return version->recommended;
|
||||||
case PathRole:
|
case PathRole:
|
||||||
return version->path;
|
return version->path;
|
||||||
case ArchitectureRole:
|
case CPUArchitectureRole:
|
||||||
return version->arch;
|
return version->arch;
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
@ -115,7 +119,7 @@ QVariant JavaInstallList::data(const QModelIndex& index, int role) const
|
|||||||
|
|
||||||
BaseVersionList::RoleList JavaInstallList::providesRoles() const
|
BaseVersionList::RoleList JavaInstallList::providesRoles() const
|
||||||
{
|
{
|
||||||
return { VersionPointerRole, VersionIdRole, VersionRole, RecommendedRole, PathRole, ArchitectureRole };
|
return { VersionPointerRole, VersionIdRole, VersionRole, RecommendedRole, PathRole, CPUArchitectureRole };
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaInstallList::updateListData(QList<BaseVersion::Ptr> versions)
|
void JavaInstallList::updateListData(QList<BaseVersion::Ptr> versions)
|
||||||
@ -129,7 +133,7 @@ void JavaInstallList::updateListData(QList<BaseVersion::Ptr> versions)
|
|||||||
}
|
}
|
||||||
endResetModel();
|
endResetModel();
|
||||||
m_status = Status::Done;
|
m_status = Status::Done;
|
||||||
m_loadTask.reset();
|
m_load_task.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sortJavas(BaseVersion::Ptr left, BaseVersion::Ptr right)
|
bool sortJavas(BaseVersion::Ptr left, BaseVersion::Ptr right)
|
||||||
@ -146,35 +150,30 @@ void JavaInstallList::sortVersions()
|
|||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
JavaListLoadTask::JavaListLoadTask(JavaInstallList* vlist) : Task()
|
JavaListLoadTask::JavaListLoadTask(JavaInstallList* vlist, bool onlyManagedVersions) : Task(), m_only_managed_versions(onlyManagedVersions)
|
||||||
{
|
{
|
||||||
m_list = vlist;
|
m_list = vlist;
|
||||||
m_currentRecommended = NULL;
|
m_current_recommended = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
JavaListLoadTask::~JavaListLoadTask() {}
|
|
||||||
|
|
||||||
void JavaListLoadTask::executeTask()
|
void JavaListLoadTask::executeTask()
|
||||||
{
|
{
|
||||||
setStatus(tr("Detecting Java installations..."));
|
setStatus(tr("Detecting Java installations..."));
|
||||||
|
|
||||||
JavaUtils ju;
|
JavaUtils ju;
|
||||||
QList<QString> candidate_paths = ju.FindJavaPaths();
|
QList<QString> candidate_paths = m_only_managed_versions ? getPrismJavaBundle() : ju.FindJavaPaths();
|
||||||
|
|
||||||
m_job.reset(new JavaCheckerJob("Java detection"));
|
ConcurrentTask::Ptr job(new ConcurrentTask(this, "Java detection", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt()));
|
||||||
|
m_job.reset(job);
|
||||||
connect(m_job.get(), &Task::finished, this, &JavaListLoadTask::javaCheckerFinished);
|
connect(m_job.get(), &Task::finished, this, &JavaListLoadTask::javaCheckerFinished);
|
||||||
connect(m_job.get(), &Task::progress, this, &Task::setProgress);
|
connect(m_job.get(), &Task::progress, this, &Task::setProgress);
|
||||||
|
|
||||||
qDebug() << "Probing the following Java paths: ";
|
qDebug() << "Probing the following Java paths: ";
|
||||||
int id = 0;
|
int id = 0;
|
||||||
for (QString candidate : candidate_paths) {
|
for (QString candidate : candidate_paths) {
|
||||||
qDebug() << " " << candidate;
|
auto checker = new JavaChecker(candidate, "", 0, 0, 0, id, this);
|
||||||
|
connect(checker, &JavaChecker::checkFinished, [this](const JavaChecker::Result& result) { m_results << result; });
|
||||||
auto candidate_checker = new JavaChecker();
|
job->addTask(Task::Ptr(checker));
|
||||||
candidate_checker->m_path = candidate;
|
|
||||||
candidate_checker->m_id = id;
|
|
||||||
m_job->addJavaCheckerAction(JavaCheckerPtr(candidate_checker));
|
|
||||||
|
|
||||||
id++;
|
id++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,16 +183,17 @@ void JavaListLoadTask::executeTask()
|
|||||||
void JavaListLoadTask::javaCheckerFinished()
|
void JavaListLoadTask::javaCheckerFinished()
|
||||||
{
|
{
|
||||||
QList<JavaInstallPtr> candidates;
|
QList<JavaInstallPtr> candidates;
|
||||||
auto results = m_job->getResults();
|
std::sort(m_results.begin(), m_results.end(), [](const JavaChecker::Result& a, const JavaChecker::Result& b) { return a.id < b.id; });
|
||||||
|
|
||||||
qDebug() << "Found the following valid Java installations:";
|
qDebug() << "Found the following valid Java installations:";
|
||||||
for (JavaCheckResult result : results) {
|
for (auto result : m_results) {
|
||||||
if (result.validity == JavaCheckResult::Validity::Valid) {
|
if (result.validity == JavaChecker::Result::Validity::Valid) {
|
||||||
JavaInstallPtr javaVersion(new JavaInstall());
|
JavaInstallPtr javaVersion(new JavaInstall());
|
||||||
|
|
||||||
javaVersion->id = result.javaVersion;
|
javaVersion->id = result.javaVersion;
|
||||||
javaVersion->arch = result.realPlatform;
|
javaVersion->arch = result.realPlatform;
|
||||||
javaVersion->path = result.path;
|
javaVersion->path = result.path;
|
||||||
|
javaVersion->is_64bit = result.is_64bit;
|
||||||
candidates.append(javaVersion);
|
candidates.append(javaVersion);
|
||||||
|
|
||||||
qDebug() << " " << javaVersion->id.toString() << javaVersion->arch << javaVersion->path;
|
qDebug() << " " << javaVersion->id.toString() << javaVersion->arch << javaVersion->path;
|
||||||
|
@ -19,9 +19,9 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include "BaseVersionList.h"
|
#include "BaseVersionList.h"
|
||||||
|
#include "java/JavaChecker.h"
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
#include "JavaCheckerJob.h"
|
|
||||||
#include "JavaInstall.h"
|
#include "JavaInstall.h"
|
||||||
|
|
||||||
#include "QObjectPtr.h"
|
#include "QObjectPtr.h"
|
||||||
@ -33,9 +33,9 @@ class JavaInstallList : public BaseVersionList {
|
|||||||
enum class Status { NotDone, InProgress, Done };
|
enum class Status { NotDone, InProgress, Done };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit JavaInstallList(QObject* parent = 0);
|
explicit JavaInstallList(QObject* parent = 0, bool onlyManagedVersions = false);
|
||||||
|
|
||||||
Task::Ptr getLoadTask() override;
|
[[nodiscard]] Task::Ptr getLoadTask() override;
|
||||||
bool isLoaded() override;
|
bool isLoaded() override;
|
||||||
const BaseVersion::Ptr at(int i) const override;
|
const BaseVersion::Ptr at(int i) const override;
|
||||||
int count() const override;
|
int count() const override;
|
||||||
@ -53,23 +53,27 @@ class JavaInstallList : public BaseVersionList {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
Status m_status = Status::NotDone;
|
Status m_status = Status::NotDone;
|
||||||
shared_qobject_ptr<JavaListLoadTask> m_loadTask;
|
shared_qobject_ptr<JavaListLoadTask> m_load_task;
|
||||||
QList<BaseVersion::Ptr> m_vlist;
|
QList<BaseVersion::Ptr> m_vlist;
|
||||||
|
bool m_only_managed_versions;
|
||||||
};
|
};
|
||||||
|
|
||||||
class JavaListLoadTask : public Task {
|
class JavaListLoadTask : public Task {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit JavaListLoadTask(JavaInstallList* vlist);
|
explicit JavaListLoadTask(JavaInstallList* vlist, bool onlyManagedVersions = false);
|
||||||
virtual ~JavaListLoadTask();
|
virtual ~JavaListLoadTask() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
void executeTask() override;
|
void executeTask() override;
|
||||||
public slots:
|
public slots:
|
||||||
void javaCheckerFinished();
|
void javaCheckerFinished();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
shared_qobject_ptr<JavaCheckerJob> m_job;
|
Task::Ptr m_job;
|
||||||
JavaInstallList* m_list;
|
JavaInstallList* m_list;
|
||||||
JavaInstall* m_currentRecommended;
|
JavaInstall* m_current_recommended;
|
||||||
|
QList<JavaChecker::Result> m_results;
|
||||||
|
bool m_only_managed_versions;
|
||||||
};
|
};
|
||||||
|
128
launcher/java/JavaMetadata.cpp
Normal file
128
launcher/java/JavaMetadata.cpp
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "java/JavaMetadata.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Json.h"
|
||||||
|
#include "StringUtils.h"
|
||||||
|
#include "java/JavaVersion.h"
|
||||||
|
#include "minecraft/ParseUtils.h"
|
||||||
|
|
||||||
|
namespace Java {
|
||||||
|
|
||||||
|
DownloadType parseDownloadType(QString javaDownload)
|
||||||
|
{
|
||||||
|
if (javaDownload == "manifest")
|
||||||
|
return DownloadType::Manifest;
|
||||||
|
else if (javaDownload == "archive")
|
||||||
|
return DownloadType::Archive;
|
||||||
|
else
|
||||||
|
return DownloadType::Unknown;
|
||||||
|
}
|
||||||
|
QString downloadTypeToString(DownloadType javaDownload)
|
||||||
|
{
|
||||||
|
switch (javaDownload) {
|
||||||
|
case DownloadType::Manifest:
|
||||||
|
return "manifest";
|
||||||
|
case DownloadType::Archive:
|
||||||
|
return "archive";
|
||||||
|
case DownloadType::Unknown:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
MetadataPtr parseJavaMeta(const QJsonObject& in)
|
||||||
|
{
|
||||||
|
auto meta = std::make_shared<Metadata>();
|
||||||
|
|
||||||
|
meta->m_name = Json::ensureString(in, "name", "");
|
||||||
|
meta->vendor = Json::ensureString(in, "vendor", "");
|
||||||
|
meta->url = Json::ensureString(in, "url", "");
|
||||||
|
meta->releaseTime = timeFromS3Time(Json::ensureString(in, "releaseTime", ""));
|
||||||
|
meta->downloadType = parseDownloadType(Json::ensureString(in, "downloadType", ""));
|
||||||
|
meta->packageType = Json::ensureString(in, "packageType", "");
|
||||||
|
meta->runtimeOS = Json::ensureString(in, "runtimeOS", "unknown");
|
||||||
|
|
||||||
|
if (in.contains("checksum")) {
|
||||||
|
auto obj = Json::requireObject(in, "checksum");
|
||||||
|
meta->checksumHash = Json::ensureString(obj, "hash", "");
|
||||||
|
meta->checksumType = Json::ensureString(obj, "type", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in.contains("version")) {
|
||||||
|
auto obj = Json::requireObject(in, "version");
|
||||||
|
auto name = Json::ensureString(obj, "name", "");
|
||||||
|
auto major = Json::ensureInteger(obj, "major", 0);
|
||||||
|
auto minor = Json::ensureInteger(obj, "minor", 0);
|
||||||
|
auto security = Json::ensureInteger(obj, "security", 0);
|
||||||
|
auto build = Json::ensureInteger(obj, "build", 0);
|
||||||
|
meta->version = JavaVersion(major, minor, security, build, name);
|
||||||
|
}
|
||||||
|
return meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Metadata::operator<(const Metadata& rhs)
|
||||||
|
{
|
||||||
|
auto id = version;
|
||||||
|
if (id < rhs.version) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (id > rhs.version) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto date = releaseTime;
|
||||||
|
if (date < rhs.releaseTime) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (date > rhs.releaseTime) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return StringUtils::naturalCompare(m_name, rhs.m_name, Qt::CaseInsensitive) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Metadata::operator==(const Metadata& rhs)
|
||||||
|
{
|
||||||
|
return version == rhs.version && m_name == rhs.m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Metadata::operator>(const Metadata& rhs)
|
||||||
|
{
|
||||||
|
return (!operator<(rhs)) && (!operator==(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Metadata::operator<(BaseVersion& a)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return operator<(dynamic_cast<Metadata&>(a));
|
||||||
|
} catch (const std::bad_cast& e) {
|
||||||
|
return BaseVersion::operator<(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Metadata::operator>(BaseVersion& a)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return operator>(dynamic_cast<Metadata&>(a));
|
||||||
|
} catch (const std::bad_cast& e) {
|
||||||
|
return BaseVersion::operator>(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Java
|
64
launcher/java/JavaMetadata.h
Normal file
64
launcher/java/JavaMetadata.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "BaseVersion.h"
|
||||||
|
#include "java/JavaVersion.h"
|
||||||
|
|
||||||
|
namespace Java {
|
||||||
|
|
||||||
|
enum class DownloadType { Manifest, Archive, Unknown };
|
||||||
|
|
||||||
|
class Metadata : public BaseVersion {
|
||||||
|
public:
|
||||||
|
virtual QString descriptor() override { return version.toString(); }
|
||||||
|
|
||||||
|
virtual QString name() override { return m_name; }
|
||||||
|
|
||||||
|
virtual QString typeString() const override { return vendor; }
|
||||||
|
|
||||||
|
virtual bool operator<(BaseVersion& a) override;
|
||||||
|
virtual bool operator>(BaseVersion& a) override;
|
||||||
|
bool operator<(const Metadata& rhs);
|
||||||
|
bool operator==(const Metadata& rhs);
|
||||||
|
bool operator>(const Metadata& rhs);
|
||||||
|
|
||||||
|
QString m_name;
|
||||||
|
QString vendor;
|
||||||
|
QString url;
|
||||||
|
QDateTime releaseTime;
|
||||||
|
QString checksumType;
|
||||||
|
QString checksumHash;
|
||||||
|
DownloadType downloadType;
|
||||||
|
QString packageType;
|
||||||
|
JavaVersion version;
|
||||||
|
QString runtimeOS;
|
||||||
|
};
|
||||||
|
using MetadataPtr = std::shared_ptr<Metadata>;
|
||||||
|
|
||||||
|
DownloadType parseDownloadType(QString javaDownload);
|
||||||
|
QString downloadTypeToString(DownloadType javaDownload);
|
||||||
|
MetadataPtr parseJavaMeta(const QJsonObject& libObj);
|
||||||
|
|
||||||
|
} // namespace Java
|
@ -182,56 +182,58 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString
|
|||||||
else if (keyType == KEY_WOW64_32KEY)
|
else if (keyType == KEY_WOW64_32KEY)
|
||||||
archType = "32";
|
archType = "32";
|
||||||
|
|
||||||
HKEY jreKey;
|
for (HKEY baseRegistry : { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }) {
|
||||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyName.toStdWString().c_str(), 0, KEY_READ | keyType | KEY_ENUMERATE_SUB_KEYS, &jreKey) ==
|
HKEY jreKey;
|
||||||
ERROR_SUCCESS) {
|
if (RegOpenKeyExW(baseRegistry, keyName.toStdWString().c_str(), 0, KEY_READ | keyType | KEY_ENUMERATE_SUB_KEYS, &jreKey) ==
|
||||||
// Read the current type version from the registry.
|
ERROR_SUCCESS) {
|
||||||
// This will be used to find any key that contains the JavaHome value.
|
// Read the current type version from the registry.
|
||||||
|
// This will be used to find any key that contains the JavaHome value.
|
||||||
|
|
||||||
WCHAR subKeyName[255];
|
WCHAR subKeyName[255];
|
||||||
DWORD subKeyNameSize, numSubKeys, retCode;
|
DWORD subKeyNameSize, numSubKeys, retCode;
|
||||||
|
|
||||||
// Get the number of subkeys
|
// Get the number of subkeys
|
||||||
RegQueryInfoKeyW(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
RegQueryInfoKeyW(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
// Iterate until RegEnumKeyEx fails
|
// Iterate until RegEnumKeyEx fails
|
||||||
if (numSubKeys > 0) {
|
if (numSubKeys > 0) {
|
||||||
for (DWORD i = 0; i < numSubKeys; i++) {
|
for (DWORD i = 0; i < numSubKeys; i++) {
|
||||||
subKeyNameSize = 255;
|
subKeyNameSize = 255;
|
||||||
retCode = RegEnumKeyExW(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL, NULL);
|
retCode = RegEnumKeyExW(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL, NULL);
|
||||||
QString newSubkeyName = QString::fromWCharArray(subKeyName);
|
QString newSubkeyName = QString::fromWCharArray(subKeyName);
|
||||||
if (retCode == ERROR_SUCCESS) {
|
if (retCode == ERROR_SUCCESS) {
|
||||||
// Now open the registry key for the version that we just got.
|
// Now open the registry key for the version that we just got.
|
||||||
QString newKeyName = keyName + "\\" + newSubkeyName + subkeySuffix;
|
QString newKeyName = keyName + "\\" + newSubkeyName + subkeySuffix;
|
||||||
|
|
||||||
HKEY newKey;
|
HKEY newKey;
|
||||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, newKeyName.toStdWString().c_str(), 0, KEY_READ | keyType, &newKey) ==
|
if (RegOpenKeyExW(baseRegistry, newKeyName.toStdWString().c_str(), 0, KEY_READ | keyType, &newKey) ==
|
||||||
ERROR_SUCCESS) {
|
ERROR_SUCCESS) {
|
||||||
// Read the JavaHome value to find where Java is installed.
|
// Read the JavaHome value to find where Java is installed.
|
||||||
DWORD valueSz = 0;
|
DWORD valueSz = 0;
|
||||||
if (RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, NULL, &valueSz) == ERROR_SUCCESS) {
|
if (RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, NULL, &valueSz) == ERROR_SUCCESS) {
|
||||||
WCHAR* value = new WCHAR[valueSz];
|
WCHAR* value = new WCHAR[valueSz];
|
||||||
RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, (BYTE*)value, &valueSz);
|
RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, (BYTE*)value, &valueSz);
|
||||||
|
|
||||||
QString newValue = QString::fromWCharArray(value);
|
QString newValue = QString::fromWCharArray(value);
|
||||||
delete[] value;
|
delete[] value;
|
||||||
|
|
||||||
// Now, we construct the version object and add it to the list.
|
// Now, we construct the version object and add it to the list.
|
||||||
JavaInstallPtr javaVersion(new JavaInstall());
|
JavaInstallPtr javaVersion(new JavaInstall());
|
||||||
|
|
||||||
javaVersion->id = newSubkeyName;
|
javaVersion->id = newSubkeyName;
|
||||||
javaVersion->arch = archType;
|
javaVersion->arch = archType;
|
||||||
javaVersion->path = QDir(FS::PathCombine(newValue, "bin")).absoluteFilePath("javaw.exe");
|
javaVersion->path = QDir(FS::PathCombine(newValue, "bin")).absoluteFilePath("javaw.exe");
|
||||||
javas.append(javaVersion);
|
javas.append(javaVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
RegCloseKey(newKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
RegCloseKey(newKey);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
RegCloseKey(jreKey);
|
RegCloseKey(jreKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return javas;
|
return javas;
|
||||||
@ -345,6 +347,7 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
}
|
}
|
||||||
|
|
||||||
candidates.append(getMinecraftJavaBundle());
|
candidates.append(getMinecraftJavaBundle());
|
||||||
|
candidates.append(getPrismJavaBundle());
|
||||||
candidates = addJavasFromEnv(candidates);
|
candidates = addJavasFromEnv(candidates);
|
||||||
candidates.removeDuplicates();
|
candidates.removeDuplicates();
|
||||||
return candidates;
|
return candidates;
|
||||||
@ -374,25 +377,43 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
auto home = qEnvironmentVariable("HOME");
|
auto home = qEnvironmentVariable("HOME");
|
||||||
|
|
||||||
// javas downloaded by sdkman
|
// javas downloaded by sdkman
|
||||||
javas.append(FS::PathCombine(home, ".sdkman/candidates/java"));
|
QDir sdkmanDir(FS::PathCombine(home, ".sdkman/candidates/java"));
|
||||||
|
QStringList sdkmanJavas = sdkmanDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
foreach (const QString& java, sdkmanJavas) {
|
||||||
|
javas.append(sdkmanDir.absolutePath() + "/" + java + "/bin/java");
|
||||||
|
}
|
||||||
|
|
||||||
|
// java in user library folder (like from intellij downloads)
|
||||||
|
QDir userLibraryJVMDir(FS::PathCombine(home, "Library/Java/JavaVirtualMachines/"));
|
||||||
|
QStringList userLibraryJVMJavas = userLibraryJVMDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
foreach (const QString& java, userLibraryJVMJavas) {
|
||||||
|
javas.append(userLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java");
|
||||||
|
javas.append(userLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java");
|
||||||
|
}
|
||||||
|
|
||||||
javas.append(getMinecraftJavaBundle());
|
javas.append(getMinecraftJavaBundle());
|
||||||
|
javas.append(getPrismJavaBundle());
|
||||||
javas = addJavasFromEnv(javas);
|
javas = addJavasFromEnv(javas);
|
||||||
javas.removeDuplicates();
|
javas.removeDuplicates();
|
||||||
return javas;
|
return javas;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(Q_OS_LINUX)
|
#elif defined(Q_OS_LINUX) || defined(Q_OS_OPENBSD) || defined(Q_OS_FREEBSD)
|
||||||
QList<QString> JavaUtils::FindJavaPaths()
|
QList<QString> JavaUtils::FindJavaPaths()
|
||||||
{
|
{
|
||||||
QList<QString> javas;
|
QList<QString> javas;
|
||||||
javas.append(this->GetDefaultJava()->path);
|
javas.append(this->GetDefaultJava()->path);
|
||||||
auto scanJavaDir = [&](const QString& dirPath) {
|
auto scanJavaDir = [&](
|
||||||
|
const QString& dirPath,
|
||||||
|
const std::function<bool(const QFileInfo&)>& filter = [](const QFileInfo&) { return true; }) {
|
||||||
QDir dir(dirPath);
|
QDir dir(dirPath);
|
||||||
if (!dir.exists())
|
if (!dir.exists())
|
||||||
return;
|
return;
|
||||||
auto entries = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
auto entries = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
for (auto& entry : entries) {
|
for (auto& entry : entries) {
|
||||||
|
if (!filter(entry))
|
||||||
|
continue;
|
||||||
|
|
||||||
QString prefix;
|
QString prefix;
|
||||||
prefix = entry.canonicalFilePath();
|
prefix = entry.canonicalFilePath();
|
||||||
javas.append(FS::PathCombine(prefix, "jre/bin/java"));
|
javas.append(FS::PathCombine(prefix, "jre/bin/java"));
|
||||||
@ -407,12 +428,21 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
scanJavaDir(snap + dirPath);
|
scanJavaDir(snap + dirPath);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
#if defined(Q_OS_LINUX)
|
||||||
// oracle RPMs
|
// oracle RPMs
|
||||||
scanJavaDirs("/usr/java");
|
scanJavaDirs("/usr/java");
|
||||||
// general locations used by distro packaging
|
// general locations used by distro packaging
|
||||||
scanJavaDirs("/usr/lib/jvm");
|
scanJavaDirs("/usr/lib/jvm");
|
||||||
scanJavaDirs("/usr/lib64/jvm");
|
scanJavaDirs("/usr/lib64/jvm");
|
||||||
scanJavaDirs("/usr/lib32/jvm");
|
scanJavaDirs("/usr/lib32/jvm");
|
||||||
|
// Gentoo's locations for openjdk and openjdk-bin respectively
|
||||||
|
auto gentooFilter = [](const QFileInfo& info) {
|
||||||
|
QString fileName = info.fileName();
|
||||||
|
return fileName.startsWith("openjdk-") || fileName.startsWith("openj9-");
|
||||||
|
};
|
||||||
|
scanJavaDir("/usr/lib64", gentooFilter);
|
||||||
|
scanJavaDir("/usr/lib", gentooFilter);
|
||||||
|
scanJavaDir("/opt", gentooFilter);
|
||||||
// javas stored in Prism Launcher's folder
|
// javas stored in Prism Launcher's folder
|
||||||
scanJavaDirs("java");
|
scanJavaDirs("java");
|
||||||
// manually installed JDKs in /opt
|
// manually installed JDKs in /opt
|
||||||
@ -421,7 +451,10 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
scanJavaDirs("/opt/ibm"); // IBM Semeru Certified Edition
|
scanJavaDirs("/opt/ibm"); // IBM Semeru Certified Edition
|
||||||
// flatpak
|
// flatpak
|
||||||
scanJavaDirs("/app/jdk");
|
scanJavaDirs("/app/jdk");
|
||||||
|
#elif defined(Q_OS_OPENBSD) || defined(Q_OS_FREEBSD)
|
||||||
|
// ports install to /usr/local on OpenBSD & FreeBSD
|
||||||
|
scanJavaDirs("/usr/local");
|
||||||
|
#endif
|
||||||
auto home = qEnvironmentVariable("HOME");
|
auto home = qEnvironmentVariable("HOME");
|
||||||
|
|
||||||
// javas downloaded by IntelliJ
|
// javas downloaded by IntelliJ
|
||||||
@ -432,6 +465,7 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
scanJavaDirs(FS::PathCombine(home, ".gradle/jdks"));
|
scanJavaDirs(FS::PathCombine(home, ".gradle/jdks"));
|
||||||
|
|
||||||
javas.append(getMinecraftJavaBundle());
|
javas.append(getMinecraftJavaBundle());
|
||||||
|
javas.append(getPrismJavaBundle());
|
||||||
javas = addJavasFromEnv(javas);
|
javas = addJavasFromEnv(javas);
|
||||||
javas.removeDuplicates();
|
javas.removeDuplicates();
|
||||||
return javas;
|
return javas;
|
||||||
@ -445,6 +479,8 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
javas.append(this->GetDefaultJava()->path);
|
javas.append(this->GetDefaultJava()->path);
|
||||||
|
|
||||||
javas.append(getMinecraftJavaBundle());
|
javas.append(getMinecraftJavaBundle());
|
||||||
|
javas.append(getPrismJavaBundle());
|
||||||
|
javas.removeDuplicates();
|
||||||
return addJavasFromEnv(javas);
|
return addJavasFromEnv(javas);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -456,12 +492,13 @@ QString JavaUtils::getJavaCheckPath()
|
|||||||
|
|
||||||
QStringList getMinecraftJavaBundle()
|
QStringList getMinecraftJavaBundle()
|
||||||
{
|
{
|
||||||
QString executable = "java";
|
|
||||||
QStringList processpaths;
|
QStringList processpaths;
|
||||||
#if defined(Q_OS_OSX)
|
#if defined(Q_OS_OSX)
|
||||||
processpaths << FS::PathCombine(QDir::homePath(), FS::PathCombine("Library", "Application Support", "minecraft", "runtime"));
|
processpaths << FS::PathCombine(QDir::homePath(), FS::PathCombine("Library", "Application Support", "minecraft", "runtime"));
|
||||||
#elif defined(Q_OS_WIN32)
|
#elif defined(Q_OS_WIN32)
|
||||||
executable += "w.exe";
|
|
||||||
|
auto appDataPath = QProcessEnvironment::systemEnvironment().value("APPDATA", "");
|
||||||
|
processpaths << FS::PathCombine(QFileInfo(appDataPath).absoluteFilePath(), ".minecraft", "runtime");
|
||||||
|
|
||||||
auto appDataPath = QProcessEnvironment::systemEnvironment().value("APPDATA", "");
|
auto appDataPath = QProcessEnvironment::systemEnvironment().value("APPDATA", "");
|
||||||
processpaths << FS::PathCombine(QFileInfo(appDataPath).absoluteFilePath(), ".minecraft", "runtime");
|
processpaths << FS::PathCombine(QFileInfo(appDataPath).absoluteFilePath(), ".minecraft", "runtime");
|
||||||
@ -486,7 +523,7 @@ QStringList getMinecraftJavaBundle()
|
|||||||
auto binFound = false;
|
auto binFound = false;
|
||||||
for (auto& entry : entries) {
|
for (auto& entry : entries) {
|
||||||
if (entry.baseName() == "bin") {
|
if (entry.baseName() == "bin") {
|
||||||
javas.append(FS::PathCombine(entry.canonicalFilePath(), executable));
|
javas.append(FS::PathCombine(entry.canonicalFilePath(), JavaUtils::javaExecutable));
|
||||||
binFound = true;
|
binFound = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -499,3 +536,33 @@ QStringList getMinecraftJavaBundle()
|
|||||||
}
|
}
|
||||||
return javas;
|
return javas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN32)
|
||||||
|
const QString JavaUtils::javaExecutable = "javaw.exe";
|
||||||
|
#else
|
||||||
|
const QString JavaUtils::javaExecutable = "java";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QStringList getPrismJavaBundle()
|
||||||
|
{
|
||||||
|
QList<QString> javas;
|
||||||
|
|
||||||
|
auto scanDir = [&](QString prefix) {
|
||||||
|
javas.append(FS::PathCombine(prefix, "jre", "bin", JavaUtils::javaExecutable));
|
||||||
|
javas.append(FS::PathCombine(prefix, "bin", JavaUtils::javaExecutable));
|
||||||
|
javas.append(FS::PathCombine(prefix, JavaUtils::javaExecutable));
|
||||||
|
};
|
||||||
|
auto scanJavaDir = [&](const QString& dirPath) {
|
||||||
|
QDir dir(dirPath);
|
||||||
|
if (!dir.exists())
|
||||||
|
return;
|
||||||
|
auto entries = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
for (auto& entry : entries) {
|
||||||
|
scanDir(entry.canonicalFilePath());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
scanJavaDir(APPLICATION->javaPath());
|
||||||
|
|
||||||
|
return javas;
|
||||||
|
}
|
||||||
|
@ -15,10 +15,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QProcess>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include "java/JavaInstall.h"
|
||||||
#include "JavaChecker.h"
|
|
||||||
#include "JavaInstallList.h"
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@ -27,6 +26,7 @@
|
|||||||
QString stripVariableEntries(QString name, QString target, QString remove);
|
QString stripVariableEntries(QString name, QString target, QString remove);
|
||||||
QProcessEnvironment CleanEnviroment();
|
QProcessEnvironment CleanEnviroment();
|
||||||
QStringList getMinecraftJavaBundle();
|
QStringList getMinecraftJavaBundle();
|
||||||
|
QStringList getPrismJavaBundle();
|
||||||
|
|
||||||
class JavaUtils : public QObject {
|
class JavaUtils : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -42,4 +42,5 @@ class JavaUtils : public QObject {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static QString getJavaCheckPath();
|
static QString getJavaCheckPath();
|
||||||
|
static const QString javaExecutable;
|
||||||
};
|
};
|
||||||
|
@ -43,12 +43,18 @@ QString JavaVersion::toString() const
|
|||||||
return m_string;
|
return m_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JavaVersion::requiresPermGen()
|
bool JavaVersion::requiresPermGen() const
|
||||||
{
|
{
|
||||||
return !m_parseable || m_major < 8;
|
return !m_parseable || m_major < 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JavaVersion::isModular()
|
bool JavaVersion::defaultsToUtf8() const
|
||||||
|
{
|
||||||
|
// starting from Java 18, UTF-8 is the default charset: https://openjdk.org/jeps/400
|
||||||
|
return m_parseable && m_major >= 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JavaVersion::isModular() const
|
||||||
{
|
{
|
||||||
return m_parseable && m_major >= 9;
|
return m_parseable && m_major >= 9;
|
||||||
}
|
}
|
||||||
@ -59,12 +65,6 @@ bool JavaVersion::operator<(const JavaVersion& rhs)
|
|||||||
auto major = m_major;
|
auto major = m_major;
|
||||||
auto rmajor = rhs.m_major;
|
auto rmajor = rhs.m_major;
|
||||||
|
|
||||||
// HACK: discourage using java 9
|
|
||||||
if (major > 8)
|
|
||||||
major = -major;
|
|
||||||
if (rmajor > 8)
|
|
||||||
rmajor = -rmajor;
|
|
||||||
|
|
||||||
if (major < rmajor)
|
if (major < rmajor)
|
||||||
return true;
|
return true;
|
||||||
if (major > rmajor)
|
if (major > rmajor)
|
||||||
@ -109,3 +109,24 @@ bool JavaVersion::operator>(const JavaVersion& rhs)
|
|||||||
{
|
{
|
||||||
return (!operator<(rhs)) && (!operator==(rhs));
|
return (!operator<(rhs)) && (!operator==(rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JavaVersion::JavaVersion(int major, int minor, int security, int build, QString name)
|
||||||
|
: m_major(major), m_minor(minor), m_security(security), m_name(name), m_parseable(true)
|
||||||
|
{
|
||||||
|
QStringList versions;
|
||||||
|
if (build != 0) {
|
||||||
|
m_prerelease = QString::number(build);
|
||||||
|
versions.push_front(m_prerelease);
|
||||||
|
}
|
||||||
|
if (m_security != 0)
|
||||||
|
versions.push_front(QString::number(m_security));
|
||||||
|
else if (!versions.isEmpty())
|
||||||
|
versions.push_front("0");
|
||||||
|
|
||||||
|
if (m_minor != 0)
|
||||||
|
versions.push_front(QString::number(m_minor));
|
||||||
|
else if (!versions.isEmpty())
|
||||||
|
versions.push_front("0");
|
||||||
|
versions.push_front(QString::number(m_major));
|
||||||
|
m_string = versions.join(".");
|
||||||
|
}
|
||||||
|
@ -16,6 +16,7 @@ class JavaVersion {
|
|||||||
public:
|
public:
|
||||||
JavaVersion() {}
|
JavaVersion() {}
|
||||||
JavaVersion(const QString& rhs);
|
JavaVersion(const QString& rhs);
|
||||||
|
JavaVersion(int major, int minor, int security, int build = 0, QString name = "");
|
||||||
|
|
||||||
JavaVersion& operator=(const QString& rhs);
|
JavaVersion& operator=(const QString& rhs);
|
||||||
|
|
||||||
@ -23,21 +24,24 @@ class JavaVersion {
|
|||||||
bool operator==(const JavaVersion& rhs);
|
bool operator==(const JavaVersion& rhs);
|
||||||
bool operator>(const JavaVersion& rhs);
|
bool operator>(const JavaVersion& rhs);
|
||||||
|
|
||||||
bool requiresPermGen();
|
bool requiresPermGen() const;
|
||||||
|
bool defaultsToUtf8() const;
|
||||||
bool isModular();
|
bool isModular() const;
|
||||||
|
|
||||||
QString toString() const;
|
QString toString() const;
|
||||||
|
|
||||||
int major() { return m_major; }
|
int major() const { return m_major; }
|
||||||
int minor() { return m_minor; }
|
int minor() const { return m_minor; }
|
||||||
int security() { return m_security; }
|
int security() const { return m_security; }
|
||||||
|
QString build() const { return m_prerelease; }
|
||||||
|
QString name() const { return m_name; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_string;
|
QString m_string;
|
||||||
int m_major = 0;
|
int m_major = 0;
|
||||||
int m_minor = 0;
|
int m_minor = 0;
|
||||||
int m_security = 0;
|
int m_security = 0;
|
||||||
|
QString m_name = "";
|
||||||
bool m_parseable = false;
|
bool m_parseable = false;
|
||||||
QString m_prerelease;
|
QString m_prerelease;
|
||||||
};
|
};
|
||||||
|
141
launcher/java/download/ArchiveDownloadTask.cpp
Normal file
141
launcher/java/download/ArchiveDownloadTask.cpp
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
#include "java/download/ArchiveDownloadTask.h"
|
||||||
|
#include <quazip.h>
|
||||||
|
#include <memory>
|
||||||
|
#include "MMCZip.h"
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "Untar.h"
|
||||||
|
#include "net/ChecksumValidator.h"
|
||||||
|
#include "net/NetJob.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
|
namespace Java {
|
||||||
|
ArchiveDownloadTask::ArchiveDownloadTask(QUrl url, QString final_path, QString checksumType, QString checksumHash)
|
||||||
|
: m_url(url), m_final_path(final_path), m_checksum_type(checksumType), m_checksum_hash(checksumHash)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void ArchiveDownloadTask::executeTask()
|
||||||
|
{
|
||||||
|
// JRE found ! download the zip
|
||||||
|
setStatus(tr("Downloading Java"));
|
||||||
|
|
||||||
|
MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("java", m_url.fileName());
|
||||||
|
|
||||||
|
auto download = makeShared<NetJob>(QString("JRE::DownloadJava"), APPLICATION->network());
|
||||||
|
auto action = Net::Download::makeCached(m_url, entry);
|
||||||
|
if (!m_checksum_hash.isEmpty() && !m_checksum_type.isEmpty()) {
|
||||||
|
auto hashType = QCryptographicHash::Algorithm::Sha1;
|
||||||
|
if (m_checksum_type == "sha256") {
|
||||||
|
hashType = QCryptographicHash::Algorithm::Sha256;
|
||||||
|
}
|
||||||
|
action->addValidator(new Net::ChecksumValidator(hashType, QByteArray::fromHex(m_checksum_hash.toUtf8())));
|
||||||
|
}
|
||||||
|
download->addNetAction(action);
|
||||||
|
auto fullPath = entry->getFullPath();
|
||||||
|
|
||||||
|
connect(download.get(), &Task::failed, this, &ArchiveDownloadTask::emitFailed);
|
||||||
|
connect(download.get(), &Task::progress, this, &ArchiveDownloadTask::setProgress);
|
||||||
|
connect(download.get(), &Task::stepProgress, this, &ArchiveDownloadTask::propagateStepProgress);
|
||||||
|
connect(download.get(), &Task::status, this, &ArchiveDownloadTask::setStatus);
|
||||||
|
connect(download.get(), &Task::details, this, &ArchiveDownloadTask::setDetails);
|
||||||
|
connect(download.get(), &Task::succeeded, [this, fullPath] {
|
||||||
|
// This should do all of the extracting and creating folders
|
||||||
|
extractJava(fullPath);
|
||||||
|
});
|
||||||
|
m_task = download;
|
||||||
|
m_task->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveDownloadTask::extractJava(QString input)
|
||||||
|
{
|
||||||
|
setStatus(tr("Extracting Java"));
|
||||||
|
if (input.endsWith("tar")) {
|
||||||
|
setStatus(tr("Extracting Java (Progress is not reported for tar archives)"));
|
||||||
|
QFile in(input);
|
||||||
|
if (!in.open(QFile::ReadOnly)) {
|
||||||
|
emitFailed(tr("Unable to open supplied tar file."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Tar::extract(&in, QDir(m_final_path).absolutePath())) {
|
||||||
|
emitFailed(tr("Unable to extract supplied tar file."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emitSucceeded();
|
||||||
|
return;
|
||||||
|
} else if (input.endsWith("tar.gz") || input.endsWith("taz") || input.endsWith("tgz")) {
|
||||||
|
setStatus(tr("Extracting Java (Progress is not reported for tar archives)"));
|
||||||
|
if (!GZTar::extract(input, QDir(m_final_path).absolutePath())) {
|
||||||
|
emitFailed(tr("Unable to extract supplied tar file."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emitSucceeded();
|
||||||
|
return;
|
||||||
|
} else if (input.endsWith("zip")) {
|
||||||
|
auto zip = std::make_shared<QuaZip>(input);
|
||||||
|
if (!zip->open(QuaZip::mdUnzip)) {
|
||||||
|
emitFailed(tr("Unable to open supplied zip file."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto files = zip->getFileNameList();
|
||||||
|
if (files.isEmpty()) {
|
||||||
|
emitFailed(tr("No files were found in the supplied zip file."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_task = makeShared<MMCZip::ExtractZipTask>(zip, m_final_path, files[0]);
|
||||||
|
|
||||||
|
auto progressStep = std::make_shared<TaskStepProgress>();
|
||||||
|
connect(m_task.get(), &Task::finished, this, [this, progressStep] {
|
||||||
|
progressStep->state = TaskStepState::Succeeded;
|
||||||
|
stepProgress(*progressStep);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(m_task.get(), &Task::succeeded, this, &ArchiveDownloadTask::emitSucceeded);
|
||||||
|
connect(m_task.get(), &Task::aborted, this, &ArchiveDownloadTask::emitAborted);
|
||||||
|
connect(m_task.get(), &Task::failed, this, [this, progressStep](QString reason) {
|
||||||
|
progressStep->state = TaskStepState::Failed;
|
||||||
|
stepProgress(*progressStep);
|
||||||
|
emitFailed(reason);
|
||||||
|
});
|
||||||
|
connect(m_task.get(), &Task::stepProgress, this, &ArchiveDownloadTask::propagateStepProgress);
|
||||||
|
|
||||||
|
connect(m_task.get(), &Task::progress, this, [this, progressStep](qint64 current, qint64 total) {
|
||||||
|
progressStep->update(current, total);
|
||||||
|
stepProgress(*progressStep);
|
||||||
|
});
|
||||||
|
connect(m_task.get(), &Task::status, this, [this, progressStep](QString status) {
|
||||||
|
progressStep->status = status;
|
||||||
|
stepProgress(*progressStep);
|
||||||
|
});
|
||||||
|
m_task->start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emitFailed(tr("Could not determine archive type!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArchiveDownloadTask::abort()
|
||||||
|
{
|
||||||
|
auto aborted = canAbort();
|
||||||
|
if (m_task)
|
||||||
|
aborted = m_task->abort();
|
||||||
|
emitAborted();
|
||||||
|
return aborted;
|
||||||
|
};
|
||||||
|
} // namespace Java
|
45
launcher/java/download/ArchiveDownloadTask.h
Normal file
45
launcher/java/download/ArchiveDownloadTask.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QUrl>
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
|
namespace Java {
|
||||||
|
class ArchiveDownloadTask : public Task {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ArchiveDownloadTask(QUrl url, QString final_path, QString checksumType = "", QString checksumHash = "");
|
||||||
|
virtual ~ArchiveDownloadTask() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] bool canAbort() const override { return true; }
|
||||||
|
void executeTask() override;
|
||||||
|
virtual bool abort() override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void extractJava(QString input);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QUrl m_url;
|
||||||
|
QString m_final_path;
|
||||||
|
QString m_checksum_type;
|
||||||
|
QString m_checksum_hash;
|
||||||
|
Task::Ptr m_task;
|
||||||
|
};
|
||||||
|
} // namespace Java
|
138
launcher/java/download/ManifestDownloadTask.cpp
Normal file
138
launcher/java/download/ManifestDownloadTask.cpp
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
#include "java/download/ManifestDownloadTask.h"
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "FileSystem.h"
|
||||||
|
#include "Json.h"
|
||||||
|
#include "net/ChecksumValidator.h"
|
||||||
|
#include "net/NetJob.h"
|
||||||
|
|
||||||
|
struct File {
|
||||||
|
QString path;
|
||||||
|
QString url;
|
||||||
|
QByteArray hash;
|
||||||
|
bool isExec;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Java {
|
||||||
|
ManifestDownloadTask::ManifestDownloadTask(QUrl url, QString final_path, QString checksumType, QString checksumHash)
|
||||||
|
: m_url(url), m_final_path(final_path), m_checksum_type(checksumType), m_checksum_hash(checksumHash)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void ManifestDownloadTask::executeTask()
|
||||||
|
{
|
||||||
|
setStatus(tr("Downloading Java"));
|
||||||
|
auto download = makeShared<NetJob>(QString("JRE::DownloadJava"), APPLICATION->network());
|
||||||
|
auto files = std::make_shared<QByteArray>();
|
||||||
|
|
||||||
|
auto action = Net::Download::makeByteArray(m_url, files);
|
||||||
|
if (!m_checksum_hash.isEmpty() && !m_checksum_type.isEmpty()) {
|
||||||
|
auto hashType = QCryptographicHash::Algorithm::Sha1;
|
||||||
|
if (m_checksum_type == "sha256") {
|
||||||
|
hashType = QCryptographicHash::Algorithm::Sha256;
|
||||||
|
}
|
||||||
|
action->addValidator(new Net::ChecksumValidator(hashType, QByteArray::fromHex(m_checksum_hash.toUtf8())));
|
||||||
|
}
|
||||||
|
download->addNetAction(action);
|
||||||
|
|
||||||
|
connect(download.get(), &Task::failed, this, &ManifestDownloadTask::emitFailed);
|
||||||
|
connect(download.get(), &Task::progress, this, &ManifestDownloadTask::setProgress);
|
||||||
|
connect(download.get(), &Task::stepProgress, this, &ManifestDownloadTask::propagateStepProgress);
|
||||||
|
connect(download.get(), &Task::status, this, &ManifestDownloadTask::setStatus);
|
||||||
|
connect(download.get(), &Task::details, this, &ManifestDownloadTask::setDetails);
|
||||||
|
|
||||||
|
connect(download.get(), &Task::succeeded, [files, this] {
|
||||||
|
QJsonParseError parse_error{};
|
||||||
|
QJsonDocument doc = QJsonDocument::fromJson(*files, &parse_error);
|
||||||
|
if (parse_error.error != QJsonParseError::NoError) {
|
||||||
|
qWarning() << "Error while parsing JSON response at " << parse_error.offset << ". Reason: " << parse_error.errorString();
|
||||||
|
qWarning() << *files;
|
||||||
|
emitFailed(parse_error.errorString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
downloadJava(doc);
|
||||||
|
});
|
||||||
|
m_task = download;
|
||||||
|
m_task->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ManifestDownloadTask::downloadJava(const QJsonDocument& doc)
|
||||||
|
{
|
||||||
|
// valid json doc, begin making jre spot
|
||||||
|
FS::ensureFolderPathExists(m_final_path);
|
||||||
|
std::vector<File> toDownload;
|
||||||
|
auto list = Json::ensureObject(Json::ensureObject(doc.object()), "files");
|
||||||
|
for (const auto& paths : list.keys()) {
|
||||||
|
auto file = FS::PathCombine(m_final_path, paths);
|
||||||
|
|
||||||
|
const QJsonObject& meta = Json::ensureObject(list, paths);
|
||||||
|
auto type = Json::ensureString(meta, "type");
|
||||||
|
if (type == "directory") {
|
||||||
|
FS::ensureFolderPathExists(file);
|
||||||
|
} else if (type == "link") {
|
||||||
|
// this is linux only !
|
||||||
|
auto path = Json::ensureString(meta, "target");
|
||||||
|
if (!path.isEmpty()) {
|
||||||
|
auto target = FS::PathCombine(file, "../" + path);
|
||||||
|
QFile(target).link(file);
|
||||||
|
}
|
||||||
|
} else if (type == "file") {
|
||||||
|
// TODO download compressed version if it exists ?
|
||||||
|
auto raw = Json::ensureObject(Json::ensureObject(meta, "downloads"), "raw");
|
||||||
|
auto isExec = Json::ensureBoolean(meta, "executable", false);
|
||||||
|
auto url = Json::ensureString(raw, "url");
|
||||||
|
if (!url.isEmpty() && QUrl(url).isValid()) {
|
||||||
|
auto f = File{ file, url, QByteArray::fromHex(Json::ensureString(raw, "sha1").toLatin1()), isExec };
|
||||||
|
toDownload.push_back(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto elementDownload = makeShared<NetJob>("JRE::FileDownload", APPLICATION->network());
|
||||||
|
for (const auto& file : toDownload) {
|
||||||
|
auto dl = Net::Download::makeFile(file.url, file.path);
|
||||||
|
if (!file.hash.isEmpty()) {
|
||||||
|
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, file.hash));
|
||||||
|
}
|
||||||
|
if (file.isExec) {
|
||||||
|
connect(dl.get(), &Net::Download::succeeded,
|
||||||
|
[file] { QFile(file.path).setPermissions(QFile(file.path).permissions() | QFileDevice::Permissions(0x1111)); });
|
||||||
|
}
|
||||||
|
elementDownload->addNetAction(dl);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(elementDownload.get(), &Task::failed, this, &ManifestDownloadTask::emitFailed);
|
||||||
|
connect(elementDownload.get(), &Task::progress, this, &ManifestDownloadTask::setProgress);
|
||||||
|
connect(elementDownload.get(), &Task::stepProgress, this, &ManifestDownloadTask::propagateStepProgress);
|
||||||
|
connect(elementDownload.get(), &Task::status, this, &ManifestDownloadTask::setStatus);
|
||||||
|
connect(elementDownload.get(), &Task::details, this, &ManifestDownloadTask::setDetails);
|
||||||
|
|
||||||
|
connect(elementDownload.get(), &Task::succeeded, this, &ManifestDownloadTask::emitSucceeded);
|
||||||
|
m_task = elementDownload;
|
||||||
|
m_task->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ManifestDownloadTask::abort()
|
||||||
|
{
|
||||||
|
auto aborted = canAbort();
|
||||||
|
if (m_task)
|
||||||
|
aborted = m_task->abort();
|
||||||
|
emitAborted();
|
||||||
|
return aborted;
|
||||||
|
};
|
||||||
|
} // namespace Java
|
46
launcher/java/download/ManifestDownloadTask.h
Normal file
46
launcher/java/download/ManifestDownloadTask.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QUrl>
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
|
namespace Java {
|
||||||
|
|
||||||
|
class ManifestDownloadTask : public Task {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ManifestDownloadTask(QUrl url, QString final_path, QString checksumType = "", QString checksumHash = "");
|
||||||
|
virtual ~ManifestDownloadTask() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] bool canAbort() const override { return true; }
|
||||||
|
void executeTask() override;
|
||||||
|
virtual bool abort() override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void downloadJava(const QJsonDocument& doc);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QUrl m_url;
|
||||||
|
QString m_final_path;
|
||||||
|
QString m_checksum_type;
|
||||||
|
QString m_checksum_hash;
|
||||||
|
Task::Ptr m_task;
|
||||||
|
};
|
||||||
|
} // namespace Java
|
81
launcher/java/download/SymlinkTask.cpp
Normal file
81
launcher/java/download/SymlinkTask.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
#include "java/download/SymlinkTask.h"
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
#include "FileSystem.h"
|
||||||
|
|
||||||
|
namespace Java {
|
||||||
|
SymlinkTask::SymlinkTask(QString final_path) : m_path(final_path) {}
|
||||||
|
|
||||||
|
QString findBinPath(QString root, QString pattern)
|
||||||
|
{
|
||||||
|
auto path = FS::PathCombine(root, pattern);
|
||||||
|
if (QFileInfo::exists(path)) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto entries = QDir(root).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
for (auto& entry : entries) {
|
||||||
|
path = FS::PathCombine(entry.absoluteFilePath(), pattern);
|
||||||
|
if (QFileInfo::exists(path)) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void SymlinkTask::executeTask()
|
||||||
|
{
|
||||||
|
setStatus(tr("Checking for Java binary path"));
|
||||||
|
const auto binPath = FS::PathCombine("bin", "java");
|
||||||
|
const auto wantedPath = FS::PathCombine(m_path, binPath);
|
||||||
|
if (QFileInfo::exists(wantedPath)) {
|
||||||
|
emitSucceeded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setStatus(tr("Searching for Java binary path"));
|
||||||
|
const auto contentsPartialPath = FS::PathCombine("Contents", "Home", binPath);
|
||||||
|
const auto relativePathToBin = findBinPath(m_path, contentsPartialPath);
|
||||||
|
if (relativePathToBin.isEmpty()) {
|
||||||
|
emitFailed(tr("Failed to find Java binary path"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto folderToLink = relativePathToBin.chopped(binPath.length());
|
||||||
|
|
||||||
|
setStatus(tr("Collecting folders to symlink"));
|
||||||
|
auto entries = QDir(folderToLink).entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries);
|
||||||
|
QList<FS::LinkPair> files;
|
||||||
|
setProgress(0, entries.length());
|
||||||
|
for (auto& entry : entries) {
|
||||||
|
files.append({ entry.absoluteFilePath(), FS::PathCombine(m_path, entry.fileName()) });
|
||||||
|
}
|
||||||
|
|
||||||
|
setStatus(tr("Symlinking Java binary path"));
|
||||||
|
FS::create_link folderLink(files);
|
||||||
|
connect(&folderLink, &FS::create_link::fileLinked, [this](QString src, QString dst) { setProgress(m_progress + 1, m_progressTotal); });
|
||||||
|
if (!folderLink()) {
|
||||||
|
emitFailed(folderLink.getOSError().message().c_str());
|
||||||
|
} else {
|
||||||
|
emitSucceeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Java
|
36
launcher/java/download/SymlinkTask.h
Normal file
36
launcher/java/download/SymlinkTask.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
namespace Java {
|
||||||
|
|
||||||
|
class SymlinkTask : public Task {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
SymlinkTask(QString final_path);
|
||||||
|
virtual ~SymlinkTask() = default;
|
||||||
|
|
||||||
|
void executeTask() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QString m_path;
|
||||||
|
Task::Ptr m_task;
|
||||||
|
};
|
||||||
|
} // namespace Java
|
@ -16,9 +16,8 @@
|
|||||||
#include "LaunchStep.h"
|
#include "LaunchStep.h"
|
||||||
#include "LaunchTask.h"
|
#include "LaunchTask.h"
|
||||||
|
|
||||||
void LaunchStep::bind(LaunchTask* parent)
|
LaunchStep::LaunchStep(LaunchTask* parent) : Task(parent), m_parent(parent)
|
||||||
{
|
{
|
||||||
m_parent = parent;
|
|
||||||
connect(this, &LaunchStep::readyForLaunch, parent, &LaunchTask::onReadyForLaunch);
|
connect(this, &LaunchStep::readyForLaunch, parent, &LaunchTask::onReadyForLaunch);
|
||||||
connect(this, &LaunchStep::logLine, parent, &LaunchTask::onLogLine);
|
connect(this, &LaunchStep::logLine, parent, &LaunchTask::onLogLine);
|
||||||
connect(this, &LaunchStep::logLines, parent, &LaunchTask::onLogLines);
|
connect(this, &LaunchStep::logLines, parent, &LaunchTask::onLogLines);
|
||||||
|
@ -24,11 +24,8 @@ class LaunchTask;
|
|||||||
class LaunchStep : public Task {
|
class LaunchStep : public Task {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public: /* methods */
|
public: /* methods */
|
||||||
explicit LaunchStep(LaunchTask* parent) : Task(nullptr), m_parent(parent) { bind(parent); };
|
explicit LaunchStep(LaunchTask* parent);
|
||||||
virtual ~LaunchStep() {};
|
virtual ~LaunchStep() = default;
|
||||||
|
|
||||||
private: /* methods */
|
|
||||||
void bind(LaunchTask* parent);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void logLines(QStringList lines, MessageLevel::Enum level);
|
void logLines(QStringList lines, MessageLevel::Enum level);
|
||||||
|
@ -44,7 +44,6 @@
|
|||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include "MessageLevel.h"
|
#include "MessageLevel.h"
|
||||||
#include "java/JavaChecker.h"
|
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
void LaunchTask::init()
|
void LaunchTask::init()
|
||||||
@ -52,14 +51,14 @@ void LaunchTask::init()
|
|||||||
m_instance->setRunning(true);
|
m_instance->setRunning(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_qobject_ptr<LaunchTask> LaunchTask::create(InstancePtr inst)
|
shared_qobject_ptr<LaunchTask> LaunchTask::create(MinecraftInstancePtr inst)
|
||||||
{
|
{
|
||||||
shared_qobject_ptr<LaunchTask> proc(new LaunchTask(inst));
|
shared_qobject_ptr<LaunchTask> proc(new LaunchTask(inst));
|
||||||
proc->init();
|
proc->init();
|
||||||
return proc;
|
return proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchTask::LaunchTask(InstancePtr instance) : m_instance(instance) {}
|
LaunchTask::LaunchTask(MinecraftInstancePtr instance) : m_instance(instance) {}
|
||||||
|
|
||||||
void LaunchTask::appendStep(shared_qobject_ptr<LaunchStep> step)
|
void LaunchTask::appendStep(shared_qobject_ptr<LaunchStep> step)
|
||||||
{
|
{
|
||||||
|
@ -37,31 +37,31 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <QObjectPtr.h>
|
#include <QObjectPtr.h>
|
||||||
|
#include <minecraft/MinecraftInstance.h>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
#include "LaunchStep.h"
|
#include "LaunchStep.h"
|
||||||
#include "LogModel.h"
|
#include "LogModel.h"
|
||||||
#include "LoggedProcess.h"
|
|
||||||
#include "MessageLevel.h"
|
#include "MessageLevel.h"
|
||||||
|
|
||||||
class LaunchTask : public Task {
|
class LaunchTask : public Task {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
protected:
|
protected:
|
||||||
explicit LaunchTask(InstancePtr instance);
|
explicit LaunchTask(MinecraftInstancePtr instance);
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum State { NotStarted, Running, Waiting, Failed, Aborted, Finished };
|
enum State { NotStarted, Running, Waiting, Failed, Aborted, Finished };
|
||||||
|
|
||||||
public: /* methods */
|
public: /* methods */
|
||||||
static shared_qobject_ptr<LaunchTask> create(InstancePtr inst);
|
static shared_qobject_ptr<LaunchTask> create(MinecraftInstancePtr inst);
|
||||||
virtual ~LaunchTask() {};
|
virtual ~LaunchTask() = default;
|
||||||
|
|
||||||
void appendStep(shared_qobject_ptr<LaunchStep> step);
|
void appendStep(shared_qobject_ptr<LaunchStep> step);
|
||||||
void prependStep(shared_qobject_ptr<LaunchStep> step);
|
void prependStep(shared_qobject_ptr<LaunchStep> step);
|
||||||
void setCensorFilter(QMap<QString, QString> filter);
|
void setCensorFilter(QMap<QString, QString> filter);
|
||||||
|
|
||||||
InstancePtr instance() { return m_instance; }
|
MinecraftInstancePtr instance() { return m_instance; }
|
||||||
|
|
||||||
void setPid(qint64 pid) { m_pid = pid; }
|
void setPid(qint64 pid) { m_pid = pid; }
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ class LaunchTask : public Task {
|
|||||||
void finalizeSteps(bool successful, const QString& error);
|
void finalizeSteps(bool successful, const QString& error);
|
||||||
|
|
||||||
protected: /* data */
|
protected: /* data */
|
||||||
InstancePtr m_instance;
|
MinecraftInstancePtr m_instance;
|
||||||
shared_qobject_ptr<LogModel> m_logModel;
|
shared_qobject_ptr<LogModel> m_logModel;
|
||||||
QList<shared_qobject_ptr<LaunchStep>> m_steps;
|
QList<shared_qobject_ptr<LaunchStep>> m_steps;
|
||||||
QMap<QString, QString> m_censorFilter;
|
QMap<QString, QString> m_censorFilter;
|
||||||
|
67
launcher/launch/TaskStepWrapper.cpp
Normal file
67
launcher/launch/TaskStepWrapper.cpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "TaskStepWrapper.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
|
void TaskStepWrapper::executeTask()
|
||||||
|
{
|
||||||
|
if (m_state == Task::State::AbortedByUser) {
|
||||||
|
emitFailed(tr("Task aborted."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
connect(m_task.get(), &Task::finished, this, &TaskStepWrapper::updateFinished);
|
||||||
|
connect(m_task.get(), &Task::progress, this, &TaskStepWrapper::setProgress);
|
||||||
|
connect(m_task.get(), &Task::stepProgress, this, &TaskStepWrapper::propagateStepProgress);
|
||||||
|
connect(m_task.get(), &Task::status, this, &TaskStepWrapper::setStatus);
|
||||||
|
connect(m_task.get(), &Task::details, this, &TaskStepWrapper::setDetails);
|
||||||
|
emit progressReportingRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskStepWrapper::proceed()
|
||||||
|
{
|
||||||
|
m_task->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskStepWrapper::updateFinished()
|
||||||
|
{
|
||||||
|
if (m_task->wasSuccessful()) {
|
||||||
|
m_task.reset();
|
||||||
|
emitSucceeded();
|
||||||
|
} else {
|
||||||
|
QString reason = tr("Instance update failed because: %1\n\n").arg(m_task->failReason());
|
||||||
|
m_task.reset();
|
||||||
|
emit logLine(reason, MessageLevel::Fatal);
|
||||||
|
emitFailed(reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TaskStepWrapper::canAbort() const
|
||||||
|
{
|
||||||
|
if (m_task) {
|
||||||
|
return m_task->canAbort();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TaskStepWrapper::abort()
|
||||||
|
{
|
||||||
|
if (m_task && m_task->canAbort()) {
|
||||||
|
auto status = m_task->abort();
|
||||||
|
emitFailed("Aborted.");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
return Task::abort();
|
||||||
|
}
|
@ -21,12 +21,11 @@
|
|||||||
#include <launch/LaunchStep.h>
|
#include <launch/LaunchStep.h>
|
||||||
#include <net/Mode.h>
|
#include <net/Mode.h>
|
||||||
|
|
||||||
// FIXME: stupid. should be defined by the instance type? or even completely abstracted away...
|
class TaskStepWrapper : public LaunchStep {
|
||||||
class Update : public LaunchStep {
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit Update(LaunchTask* parent, Net::Mode mode) : LaunchStep(parent), m_mode(mode) {};
|
explicit TaskStepWrapper(LaunchTask* parent, Task::Ptr task) : LaunchStep(parent), m_task(task) {};
|
||||||
virtual ~Update() {};
|
virtual ~TaskStepWrapper() = default;
|
||||||
|
|
||||||
void executeTask() override;
|
void executeTask() override;
|
||||||
bool canAbort() const override;
|
bool canAbort() const override;
|
||||||
@ -38,7 +37,5 @@ class Update : public LaunchStep {
|
|||||||
void updateFinished();
|
void updateFinished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Task::Ptr m_updateTask;
|
Task::Ptr m_task;
|
||||||
bool m_aborted = false;
|
|
||||||
Net::Mode m_mode = Net::Mode::Offline;
|
|
||||||
};
|
};
|
@ -37,6 +37,7 @@
|
|||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
#include <launch/LaunchTask.h>
|
#include <launch/LaunchTask.h>
|
||||||
#include <sys.h>
|
#include <sys.h>
|
||||||
|
#include <QCryptographicHash>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include "java/JavaUtils.h"
|
#include "java/JavaUtils.h"
|
||||||
@ -45,20 +46,23 @@ void CheckJava::executeTask()
|
|||||||
{
|
{
|
||||||
auto instance = m_parent->instance();
|
auto instance = m_parent->instance();
|
||||||
auto settings = instance->settings();
|
auto settings = instance->settings();
|
||||||
m_javaPath = FS::ResolveExecutable(settings->get("JavaPath").toString());
|
|
||||||
|
QString javaPathSetting = settings->get("JavaPath").toString();
|
||||||
|
m_javaPath = FS::ResolveExecutable(javaPathSetting);
|
||||||
|
|
||||||
bool perInstance = settings->get("OverrideJava").toBool() || settings->get("OverrideJavaLocation").toBool();
|
bool perInstance = settings->get("OverrideJava").toBool() || settings->get("OverrideJavaLocation").toBool();
|
||||||
|
|
||||||
auto realJavaPath = QStandardPaths::findExecutable(m_javaPath);
|
auto realJavaPath = QStandardPaths::findExecutable(m_javaPath);
|
||||||
if (realJavaPath.isEmpty()) {
|
if (realJavaPath.isEmpty()) {
|
||||||
if (perInstance) {
|
if (perInstance) {
|
||||||
emit logLine(QString("The java binary \"%1\" couldn't be found. Please fix the java path "
|
emit logLine(QString("The Java binary \"%1\" couldn't be found. Please fix the Java path "
|
||||||
"override in the instance's settings or disable it.")
|
"override in the instance's settings or disable it.")
|
||||||
.arg(m_javaPath),
|
.arg(javaPathSetting),
|
||||||
MessageLevel::Warning);
|
MessageLevel::Warning);
|
||||||
} else {
|
} else {
|
||||||
emit logLine(QString("The java binary \"%1\" couldn't be found. Please set up java in "
|
emit logLine(QString("The Java binary \"%1\" couldn't be found. Please set up Java in "
|
||||||
"the settings.")
|
"the settings.")
|
||||||
.arg(m_javaPath),
|
.arg(javaPathSetting),
|
||||||
MessageLevel::Warning);
|
MessageLevel::Warning);
|
||||||
}
|
}
|
||||||
emitFailed(QString("Java path is not valid."));
|
emitFailed(QString("Java path is not valid."));
|
||||||
@ -90,11 +94,10 @@ void CheckJava::executeTask()
|
|||||||
// if timestamps are not the same, or something is missing, check!
|
// if timestamps are not the same, or something is missing, check!
|
||||||
if (m_javaSignature != storedSignature || storedVersion.size() == 0 || storedArchitecture.size() == 0 ||
|
if (m_javaSignature != storedSignature || storedVersion.size() == 0 || storedArchitecture.size() == 0 ||
|
||||||
storedRealArchitecture.size() == 0 || storedVendor.size() == 0) {
|
storedRealArchitecture.size() == 0 || storedVendor.size() == 0) {
|
||||||
m_JavaChecker.reset(new JavaChecker);
|
m_JavaChecker.reset(new JavaChecker(realJavaPath, "", 0, 0, 0, 0, this));
|
||||||
emit logLine(QString("Checking Java version..."), MessageLevel::Launcher);
|
emit logLine(QString("Checking Java version..."), MessageLevel::Launcher);
|
||||||
connect(m_JavaChecker.get(), &JavaChecker::checkFinished, this, &CheckJava::checkJavaFinished);
|
connect(m_JavaChecker.get(), &JavaChecker::checkFinished, this, &CheckJava::checkJavaFinished);
|
||||||
m_JavaChecker->m_path = realJavaPath;
|
m_JavaChecker->start();
|
||||||
m_JavaChecker->performCheck();
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
auto verString = instance->settings()->get("JavaVersion").toString();
|
auto verString = instance->settings()->get("JavaVersion").toString();
|
||||||
@ -103,13 +106,14 @@ void CheckJava::executeTask()
|
|||||||
auto vendorString = instance->settings()->get("JavaVendor").toString();
|
auto vendorString = instance->settings()->get("JavaVendor").toString();
|
||||||
printJavaInfo(verString, archString, realArchString, vendorString);
|
printJavaInfo(verString, archString, realArchString, vendorString);
|
||||||
}
|
}
|
||||||
|
m_parent->instance()->updateRuntimeContext();
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckJava::checkJavaFinished(JavaCheckResult result)
|
void CheckJava::checkJavaFinished(const JavaChecker::Result& result)
|
||||||
{
|
{
|
||||||
switch (result.validity) {
|
switch (result.validity) {
|
||||||
case JavaCheckResult::Validity::Errored: {
|
case JavaChecker::Result::Validity::Errored: {
|
||||||
// Error message displayed if java can't start
|
// Error message displayed if java can't start
|
||||||
emit logLine(QString("Could not start java:"), MessageLevel::Error);
|
emit logLine(QString("Could not start java:"), MessageLevel::Error);
|
||||||
emit logLines(result.errorLog.split('\n'), MessageLevel::Error);
|
emit logLines(result.errorLog.split('\n'), MessageLevel::Error);
|
||||||
@ -117,14 +121,15 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
|||||||
emitFailed(QString("Could not start java!"));
|
emitFailed(QString("Could not start java!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case JavaCheckResult::Validity::ReturnedInvalidData: {
|
case JavaChecker::Result::Validity::ReturnedInvalidData: {
|
||||||
emit logLine(QString("Java checker returned some invalid data we don't understand:"), MessageLevel::Error);
|
emit logLine(QString("Java checker returned some invalid data we don't understand:"), MessageLevel::Error);
|
||||||
emit logLines(result.outLog.split('\n'), MessageLevel::Warning);
|
emit logLines(result.outLog.split('\n'), MessageLevel::Warning);
|
||||||
emit logLine("\nMinecraft might not start properly.", MessageLevel::Launcher);
|
emit logLine("\nMinecraft might not start properly.", MessageLevel::Launcher);
|
||||||
|
m_parent->instance()->updateRuntimeContext();
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case JavaCheckResult::Validity::Valid: {
|
case JavaChecker::Result::Validity::Valid: {
|
||||||
auto instance = m_parent->instance();
|
auto instance = m_parent->instance();
|
||||||
printJavaInfo(result.javaVersion.toString(), result.mojangPlatform, result.realPlatform, result.javaVendor);
|
printJavaInfo(result.javaVersion.toString(), result.mojangPlatform, result.realPlatform, result.javaVendor);
|
||||||
instance->settings()->set("JavaVersion", result.javaVersion.toString());
|
instance->settings()->set("JavaVersion", result.javaVersion.toString());
|
||||||
@ -132,6 +137,7 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
|||||||
instance->settings()->set("JavaRealArchitecture", result.realPlatform);
|
instance->settings()->set("JavaRealArchitecture", result.realPlatform);
|
||||||
instance->settings()->set("JavaVendor", result.javaVendor);
|
instance->settings()->set("JavaVendor", result.javaVendor);
|
||||||
instance->settings()->set("JavaSignature", m_javaSignature);
|
instance->settings()->set("JavaSignature", m_javaSignature);
|
||||||
|
m_parent->instance()->updateRuntimeContext();
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -23,12 +23,12 @@ class CheckJava : public LaunchStep {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit CheckJava(LaunchTask* parent) : LaunchStep(parent) {};
|
explicit CheckJava(LaunchTask* parent) : LaunchStep(parent) {};
|
||||||
virtual ~CheckJava() {};
|
virtual ~CheckJava() = default;
|
||||||
|
|
||||||
virtual void executeTask();
|
virtual void executeTask();
|
||||||
virtual bool canAbort() const { return false; }
|
virtual bool canAbort() const { return false; }
|
||||||
private slots:
|
private slots:
|
||||||
void checkJavaFinished(JavaCheckResult result);
|
void checkJavaFinished(const JavaChecker::Result& result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void printJavaInfo(const QString& version, const QString& architecture, const QString& realArchitecture, const QString& vendor);
|
void printJavaInfo(const QString& version, const QString& architecture, const QString& realArchitecture, const QString& vendor);
|
||||||
@ -37,5 +37,5 @@ class CheckJava : public LaunchStep {
|
|||||||
private:
|
private:
|
||||||
QString m_javaPath;
|
QString m_javaPath;
|
||||||
QString m_javaSignature;
|
QString m_javaSignature;
|
||||||
JavaCheckerPtr m_JavaChecker;
|
JavaChecker::Ptr m_JavaChecker;
|
||||||
};
|
};
|
||||||
|
@ -30,7 +30,7 @@ void LookupServerAddress::setLookupAddress(const QString& lookupAddress)
|
|||||||
m_dnsLookup->setName(QString("_minecraft._tcp.%1").arg(lookupAddress));
|
m_dnsLookup->setName(QString("_minecraft._tcp.%1").arg(lookupAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LookupServerAddress::setOutputAddressPtr(MinecraftServerTargetPtr output)
|
void LookupServerAddress::setOutputAddressPtr(MinecraftTarget::Ptr output)
|
||||||
{
|
{
|
||||||
m_output = std::move(output);
|
m_output = std::move(output);
|
||||||
}
|
}
|
||||||
|
@ -19,20 +19,20 @@
|
|||||||
#include <launch/LaunchStep.h>
|
#include <launch/LaunchStep.h>
|
||||||
#include <QDnsLookup>
|
#include <QDnsLookup>
|
||||||
|
|
||||||
#include "minecraft/launch/MinecraftServerTarget.h"
|
#include "minecraft/launch/MinecraftTarget.h"
|
||||||
|
|
||||||
class LookupServerAddress : public LaunchStep {
|
class LookupServerAddress : public LaunchStep {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit LookupServerAddress(LaunchTask* parent);
|
explicit LookupServerAddress(LaunchTask* parent);
|
||||||
virtual ~LookupServerAddress() {};
|
virtual ~LookupServerAddress() = default;
|
||||||
|
|
||||||
virtual void executeTask();
|
virtual void executeTask();
|
||||||
virtual bool abort();
|
virtual bool abort();
|
||||||
virtual bool canAbort() const { return true; }
|
virtual bool canAbort() const { return true; }
|
||||||
|
|
||||||
void setLookupAddress(const QString& lookupAddress);
|
void setLookupAddress(const QString& lookupAddress);
|
||||||
void setOutputAddressPtr(MinecraftServerTargetPtr output);
|
void setOutputAddressPtr(MinecraftTarget::Ptr output);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_dnsLookupFinished();
|
void on_dnsLookupFinished();
|
||||||
@ -42,5 +42,5 @@ class LookupServerAddress : public LaunchStep {
|
|||||||
|
|
||||||
QDnsLookup* m_dnsLookup;
|
QDnsLookup* m_dnsLookup;
|
||||||
QString m_lookupAddress;
|
QString m_lookupAddress;
|
||||||
MinecraftServerTargetPtr m_output;
|
MinecraftTarget::Ptr m_output;
|
||||||
};
|
};
|
||||||
|
65
launcher/launch/steps/PrintServers.cpp
Normal file
65
launcher/launch/steps/PrintServers.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2024 Leia uwu <leia@tutamail.com>
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PrintServers.h"
|
||||||
|
#include "QHostInfo"
|
||||||
|
|
||||||
|
PrintServers::PrintServers(LaunchTask* parent, const QStringList& servers) : LaunchStep(parent)
|
||||||
|
{
|
||||||
|
m_servers = servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintServers::executeTask()
|
||||||
|
{
|
||||||
|
for (QString server : m_servers) {
|
||||||
|
QHostInfo::lookupHost(server, this, &PrintServers::resolveServer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintServers::resolveServer(const QHostInfo& host_info)
|
||||||
|
{
|
||||||
|
QString server = host_info.hostName();
|
||||||
|
QString addresses = server + " resolves to:\n [";
|
||||||
|
|
||||||
|
if (!host_info.addresses().isEmpty()) {
|
||||||
|
for (QHostAddress address : host_info.addresses()) {
|
||||||
|
addresses += address.toString();
|
||||||
|
if (!host_info.addresses().endsWith(address)) {
|
||||||
|
addresses += ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addresses += "N/A";
|
||||||
|
}
|
||||||
|
addresses += "]\n\n";
|
||||||
|
|
||||||
|
m_server_to_address.insert(server, addresses);
|
||||||
|
|
||||||
|
// print server info in order once all servers are resolved
|
||||||
|
if (m_server_to_address.size() >= m_servers.size()) {
|
||||||
|
for (QString serv : m_servers) {
|
||||||
|
emit logLine(m_server_to_address.value(serv), MessageLevel::Launcher);
|
||||||
|
}
|
||||||
|
emitSucceeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PrintServers::canAbort() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
37
launcher/launch/steps/PrintServers.h
Normal file
37
launcher/launch/steps/PrintServers.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2024 Leia uwu <leia@tutamail.com>
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LoggedProcess.h>
|
||||||
|
#include <java/JavaChecker.h>
|
||||||
|
#include <launch/LaunchStep.h>
|
||||||
|
#include <QHostInfo>
|
||||||
|
|
||||||
|
class PrintServers : public LaunchStep {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
PrintServers(LaunchTask* parent, const QStringList& servers);
|
||||||
|
|
||||||
|
virtual void executeTask();
|
||||||
|
virtual bool canAbort() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void resolveServer(const QHostInfo& host_info);
|
||||||
|
QMap<QString, QString> m_server_to_address;
|
||||||
|
QStringList m_servers;
|
||||||
|
};
|
@ -24,7 +24,7 @@ class QuitAfterGameStop : public LaunchStep {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit QuitAfterGameStop(LaunchTask* parent) : LaunchStep(parent) {};
|
explicit QuitAfterGameStop(LaunchTask* parent) : LaunchStep(parent) {};
|
||||||
virtual ~QuitAfterGameStop() {};
|
virtual ~QuitAfterGameStop() = default;
|
||||||
|
|
||||||
virtual void executeTask();
|
virtual void executeTask();
|
||||||
virtual bool canAbort() const { return false; }
|
virtual bool canAbort() const { return false; }
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user