Merge branch 'develop' of github.com:Trial97/PrismLauncher into quick-play
This commit is contained in:
commit
23bdccc91d
5
.clang-tidy
Normal file
5
.clang-tidy
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Checks:
|
||||||
|
- modernize-use-using
|
||||||
|
- readability-avoid-const-params-in-decls
|
||||||
|
|
||||||
|
SystemHeaders: false
|
5
.github/workflows/backport.yml
vendored
5
.github/workflows/backport.yml
vendored
@ -16,15 +16,16 @@ 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
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
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@v1.3.1
|
uses: korthout/backport-action@v2.4.1
|
||||||
with:
|
with:
|
||||||
# Config README: https://github.com/korthout/backport-action#backport-action
|
# Config README: https://github.com/korthout/backport-action#backport-action
|
||||||
pull_description: |-
|
pull_description: |-
|
||||||
|
262
.github/workflows/build.yml
vendored
262
.github/workflows/build.yml
vendored
@ -21,8 +21,29 @@ on:
|
|||||||
WINDOWS_CODESIGN_PASSWORD:
|
WINDOWS_CODESIGN_PASSWORD:
|
||||||
description: Password for signing Windows builds
|
description: Password for signing Windows builds
|
||||||
required: false
|
required: false
|
||||||
CACHIX_AUTH_TOKEN:
|
APPLE_CODESIGN_CERT:
|
||||||
description: Private token for authenticating against Cachix cache
|
description: Certificate for signing macOS builds
|
||||||
|
required: false
|
||||||
|
APPLE_CODESIGN_PASSWORD:
|
||||||
|
description: Password for signing macOS builds
|
||||||
|
required: false
|
||||||
|
APPLE_CODESIGN_ID:
|
||||||
|
description: Certificate ID for signing macOS builds
|
||||||
|
required: false
|
||||||
|
APPLE_NOTARIZE_APPLE_ID:
|
||||||
|
description: Apple ID used for notarizing macOS builds
|
||||||
|
required: false
|
||||||
|
APPLE_NOTARIZE_TEAM_ID:
|
||||||
|
description: Team ID used for notarizing macOS builds
|
||||||
|
required: false
|
||||||
|
APPLE_NOTARIZE_PASSWORD:
|
||||||
|
description: Password used for notarizing macOS builds
|
||||||
|
required: false
|
||||||
|
GPG_PRIVATE_KEY:
|
||||||
|
description: Private key for AppImage signing
|
||||||
|
required: false
|
||||||
|
GPG_PRIVATE_KEY_ID:
|
||||||
|
description: ID for the GPG_PRIVATE_KEY, to select the signing key
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@ -31,56 +52,43 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
|
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
qt_ver: 5
|
qt_ver: 5
|
||||||
|
|
||||||
- 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"
|
||||||
qt_tools: ''
|
qt_tools: ""
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
name: "Windows-MinGW-w64"
|
name: "Windows-MinGW-w64"
|
||||||
msystem: clang64
|
msystem: clang64
|
||||||
vcvars_arch: 'amd64_x86'
|
vcvars_arch: "amd64_x86"
|
||||||
|
|
||||||
- os: windows-2022
|
|
||||||
name: "Windows-MSVC-Legacy"
|
|
||||||
msystem: ''
|
|
||||||
architecture: 'win32'
|
|
||||||
vcvars_arch: 'amd64_x86'
|
|
||||||
qt_ver: 5
|
|
||||||
qt_host: windows
|
|
||||||
qt_arch: 'win32_msvc2019'
|
|
||||||
qt_version: '5.15.2'
|
|
||||||
qt_modules: ''
|
|
||||||
qt_tools: 'tools_openssl_x86'
|
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
name: "Windows-MSVC"
|
name: "Windows-MSVC"
|
||||||
msystem: ''
|
msystem: ""
|
||||||
architecture: 'x64'
|
architecture: "x64"
|
||||||
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.5.2'
|
qt_version: '6.6.2'
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
qt_modules: 'qt5compat qtimageformats'
|
||||||
qt_tools: ''
|
qt_tools: ''
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
name: "Windows-MSVC-arm64"
|
name: "Windows-MSVC-arm64"
|
||||||
msystem: ''
|
msystem: ""
|
||||||
architecture: 'arm64'
|
architecture: "arm64"
|
||||||
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.5.2'
|
qt_version: '6.6.2'
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
qt_modules: 'qt5compat qtimageformats'
|
||||||
qt_tools: ''
|
qt_tools: ''
|
||||||
|
|
||||||
@ -90,7 +98,7 @@ jobs:
|
|||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: mac
|
qt_host: mac
|
||||||
qt_arch: ''
|
qt_arch: ''
|
||||||
qt_version: '6.5.2'
|
qt_version: '6.6.2'
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
qt_modules: 'qt5compat qtimageformats'
|
||||||
qt_tools: ''
|
qt_tools: ''
|
||||||
|
|
||||||
@ -99,9 +107,9 @@ jobs:
|
|||||||
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: ""
|
||||||
qt_tools: ''
|
qt_tools: ""
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
@ -119,11 +127,11 @@ jobs:
|
|||||||
# PREPARE
|
# PREPARE
|
||||||
##
|
##
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: 'true'
|
submodules: "true"
|
||||||
|
|
||||||
- name: 'Setup MSYS2'
|
- name: "Setup MSYS2"
|
||||||
if: runner.os == 'Windows' && matrix.msystem != ''
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
uses: msys2/setup-msys2@v2
|
uses: msys2/setup-msys2@v2
|
||||||
with:
|
with:
|
||||||
@ -152,18 +160,18 @@ jobs:
|
|||||||
|
|
||||||
- name: Setup ccache
|
- name: Setup ccache
|
||||||
if: (runner.os != 'Windows' || matrix.msystem == '') && inputs.build_type == 'Debug'
|
if: (runner.os != 'Windows' || matrix.msystem == '') && inputs.build_type == 'Debug'
|
||||||
uses: hendrikmuhs/ccache-action@v1.2.10
|
uses: hendrikmuhs/ccache-action@v1.2.12
|
||||||
with:
|
with:
|
||||||
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}-${{ matrix.architecture }}
|
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}-${{ matrix.architecture }}
|
||||||
|
|
||||||
- name: Retrieve ccache cache (Windows MinGW-w64)
|
- name: Retrieve ccache cache (Windows MinGW-w64)
|
||||||
if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug'
|
if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug'
|
||||||
uses: actions/cache@v3.3.1
|
uses: actions/cache@v4.0.0
|
||||||
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 }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ matrix.os }}-mingw-w64-ccache
|
${{ matrix.os }}-mingw-w64-ccache
|
||||||
|
|
||||||
- name: Setup ccache (Windows MinGW-w64)
|
- name: Setup ccache (Windows MinGW-w64)
|
||||||
if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug'
|
if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug'
|
||||||
@ -208,35 +216,35 @@ jobs:
|
|||||||
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
|
||||||
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: 'windows'
|
host: "windows"
|
||||||
target: 'desktop'
|
target: "desktop"
|
||||||
arch: ''
|
arch: ""
|
||||||
modules: ${{ matrix.qt_modules }}
|
modules: ${{ matrix.qt_modules }}
|
||||||
tools: ${{ matrix.qt_tools }}
|
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, Qt 6 & Windows MSVC)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver == 6 || runner.os == 'macOS' || (runner.os == 'Windows' && matrix.msystem == '')
|
if: runner.os == 'Linux' && matrix.qt_ver == 6 || runner.os == 'macOS' || (runner.os == 'Windows' && 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 }}
|
host: ${{ matrix.qt_host }}
|
||||||
target: 'desktop'
|
target: "desktop"
|
||||||
arch: ${{ matrix.qt_arch }}
|
arch: ${{ matrix.qt_arch }}
|
||||||
modules: ${{ matrix.qt_modules }}
|
modules: ${{ matrix.qt_modules }}
|
||||||
tools: ${{ matrix.qt_tools }}
|
tools: ${{ matrix.qt_tools }}
|
||||||
cache: ${{ inputs.is_qt_cached }}
|
cache: ${{ inputs.is_qt_cached }}
|
||||||
|
|
||||||
- name: Install MSVC (Windows MSVC)
|
- name: Install MSVC (Windows MSVC)
|
||||||
if: runner.os == 'Windows' # We want this for MinGW builds as well, as we need SignTool
|
if: runner.os == 'Windows' # We want this for MinGW builds as well, as we need SignTool
|
||||||
uses: ilammy/msvc-dev-cmd@v1
|
uses: ilammy/msvc-dev-cmd@v1
|
||||||
with:
|
with:
|
||||||
vsversion: 2022
|
vsversion: 2022
|
||||||
@ -249,6 +257,8 @@ jobs:
|
|||||||
wget "https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage"
|
wget "https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage"
|
||||||
wget "https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage"
|
wget "https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage"
|
||||||
|
|
||||||
|
wget "https://github.com/AppImageCommunity/AppImageUpdate/releases/download/continuous/AppImageUpdate-x86_64.AppImage"
|
||||||
|
|
||||||
${{ github.workspace }}/.github/scripts/prepare_JREs.sh
|
${{ github.workspace }}/.github/scripts/prepare_JREs.sh
|
||||||
sudo apt install libopengl0
|
sudo apt install libopengl0
|
||||||
|
|
||||||
@ -275,12 +285,12 @@ jobs:
|
|||||||
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 -G Ninja
|
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
|
||||||
|
|
||||||
- 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
|
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 }}
|
||||||
# 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 }}")
|
||||||
{
|
{
|
||||||
@ -295,7 +305,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 }} -G Ninja
|
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
|
||||||
|
|
||||||
##
|
##
|
||||||
# BUILD
|
# BUILD
|
||||||
@ -335,12 +345,26 @@ jobs:
|
|||||||
- name: Test (Windows MSVC)
|
- name: Test (Windows MSVC)
|
||||||
if: runner.os == 'Windows' && matrix.msystem == '' && matrix.architecture != 'arm64'
|
if: runner.os == 'Windows' && matrix.msystem == '' && matrix.architecture != 'arm64'
|
||||||
run: |
|
run: |
|
||||||
ctest -E "^example64|example$" --test-dir build --output-on-failure -C ${{ inputs.build_type }}
|
ctest -E "^example64|example$" --test-dir build --output-on-failure -C ${{ inputs.build_type }}
|
||||||
|
|
||||||
##
|
##
|
||||||
# PACKAGE BUILDS
|
# PACKAGE BUILDS
|
||||||
##
|
##
|
||||||
|
|
||||||
|
- name: Fetch codesign certificate (macOS)
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
run: |
|
||||||
|
echo '${{ secrets.APPLE_CODESIGN_CERT }}' | base64 --decode > codesign.p12
|
||||||
|
if [ -n '${{ secrets.APPLE_CODESIGN_ID }}' ]; then
|
||||||
|
security create-keychain -p '${{ secrets.APPLE_CODESIGN_PASSWORD }}' build.keychain
|
||||||
|
security default-keychain -s build.keychain
|
||||||
|
security unlock-keychain -p '${{ secrets.APPLE_CODESIGN_PASSWORD }}' build.keychain
|
||||||
|
security import codesign.p12 -k build.keychain -P '${{ secrets.APPLE_CODESIGN_PASSWORD }}' -T /usr/bin/codesign
|
||||||
|
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k '${{ secrets.APPLE_CODESIGN_PASSWORD }}' build.keychain
|
||||||
|
else
|
||||||
|
echo ":warning: Using ad-hoc code signing for macOS, as certificate was not present." >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Package (macOS)
|
- name: Package (macOS)
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
run: |
|
run: |
|
||||||
@ -348,9 +372,34 @@ jobs:
|
|||||||
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
cd ${{ env.INSTALL_DIR }}
|
||||||
chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
||||||
sudo codesign --sign - --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
|
||||||
|
if [ -n '${{ secrets.APPLE_CODESIGN_ID }}' ]; then
|
||||||
|
APPLE_CODESIGN_ID='${{ secrets.APPLE_CODESIGN_ID }}'
|
||||||
|
else
|
||||||
|
APPLE_CODESIGN_ID='-'
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo codesign --sign "$APPLE_CODESIGN_ID" --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
||||||
mv "PrismLauncher.app" "Prism Launcher.app"
|
mv "PrismLauncher.app" "Prism Launcher.app"
|
||||||
tar -czf ../PrismLauncher.tar.gz *
|
|
||||||
|
- name: Notarize (macOS)
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
run: |
|
||||||
|
cd ${{ env.INSTALL_DIR }}
|
||||||
|
|
||||||
|
if [ -n '${{ secrets.APPLE_NOTARIZE_PASSWORD }}' ]; then
|
||||||
|
ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip
|
||||||
|
xcrun notarytool submit ../PrismLauncher.zip \
|
||||||
|
--wait --progress \
|
||||||
|
--apple-id '${{ secrets.APPLE_NOTARIZE_APPLE_ID }}' \
|
||||||
|
--team-id '${{ secrets.APPLE_NOTARIZE_TEAM_ID }}' \
|
||||||
|
--password '${{ secrets.APPLE_NOTARIZE_PASSWORD }}'
|
||||||
|
|
||||||
|
xcrun stapler staple "Prism Launcher.app"
|
||||||
|
else
|
||||||
|
echo ":warning: Skipping notarization as credentials are not present." >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip
|
||||||
|
|
||||||
- name: Make Sparkle signature (macOS)
|
- name: Make Sparkle signature (macOS)
|
||||||
if: matrix.name == 'macOS'
|
if: matrix.name == 'macOS'
|
||||||
@ -358,7 +407,7 @@ jobs:
|
|||||||
if [ '${{ secrets.SPARKLE_ED25519_KEY }}' != '' ]; then
|
if [ '${{ secrets.SPARKLE_ED25519_KEY }}' != '' ]; then
|
||||||
brew install openssl@3
|
brew install openssl@3
|
||||||
echo '${{ secrets.SPARKLE_ED25519_KEY }}' > ed25519-priv.pem
|
echo '${{ secrets.SPARKLE_ED25519_KEY }}' > ed25519-priv.pem
|
||||||
signature=$(/usr/local/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.tar.gz -inkey ed25519-priv.pem | openssl base64 | tr -d \\n)
|
signature=$(/usr/local/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.zip -inkey ed25519-priv.pem | openssl base64 | tr -d \\n)
|
||||||
rm ed25519-priv.pem
|
rm ed25519-priv.pem
|
||||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
cat >> $GITHUB_STEP_SUMMARY << EOF
|
||||||
### Artifact Information :information_source:
|
### Artifact Information :information_source:
|
||||||
@ -377,7 +426,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cmake --install ${{ env.BUILD_DIR }}
|
cmake --install ${{ env.BUILD_DIR }}
|
||||||
touch ${{ env.INSTALL_DIR }}/manifest.txt
|
touch ${{ env.INSTALL_DIR }}/manifest.txt
|
||||||
for l in $(find ${{ env.INSTALL_DIR }} -type f); do l=$(cygpath -u $l); l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_DIR }}/}; l=${l#./}; echo $l; done >> ${{ env.INSTALL_DIR }}/manifest.txt
|
for l in $(find ${{ env.INSTALL_DIR }} -type f); do l=$(cygpath -u $l); l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_DIR }}/}; l=${l#./}; echo $l; done >> ${{ env.INSTALL_DIR }}/manifest.txt
|
||||||
|
|
||||||
- name: Package (Windows MSVC)
|
- name: Package (Windows MSVC)
|
||||||
if: runner.os == 'Windows' && matrix.msystem == ''
|
if: runner.os == 'Windows' && matrix.msystem == ''
|
||||||
@ -387,17 +436,16 @@ jobs:
|
|||||||
cd ${{ env.INSTALL_DIR }}
|
cd ${{ env.INSTALL_DIR }}
|
||||||
if ("${{ matrix.qt_ver }}" -eq "5")
|
if ("${{ matrix.qt_ver }}" -eq "5")
|
||||||
{
|
{
|
||||||
Copy-Item D:/a/PrismLauncher/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/libcrypto-1_1.dll -Destination libcrypto-1_1.dll
|
||||||
Copy-Item D:/a/PrismLauncher/Qt/Tools/OpenSSL/Win_x86/bin/libssl-1_1.dll -Destination libssl-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
|
||||||
|
|
||||||
|
|
||||||
- name: Fetch codesign certificate (Windows)
|
- name: Fetch codesign certificate (Windows)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
shell: bash # yes, we are not using MSYS2 or PowerShell here
|
shell: bash # yes, we are not using MSYS2 or PowerShell here
|
||||||
run: |
|
run: |
|
||||||
echo '${{ secrets.WINDOWS_CODESIGN_CERT }}' | base64 --decode > codesign.pfx
|
echo '${{ secrets.WINDOWS_CODESIGN_CERT }}' | base64 --decode > codesign.pfx
|
||||||
|
|
||||||
@ -407,7 +455,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 prismlauncher.exe prismlauncher_filelink.exe
|
SignTool sign /fd sha256 /td sha256 /f ../codesign.pfx /p '${{ secrets.WINDOWS_CODESIGN_PASSWORD }}' /tr http://timestamp.digicert.com prismlauncher.exe prismlauncher_updater.exe prismlauncher_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
|
||||||
}
|
}
|
||||||
@ -425,7 +473,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead
|
cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead
|
||||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
||||||
|
|
||||||
Get-ChildItem ${{ env.INSTALL_PORTABLE_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_PORTABLE_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt
|
Get-ChildItem ${{ env.INSTALL_PORTABLE_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_PORTABLE_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt
|
||||||
|
|
||||||
- name: Package (Windows, installer)
|
- name: Package (Windows, installer)
|
||||||
@ -466,11 +514,15 @@ jobs:
|
|||||||
- 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
|
||||||
|
env:
|
||||||
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
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.prismlauncher.PrismLauncher.metainfo.xml ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/metainfo/org.prismlauncher.PrismLauncher.appdata.xml
|
mv ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/metainfo/org.prismlauncher.PrismLauncher.metainfo.xml ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/metainfo/org.prismlauncher.PrismLauncher.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="PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage"
|
|
||||||
|
export OUTPUT="PrismLauncher-Linux-x86_64.AppImage"
|
||||||
|
|
||||||
chmod +x linuxdeploy-*.AppImage
|
chmod +x linuxdeploy-*.AppImage
|
||||||
|
|
||||||
@ -481,8 +533,8 @@ jobs:
|
|||||||
|
|
||||||
cp -r ${{ github.workspace }}/JREs/jre17/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk
|
cp -r ${{ github.workspace }}/JREs/jre17/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk
|
||||||
|
|
||||||
cp -r /home/runner/work/PrismLauncher/Qt/${{ matrix.qt_version }}/gcc_64/plugins/iconengines/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines
|
cp -r ${{ runner.workspace }}/Qt/${{ matrix.qt_version }}/gcc_64/plugins/iconengines/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines
|
||||||
|
|
||||||
cp /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
|
cp /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
|
||||||
cp /usr/lib/x86_64-linux-gnu/libssl.so.1.1 ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
|
cp /usr/lib/x86_64-linux-gnu/libssl.so.1.1 ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
|
||||||
cp /usr/lib/x86_64-linux-gnu/libOpenGL.so.0* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
|
cp /usr/lib/x86_64-linux-gnu/libOpenGL.so.0* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
|
||||||
@ -494,75 +546,99 @@ jobs:
|
|||||||
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk/lib"
|
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk/lib"
|
||||||
export LD_LIBRARY_PATH
|
export LD_LIBRARY_PATH
|
||||||
|
|
||||||
|
chmod +x AppImageUpdate-x86_64.AppImage
|
||||||
|
cp AppImageUpdate-x86_64.AppImage ${{ env.INSTALL_APPIMAGE_DIR }}/usr/bin
|
||||||
|
|
||||||
|
export UPDATE_INFORMATION="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|PrismLauncher-Linux-x86_64.AppImage.zsync"
|
||||||
|
|
||||||
|
if [ '${{ secrets.GPG_PRIVATE_KEY_ID }}' != '' ]; then
|
||||||
|
export SIGN=1
|
||||||
|
export SIGN_KEY=${{ secrets.GPG_PRIVATE_KEY_ID }}
|
||||||
|
mkdir -p ~/.gnupg/
|
||||||
|
echo "$GPG_PRIVATE_KEY" > ~/.gnupg/private.key
|
||||||
|
gpg --import ~/.gnupg/private.key
|
||||||
|
else
|
||||||
|
echo ":warning: Skipped code signing for Linux AppImage, as gpg key was not present." >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
./linuxdeploy-x86_64.AppImage --appdir ${{ env.INSTALL_APPIMAGE_DIR }} --output appimage --plugin qt -i ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/icons/hicolor/scalable/apps/org.prismlauncher.PrismLauncher.svg
|
./linuxdeploy-x86_64.AppImage --appdir ${{ env.INSTALL_APPIMAGE_DIR }} --output appimage --plugin qt -i ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/icons/hicolor/scalable/apps/org.prismlauncher.PrismLauncher.svg
|
||||||
|
|
||||||
|
mv "PrismLauncher-Linux-x86_64.AppImage" "PrismLauncher-Linux-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage"
|
||||||
|
|
||||||
##
|
##
|
||||||
# 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: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PrismLauncher.tar.gz
|
path: PrismLauncher.zip
|
||||||
|
|
||||||
- name: Upload binary zip (Windows)
|
- name: Upload binary zip (Windows)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: ${{ env.INSTALL_DIR }}/**
|
path: ${{ env.INSTALL_DIR }}/**
|
||||||
|
|
||||||
- name: Upload binary zip (Windows, portable)
|
- name: Upload binary zip (Windows, portable)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ matrix.name }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PrismLauncher-${{ matrix.name }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: ${{ env.INSTALL_PORTABLE_DIR }}/**
|
path: ${{ env.INSTALL_PORTABLE_DIR }}/**
|
||||||
|
|
||||||
- name: Upload installer (Windows)
|
- name: Upload installer (Windows)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PrismLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PrismLauncher-Setup.exe
|
path: PrismLauncher-Setup.exe
|
||||||
|
|
||||||
- name: Upload binary tarball (Linux, Qt 5)
|
- name: Upload binary tarball (Linux, Qt 5)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PrismLauncher-${{ runner.os }}-Qt5-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PrismLauncher.tar.gz
|
path: PrismLauncher.tar.gz
|
||||||
|
|
||||||
- name: Upload binary tarball (Linux, portable, Qt 5)
|
- name: Upload binary tarball (Linux, portable, Qt 5)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PrismLauncher-${{ runner.os }}-Qt5-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PrismLauncher-portable.tar.gz
|
path: PrismLauncher-portable.tar.gz
|
||||||
|
|
||||||
- name: Upload binary tarball (Linux, Qt 6)
|
- name: Upload binary tarball (Linux, Qt 6)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver !=5
|
if: runner.os == 'Linux' && matrix.qt_ver !=5
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-Qt6-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PrismLauncher-${{ runner.os }}-Qt6-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PrismLauncher.tar.gz
|
path: PrismLauncher.tar.gz
|
||||||
|
|
||||||
- name: Upload binary tarball (Linux, portable, Qt 6)
|
- name: Upload binary tarball (Linux, portable, Qt 6)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-Qt6-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PrismLauncher-${{ runner.os }}-Qt6-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PrismLauncher-portable.tar.gz
|
path: PrismLauncher-portable.tar.gz
|
||||||
|
|
||||||
- name: Upload AppImage (Linux)
|
- name: Upload AppImage (Linux)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||||
path: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
path: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||||
|
|
||||||
|
- name: Upload AppImage Zsync (Linux)
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage.zsync
|
||||||
|
path: PrismLauncher-Linux-x86_64.AppImage.zsync
|
||||||
|
|
||||||
- name: ccache stats (Windows MinGW-w64)
|
- name: ccache stats (Windows MinGW-w64)
|
||||||
if: runner.os == 'Windows' && matrix.msystem != ''
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
@ -572,17 +648,17 @@ jobs:
|
|||||||
flatpak:
|
flatpak:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: bilelmoussaoui/flatpak-github-actions:kde-5.15-22.08
|
image: bilelmoussaoui/flatpak-github-actions:kde-5.15-23.08
|
||||||
options: --privileged
|
options: --privileged
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
if: inputs.build_type == 'Debug'
|
if: inputs.build_type == 'Debug'
|
||||||
with:
|
with:
|
||||||
submodules: 'true'
|
submodules: "true"
|
||||||
- name: Build Flatpak (Linux)
|
- name: Build Flatpak (Linux)
|
||||||
if: inputs.build_type == 'Debug'
|
if: inputs.build_type == 'Debug'
|
||||||
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
||||||
with:
|
with:
|
||||||
bundle: "Prism Launcher.flatpak"
|
bundle: "Prism Launcher.flatpak"
|
||||||
manifest-path: flatpak/org.prismlauncher.PrismLauncher.yml
|
manifest-path: flatpak/org.prismlauncher.PrismLauncher.yml
|
||||||
|
6
.github/workflows/codeql.yml
vendored
6
.github/workflows/codeql.yml
vendored
@ -8,12 +8,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: 'true'
|
submodules: 'true'
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v2
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
config-file: ./.github/codeql/codeql-config.yml
|
config-file: ./.github/codeql/codeql-config.yml
|
||||||
queries: security-and-quality
|
queries: security-and-quality
|
||||||
@ -32,4 +32,4 @@ jobs:
|
|||||||
cmake --build build
|
cmake --build build
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v2
|
uses: github/codeql-action/analyze@v3
|
||||||
|
36
.github/workflows/trigger_builds.yml
vendored
36
.github/workflows/trigger_builds.yml
vendored
@ -3,26 +3,25 @@ name: Build Application
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches-ignore:
|
branches-ignore:
|
||||||
- 'renovate/**'
|
- "renovate/**"
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- "**.md"
|
||||||
- '**/LICENSE'
|
- "**/LICENSE"
|
||||||
- 'flake.lock'
|
- "flake.lock"
|
||||||
- 'packages/**'
|
- "packages/**"
|
||||||
- '.github/ISSUE_TEMPLATE/**'
|
- ".github/ISSUE_TEMPLATE/**"
|
||||||
- '.markdownlint**'
|
- ".markdownlint**"
|
||||||
pull_request:
|
pull_request:
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- "**.md"
|
||||||
- '**/LICENSE'
|
- "**/LICENSE"
|
||||||
- 'flake.lock'
|
- "flake.lock"
|
||||||
- 'packages/**'
|
- "packages/**"
|
||||||
- '.github/ISSUE_TEMPLATE/**'
|
- ".github/ISSUE_TEMPLATE/**"
|
||||||
- '.markdownlint**'
|
- ".markdownlint**"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
build_debug:
|
build_debug:
|
||||||
name: Build Debug
|
name: Build Debug
|
||||||
uses: ./.github/workflows/build.yml
|
uses: ./.github/workflows/build.yml
|
||||||
@ -33,4 +32,11 @@ jobs:
|
|||||||
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
||||||
WINDOWS_CODESIGN_CERT: ${{ secrets.WINDOWS_CODESIGN_CERT }}
|
WINDOWS_CODESIGN_CERT: ${{ secrets.WINDOWS_CODESIGN_CERT }}
|
||||||
WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
|
WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
|
||||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
APPLE_CODESIGN_CERT: ${{ secrets.APPLE_CODESIGN_CERT }}
|
||||||
|
APPLE_CODESIGN_PASSWORD: ${{ secrets.APPLE_CODESIGN_PASSWORD }}
|
||||||
|
APPLE_CODESIGN_ID: ${{ secrets.APPLE_CODESIGN_ID }}
|
||||||
|
APPLE_NOTARIZE_APPLE_ID: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }}
|
||||||
|
APPLE_NOTARIZE_TEAM_ID: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }}
|
||||||
|
APPLE_NOTARIZE_PASSWORD: ${{ secrets.APPLE_NOTARIZE_PASSWORD }}
|
||||||
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
|
GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }}
|
||||||
|
50
.github/workflows/trigger_release.yml
vendored
50
.github/workflows/trigger_release.yml
vendored
@ -3,10 +3,9 @@ name: Build Application and Make Release
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- '*'
|
- "*"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
build_release:
|
build_release:
|
||||||
name: Build Release
|
name: Build Release
|
||||||
uses: ./.github/workflows/build.yml
|
uses: ./.github/workflows/build.yml
|
||||||
@ -17,7 +16,14 @@ jobs:
|
|||||||
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
||||||
WINDOWS_CODESIGN_CERT: ${{ secrets.WINDOWS_CODESIGN_CERT }}
|
WINDOWS_CODESIGN_CERT: ${{ secrets.WINDOWS_CODESIGN_CERT }}
|
||||||
WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
|
WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
|
||||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
APPLE_CODESIGN_CERT: ${{ secrets.APPLE_CODESIGN_CERT }}
|
||||||
|
APPLE_CODESIGN_PASSWORD: ${{ secrets.APPLE_CODESIGN_PASSWORD }}
|
||||||
|
APPLE_CODESIGN_ID: ${{ secrets.APPLE_CODESIGN_ID }}
|
||||||
|
APPLE_NOTARIZE_APPLE_ID: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }}
|
||||||
|
APPLE_NOTARIZE_TEAM_ID: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }}
|
||||||
|
APPLE_NOTARIZE_PASSWORD: ${{ secrets.APPLE_NOTARIZE_PASSWORD }}
|
||||||
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
|
GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }}
|
||||||
|
|
||||||
create_release:
|
create_release:
|
||||||
needs: build_release
|
needs: build_release
|
||||||
@ -26,12 +32,12 @@ jobs:
|
|||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: 'true'
|
submodules: "true"
|
||||||
path: 'PrismLauncher-source'
|
path: "PrismLauncher-source"
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
- name: Grab and store version
|
- name: Grab and store version
|
||||||
run: |
|
run: |
|
||||||
tag_name=$(echo ${{ github.ref }} | grep -oE "[^/]+$")
|
tag_name=$(echo ${{ github.ref }} | grep -oE "[^/]+$")
|
||||||
@ -40,12 +46,13 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mv ${{ github.workspace }}/PrismLauncher-source PrismLauncher-${{ env.VERSION }}
|
mv ${{ github.workspace }}/PrismLauncher-source PrismLauncher-${{ env.VERSION }}
|
||||||
mv PrismLauncher-Linux-Qt6-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
mv PrismLauncher-Linux-Qt6-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
||||||
mv PrismLauncher-Linux-Qt6*/PrismLauncher.tar.gz PrismLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz
|
mv PrismLauncher-Linux-Qt6*/PrismLauncher.tar.gz PrismLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz
|
||||||
mv PrismLauncher-Linux-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Portable-${{ env.VERSION }}.tar.gz
|
mv PrismLauncher-Linux-Qt5-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz
|
||||||
mv PrismLauncher-Linux*/PrismLauncher.tar.gz PrismLauncher-Linux-${{ env.VERSION }}.tar.gz
|
mv PrismLauncher-Linux-Qt5*/PrismLauncher.tar.gz PrismLauncher-Linux-Qt5-${{ env.VERSION }}.tar.gz
|
||||||
mv PrismLauncher-*.AppImage/PrismLauncher-*.AppImage PrismLauncher-Linux-${{ env.VERSION }}-x86_64.AppImage
|
mv PrismLauncher-*.AppImage/PrismLauncher-*.AppImage PrismLauncher-Linux-x86_64.AppImage
|
||||||
mv PrismLauncher-macOS-Legacy*/PrismLauncher.tar.gz PrismLauncher-macOS-Legacy-${{ env.VERSION }}.tar.gz
|
mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*.AppImage.zsync PrismLauncher-Linux-x86_64.AppImage.zsync
|
||||||
mv PrismLauncher-macOS*/PrismLauncher.tar.gz PrismLauncher-macOS-${{ env.VERSION }}.tar.gz
|
mv PrismLauncher-macOS-Legacy*/PrismLauncher.zip PrismLauncher-macOS-Legacy-${{ env.VERSION }}.zip
|
||||||
|
mv PrismLauncher-macOS*/PrismLauncher.zip PrismLauncher-macOS-${{ env.VERSION }}.zip
|
||||||
|
|
||||||
tar --exclude='.git' -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
|
tar --exclude='.git' -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
|
||||||
|
|
||||||
@ -78,31 +85,28 @@ jobs:
|
|||||||
- name: Create release
|
- name: Create release
|
||||||
id: create_release
|
id: create_release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
tag_name: ${{ github.ref }}
|
tag_name: ${{ github.ref }}
|
||||||
name: Prism Launcher ${{ env.VERSION }}
|
name: Prism Launcher ${{ env.VERSION }}
|
||||||
draft: true
|
draft: true
|
||||||
prerelease: false
|
prerelease: false
|
||||||
files: |
|
files: |
|
||||||
PrismLauncher-Linux-${{ env.VERSION }}.tar.gz
|
PrismLauncher-Linux-Qt5-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-Linux-Portable-${{ env.VERSION }}.tar.gz
|
PrismLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-Linux-${{ env.VERSION }}-x86_64.AppImage
|
PrismLauncher-Linux-x86_64.AppImage
|
||||||
|
PrismLauncher-Linux-x86_64.AppImage.zsync
|
||||||
PrismLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz
|
PrismLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-Windows-MinGW-w64-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-MinGW-w64-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-MinGW-w64-Portable-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-MinGW-w64-Portable-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-MinGW-w64-Setup-${{ env.VERSION }}.exe
|
PrismLauncher-Windows-MinGW-w64-Setup-${{ env.VERSION }}.exe
|
||||||
PrismLauncher-Windows-MSVC-Legacy-${{ env.VERSION }}.zip
|
|
||||||
PrismLauncher-Windows-MSVC-Legacy-Portable-${{ env.VERSION }}.zip
|
|
||||||
PrismLauncher-Windows-MSVC-Legacy-Setup-${{ env.VERSION }}.exe
|
|
||||||
PrismLauncher-Windows-MSVC-arm64-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-MSVC-arm64-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-MSVC-arm64-Portable-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-MSVC-arm64-Portable-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-MSVC-arm64-Setup-${{ env.VERSION }}.exe
|
PrismLauncher-Windows-MSVC-arm64-Setup-${{ env.VERSION }}.exe
|
||||||
PrismLauncher-Windows-MSVC-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-MSVC-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-MSVC-Portable-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-MSVC-Portable-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-MSVC-Setup-${{ env.VERSION }}.exe
|
PrismLauncher-Windows-MSVC-Setup-${{ env.VERSION }}.exe
|
||||||
PrismLauncher-macOS-${{ env.VERSION }}.tar.gz
|
PrismLauncher-macOS-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-macOS-Legacy-${{ env.VERSION }}.tar.gz
|
PrismLauncher-macOS-Legacy-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-${{ env.VERSION }}.tar.gz
|
PrismLauncher-${{ env.VERSION }}.tar.gz
|
||||||
|
8
.github/workflows/update-flake.yml
vendored
8
.github/workflows/update-flake.yml
vendored
@ -16,13 +16,15 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: cachix/install-nix-action@v22
|
- uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25
|
||||||
|
|
||||||
- uses: DeterminateSystems/update-flake-lock@v19
|
- uses: DeterminateSystems/update-flake-lock@v20
|
||||||
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"
|
||||||
pr-labels: |
|
pr-labels: |
|
||||||
Linux
|
Linux
|
||||||
|
packaging
|
||||||
simple change
|
simple change
|
||||||
|
changelog:omit
|
||||||
|
@ -33,6 +33,13 @@ if(MSVC)
|
|||||||
# Use /W4 as /Wall includes unnesserey warnings such as added padding to structs
|
# Use /W4 as /Wall includes unnesserey warnings such as added padding to structs
|
||||||
set(CMAKE_CXX_FLAGS "/GS /permissive- /W4 ${CMAKE_CXX_FLAGS}")
|
set(CMAKE_CXX_FLAGS "/GS /permissive- /W4 ${CMAKE_CXX_FLAGS}")
|
||||||
|
|
||||||
|
# /EHs Enables stack unwind semantics for standard C++ exceptions to ensure stackframes are unwound
|
||||||
|
# and object deconstructors are called when an exception is caught.
|
||||||
|
# without it memory leaks and a warning is printed
|
||||||
|
# /EHc tells the compiler to assume that functions declared as extern "C" never throw a C++ exception
|
||||||
|
# This appears to not always be a defualt compiler option in CMAKE
|
||||||
|
set(CMAKE_CXX_FLAGS "/EHsc ${CMAKE_CXX_FLAGS}")
|
||||||
|
|
||||||
# LINK accepts /SUBSYSTEM whics sets if we are a WINDOWS (gui) or a CONSOLE programs
|
# LINK accepts /SUBSYSTEM whics sets if we are a WINDOWS (gui) or a CONSOLE programs
|
||||||
# This implicitly selects an entrypoint specific to the subsystem selected
|
# This implicitly selects an entrypoint specific to the subsystem selected
|
||||||
# qtmain/QtEntryPointLib provides the correct entrypoint (wWinMain) for gui programs
|
# qtmain/QtEntryPointLib provides the correct entrypoint (wWinMain) for gui programs
|
||||||
@ -88,35 +95,36 @@ set(CMAKE_CXX_FLAGS_RELEASE "-O2 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS_RELEASE}"
|
|||||||
option(DEBUG_ADDRESS_SANITIZER "Enable Address Sanitizer in Debug builds" OFF)
|
option(DEBUG_ADDRESS_SANITIZER "Enable Address Sanitizer in Debug builds" OFF)
|
||||||
|
|
||||||
# If this is a Debug build turn on address sanitiser
|
# If this is a Debug build turn on address sanitiser
|
||||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug" AND DEBUG_ADDRESS_SANITIZER)
|
if ((CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") AND DEBUG_ADDRESS_SANITIZER)
|
||||||
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 /O1 /Oy-")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /Oy-")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /O1 /Oy-")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /Oy-")
|
||||||
else()
|
else()
|
||||||
# AppleClang and Clang
|
# AppleClang and Clang
|
||||||
message(STATUS "Address Sanitizer available on Clang")
|
message(STATUS "Address Sanitizer available on Clang")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -O1 -fno-omit-frame-pointer")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -O1 -fno-omit-frame-pointer")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||||
endif()
|
endif()
|
||||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||||
# GCC
|
# GCC
|
||||||
message(STATUS "Address Sanitizer available on GCC")
|
message(STATUS "Address Sanitizer available on GCC")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -O1 -fno-omit-frame-pointer")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -O1 -fno-omit-frame-pointer")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||||
link_libraries("asan")
|
link_libraries("asan")
|
||||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||||
message(STATUS "Address Sanitizer available on MSVC")
|
message(STATUS "Address Sanitizer available on MSVC")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /O1 /Oy-")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /Oy-")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /O1 /Oy-")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /Oy-")
|
||||||
else()
|
else()
|
||||||
message(STATUS "Address Sanitizer not available on compiler ${CMAKE_CXX_COMPILER_ID}")
|
message(STATUS "Address Sanitizer not available on compiler ${CMAKE_CXX_COMPILER_ID}")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
option(ENABLE_LTO "Enable Link Time Optimization" off)
|
option(ENABLE_LTO "Enable Link Time Optimization" off)
|
||||||
|
|
||||||
if(ENABLE_LTO)
|
if(ENABLE_LTO)
|
||||||
@ -180,8 +188,11 @@ set(Launcher_VERSION_NAME4_COMMA "${Launcher_VERSION_MAJOR},${Launcher_VERSION_M
|
|||||||
# Build platform.
|
# Build platform.
|
||||||
set(Launcher_BUILD_PLATFORM "unknown" CACHE STRING "A short string identifying the platform that this build was built for. Only used to display in the about dialog.")
|
set(Launcher_BUILD_PLATFORM "unknown" CACHE STRING "A short string identifying the platform that this build was built for. Only used to display in the about dialog.")
|
||||||
|
|
||||||
# Channel list URL
|
# Github repo URL with releases for updater
|
||||||
set(Launcher_UPDATER_BASE "" CACHE STRING "Base URL for the updater.")
|
set(Launcher_UPDATER_GITHUB_REPO "https://github.com/PrismLauncher/PrismLauncher" CACHE STRING "Base github URL for the updater.")
|
||||||
|
|
||||||
|
# Name to help updater identify valid artifacts
|
||||||
|
set(Launcher_BUILD_ARTIFACT "" CACHE STRING "Artifact name to help the updater identify valid artifacts.")
|
||||||
|
|
||||||
# The metadata server
|
# The metadata server
|
||||||
set(Launcher_META_URL "https://meta.prismlauncher.org/v1/" CACHE STRING "URL to fetch Launcher's meta files from.")
|
set(Launcher_META_URL "https://meta.prismlauncher.org/v1/" CACHE STRING "URL to fetch Launcher's meta files from.")
|
||||||
@ -208,6 +219,18 @@ set(Launcher_SUBREDDIT_URL "https://prismlauncher.org/reddit" CACHE STRING "URL
|
|||||||
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")
|
||||||
|
|
||||||
|
# Native libraries
|
||||||
|
if(UNIX AND APPLE)
|
||||||
|
set(Launcher_GLFW_LIBRARY_NAME "libglfw.dylib" CACHE STRING "Name of native glfw library")
|
||||||
|
set(Launcher_OPENAL_LIBRARY_NAME "libopenal.dylib" CACHE STRING "Name of native openal library")
|
||||||
|
elseif(UNIX)
|
||||||
|
set(Launcher_GLFW_LIBRARY_NAME "libglfw.so" CACHE STRING "Name of native glfw library")
|
||||||
|
set(Launcher_OPENAL_LIBRARY_NAME "libopenal.so" CACHE STRING "Name of native openal library")
|
||||||
|
elseif(WIN32)
|
||||||
|
set(Launcher_GLFW_LIBRARY_NAME "glfw.dll" CACHE STRING "Name of native glfw library")
|
||||||
|
set(Launcher_OPENAL_LIBRARY_NAME "OpenAL.dll" CACHE STRING "Name of native openal library")
|
||||||
|
endif()
|
||||||
|
|
||||||
# API Keys
|
# API Keys
|
||||||
# NOTE: These API keys are here for convenience. If you rebrand this software or intend to break the terms of service
|
# NOTE: These API keys are here for convenience. If you rebrand this software or intend to break the terms of service
|
||||||
# of these platforms, please change these API keys beforehand.
|
# of these platforms, please change these API keys beforehand.
|
||||||
@ -225,6 +248,11 @@ set(Launcher_MSA_CLIENT_ID "c36a9fb6-4f2a-41ff-90bd-ae7cc92031eb" CACHE STRING "
|
|||||||
# This key was issued specifically for Prism Launcher
|
# This key was issued specifically for Prism Launcher
|
||||||
set(Launcher_CURSEFORGE_API_KEY "$2a$10$wuAJuNZuted3NORVmpgUC.m8sI.pv1tOPKZyBgLFGjxFp/br0lZCC" CACHE STRING "API key for the CurseForge platform")
|
set(Launcher_CURSEFORGE_API_KEY "$2a$10$wuAJuNZuted3NORVmpgUC.m8sI.pv1tOPKZyBgLFGjxFp/br0lZCC" CACHE STRING "API key for the CurseForge platform")
|
||||||
|
|
||||||
|
set(Launcher_COMPILER_NAME ${CMAKE_CXX_COMPILER_ID})
|
||||||
|
set(Launcher_COMPILER_VERSION ${CMAKE_CXX_COMPILER_VERSION})
|
||||||
|
set(Launcher_COMPILER_TARGET_SYSTEM ${CMAKE_SYSTEM_NAME})
|
||||||
|
set(Launcher_COMPILER_TARGET_SYSTEM_VERSION ${CMAKE_SYSTEM_VERSION})
|
||||||
|
set(Launcher_COMPILER_TARGET_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR})
|
||||||
|
|
||||||
#### Check the current Git commit and branch
|
#### Check the current Git commit and branch
|
||||||
include(GetGitRevisionDescription)
|
include(GetGitRevisionDescription)
|
||||||
@ -319,6 +347,11 @@ add_subdirectory(program_info)
|
|||||||
####################################### Install layout #######################################
|
####################################### Install layout #######################################
|
||||||
|
|
||||||
set(Launcher_ENABLE_UPDATER NO)
|
set(Launcher_ENABLE_UPDATER NO)
|
||||||
|
set(Launcher_BUILD_UPDATER NO)
|
||||||
|
|
||||||
|
if (NOT APPLE AND (NOT Launcher_UPDATER_GITHUB_REPO STREQUAL "" AND NOT Launcher_BUILD_ARTIFACT STREQUAL ""))
|
||||||
|
set(Launcher_BUILD_UPDATER YES)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(NOT (UNIX AND APPLE))
|
if(NOT (UNIX AND APPLE))
|
||||||
# Install "portable.txt" if selected component is "portable"
|
# Install "portable.txt" if selected component is "portable"
|
||||||
@ -344,12 +377,12 @@ if(UNIX AND APPLE)
|
|||||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
|
||||||
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}")
|
||||||
set(MACOSX_BUNDLE_ICON_FILE ${Launcher_Name}.icns)
|
set(MACOSX_BUNDLE_ICON_FILE ${Launcher_Name}.icns)
|
||||||
set(MACOSX_BUNDLE_COPYRIGHT "© 2022-2023 ${Launcher_Copyright_Mac}")
|
set(MACOSX_BUNDLE_COPYRIGHT "${Launcher_Copyright_Mac}")
|
||||||
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=" CACHE STRING "Public key for Sparkle update feed")
|
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=" CACHE STRING "Public key for Sparkle update feed")
|
||||||
set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml" CACHE STRING "URL for Sparkle update feed")
|
set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml" CACHE STRING "URL for Sparkle update feed")
|
||||||
|
|
||||||
set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.1.0/Sparkle-2.1.0.tar.xz" CACHE STRING "URL to Sparkle release archive")
|
set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.5.2/Sparkle-2.5.2.tar.xz" CACHE STRING "URL to Sparkle release archive")
|
||||||
set(MACOSX_SPARKLE_SHA256 "bf6ac1caa9f8d321d5784859c88da874f28412f37fb327bc21b7b14c5d61ef94" CACHE STRING "SHA256 checksum for Sparkle release archive")
|
set(MACOSX_SPARKLE_SHA256 "572dd67ae398a466f19f343a449e1890bac1ef74885b4739f68f979a8a89884b" CACHE STRING "SHA256 checksum for Sparkle release archive")
|
||||||
set(MACOSX_SPARKLE_DIR "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
set(MACOSX_SPARKLE_DIR "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
||||||
|
|
||||||
# directories to look for dependencies
|
# directories to look for dependencies
|
||||||
@ -471,11 +504,10 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
if(NOT cmark_FOUND)
|
if(NOT cmark_FOUND)
|
||||||
message(STATUS "Using bundled cmark")
|
message(STATUS "Using bundled cmark")
|
||||||
set(CMARK_STATIC ON CACHE BOOL "Build static libcmark library" FORCE)
|
set(BUILD_TESTING 0)
|
||||||
set(CMARK_SHARED OFF CACHE BOOL "Build shared libcmark library" FORCE)
|
set(BUILD_SHARED_LIBS 0)
|
||||||
set(CMARK_TESTS OFF CACHE BOOL "Build cmark tests and enable testing" FORCE)
|
|
||||||
add_subdirectory(libraries/cmark EXCLUDE_FROM_ALL) # Markdown parser
|
add_subdirectory(libraries/cmark EXCLUDE_FROM_ALL) # Markdown parser
|
||||||
add_library(cmark::cmark ALIAS cmark_static)
|
add_library(cmark::cmark ALIAS cmark)
|
||||||
else()
|
else()
|
||||||
message(STATUS "Using system cmark")
|
message(STATUS "Using system cmark")
|
||||||
endif()
|
endif()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
## Prism Launcher
|
## Prism Launcher
|
||||||
|
|
||||||
Prism Launcher - Minecraft Launcher
|
Prism Launcher - Minecraft Launcher
|
||||||
Copyright (C) 2022-2023 Prism Launcher Contributors
|
Copyright (C) 2022-2024 Prism Launcher Contributors
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -436,7 +436,7 @@
|
|||||||
Copyright (C) 2007 Johann Ollivier Lapeyre <johann@oxygen-icons.org>
|
Copyright (C) 2007 Johann Ollivier Lapeyre <johann@oxygen-icons.org>
|
||||||
Copyright (C) 2007 Kenneth Wimer <kwwii@bootsplash.org>
|
Copyright (C) 2007 Kenneth Wimer <kwwii@bootsplash.org>
|
||||||
Copyright (C) 2007 Riccardo Iaconelli <riccardo@oxygen-icons.org>
|
Copyright (C) 2007 Riccardo Iaconelli <riccardo@oxygen-icons.org>
|
||||||
|
|
||||||
and others
|
and others
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
|
15
README.md
15
README.md
@ -18,11 +18,18 @@
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
- All downloads and instructions for Prism Launcher can be found on our [Website](https://prismlauncher.org/download).
|
- All downloads and instructions for Prism Launcher can be found on our [Website](https://prismlauncher.org/download).
|
||||||
- Last build status can be found in the [GitHub Actions](https://github.com/PrismLauncher/PrismLauncher/actions).
|
- Last build status can be found in the [GitHub Actions](https://github.com/PrismLauncher/PrismLauncher/actions) tab (this also includes the pull requests status).
|
||||||
|
|
||||||
### Development Builds
|
### Development Builds
|
||||||
|
|
||||||
There are development builds available [here](https://github.com/PrismLauncher/PrismLauncher/actions). These have debug information in the binaries, so their file sizes are relatively larger.
|
Please understand that these builds are not intended for most users. There may be bugs, and other instabilities. You have been warned.
|
||||||
|
|
||||||
|
There are development builds available through:
|
||||||
|
|
||||||
|
- [GitHub Actions](https://github.com/PrismLauncher/PrismLauncher/actions) (includes builds from pull requests opened by contribuitors)
|
||||||
|
- [nightly.link](https://nightly.link/PrismLauncher/PrismLauncher/workflows/trigger_builds/develop) (this will always point only to the latest version of develop)
|
||||||
|
|
||||||
|
These have debug information in the binaries, so their file sizes are relatively larger.
|
||||||
|
|
||||||
Prebuilt Development builds are provided for **Linux**, **Windows** and **macOS**.
|
Prebuilt Development builds are provided for **Linux**, **Windows** and **macOS**.
|
||||||
|
|
||||||
@ -30,7 +37,7 @@ For **Arch**, **Debian**, **Fedora**, **OpenSUSE (Tumbleweed)** and **Gentoo**,
|
|||||||
|
|
||||||
[](https://aur.archlinux.org/packages/prismlauncher-git) [](https://aur.archlinux.org/packages/prismlauncher-qt5-git) [](https://mpr.makedeb.org/packages/prismlauncher-git)<br />[](https://copr.fedorainfracloud.org/coprs/g3tchoo/prismlauncher/) [](https://build.opensuse.org/project/show/home:getchoo) [](https://packages.gentoo.org/packages/games-action/prismlauncher)
|
[](https://aur.archlinux.org/packages/prismlauncher-git) [](https://aur.archlinux.org/packages/prismlauncher-qt5-git) [](https://mpr.makedeb.org/packages/prismlauncher-git)<br />[](https://copr.fedorainfracloud.org/coprs/g3tchoo/prismlauncher/) [](https://build.opensuse.org/project/show/home:getchoo) [](https://packages.gentoo.org/packages/games-action/prismlauncher)
|
||||||
|
|
||||||
These packages are also availiable to all the distributions based on the ones mentioned above.
|
These packages are also available to all the distributions based on the ones mentioned above.
|
||||||
|
|
||||||
## Community & Support
|
## Community & Support
|
||||||
|
|
||||||
@ -50,7 +57,7 @@ Feel free to create a GitHub issue if you find a bug or want to suggest a new fe
|
|||||||
|
|
||||||
## Translations
|
## Translations
|
||||||
|
|
||||||
The translation effort for Prism Launcher is hosted on [Weblate](https://hosted.weblate.org/projects/prismlauncher/launcher/) and information about translating Prism Launcher is available at <https://github.com/PrismLauncher/Translations>
|
The translation effort for Prism Launcher is hosted on [Weblate](https://hosted.weblate.org/projects/prismlauncher/launcher/) and information about translating Prism Launcher is available at <https://github.com/PrismLauncher/Translations>.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <qstringliteral.h>
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
@ -59,8 +60,16 @@ Config::Config()
|
|||||||
VERSION_MINOR = @Launcher_VERSION_MINOR@;
|
VERSION_MINOR = @Launcher_VERSION_MINOR@;
|
||||||
|
|
||||||
BUILD_PLATFORM = "@Launcher_BUILD_PLATFORM@";
|
BUILD_PLATFORM = "@Launcher_BUILD_PLATFORM@";
|
||||||
|
BUILD_ARTIFACT = "@Launcher_BUILD_ARTIFACT@";
|
||||||
BUILD_DATE = "@Launcher_BUILD_TIMESTAMP@";
|
BUILD_DATE = "@Launcher_BUILD_TIMESTAMP@";
|
||||||
UPDATER_BASE = "@Launcher_UPDATER_BASE@";
|
UPDATER_GITHUB_REPO = "@Launcher_UPDATER_GITHUB_REPO@";
|
||||||
|
|
||||||
|
COMPILER_NAME = "@Launcher_COMPILER_NAME@";
|
||||||
|
COMPILER_VERSION = "@Launcher_COMPILER_VERSION@";
|
||||||
|
|
||||||
|
COMPILER_TARGET_SYSTEM = "@Launcher_COMPILER_TARGET_SYSTEM@";
|
||||||
|
COMPILER_TARGET_SYSTEM_VERSION = "@Launcher_COMPILER_TARGET_SYSTEM_VERSION@";
|
||||||
|
COMPILER_TARGET_SYSTEM_PROCESSOR = "@Launcher_COMPILER_TARGET_PROCESSOR@";
|
||||||
|
|
||||||
MAC_SPARKLE_PUB_KEY = "@MACOSX_SPARKLE_UPDATE_PUBLIC_KEY@";
|
MAC_SPARKLE_PUB_KEY = "@MACOSX_SPARKLE_UPDATE_PUBLIC_KEY@";
|
||||||
MAC_SPARKLE_APPCAST_URL = "@MACOSX_SPARKLE_UPDATE_FEED_URL@";
|
MAC_SPARKLE_APPCAST_URL = "@MACOSX_SPARKLE_UPDATE_FEED_URL@";
|
||||||
@ -68,6 +77,8 @@ Config::Config()
|
|||||||
if (!MAC_SPARKLE_PUB_KEY.isEmpty() && !MAC_SPARKLE_APPCAST_URL.isEmpty())
|
if (!MAC_SPARKLE_PUB_KEY.isEmpty() && !MAC_SPARKLE_APPCAST_URL.isEmpty())
|
||||||
{
|
{
|
||||||
UPDATER_ENABLED = true;
|
UPDATER_ENABLED = true;
|
||||||
|
} else if(!UPDATER_GITHUB_REPO.isEmpty() && !BUILD_ARTIFACT.isEmpty()) {
|
||||||
|
UPDATER_ENABLED = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
|
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
|
||||||
@ -88,10 +99,7 @@ Config::Config()
|
|||||||
if (GIT_REFSPEC.startsWith("refs/heads/"))
|
if (GIT_REFSPEC.startsWith("refs/heads/"))
|
||||||
{
|
{
|
||||||
VERSION_CHANNEL = GIT_REFSPEC;
|
VERSION_CHANNEL = GIT_REFSPEC;
|
||||||
VERSION_CHANNEL.remove("refs/heads/");
|
VERSION_CHANNEL.remove("refs/heads/");
|
||||||
if(!UPDATER_BASE.isEmpty() && !BUILD_PLATFORM.isEmpty()) {
|
|
||||||
UPDATER_ENABLED = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (!GIT_COMMIT.isEmpty())
|
else if (!GIT_COMMIT.isEmpty())
|
||||||
{
|
{
|
||||||
@ -110,6 +118,9 @@ Config::Config()
|
|||||||
FLAME_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
|
FLAME_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
|
||||||
META_URL = "@Launcher_META_URL@";
|
META_URL = "@Launcher_META_URL@";
|
||||||
|
|
||||||
|
GLFW_LIBRARY_NAME = "@Launcher_GLFW_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@";
|
||||||
MATRIX_URL = "@Launcher_MATRIX_URL@";
|
MATRIX_URL = "@Launcher_MATRIX_URL@";
|
||||||
@ -133,3 +144,16 @@ QString Config::printableVersionString() const
|
|||||||
}
|
}
|
||||||
return vstr;
|
return vstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Config::compilerID() const
|
||||||
|
{
|
||||||
|
if (COMPILER_VERSION.isEmpty())
|
||||||
|
return COMPILER_NAME;
|
||||||
|
return QStringLiteral("%1 - %2").arg(COMPILER_NAME).arg(COMPILER_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Config::systemID() const
|
||||||
|
{
|
||||||
|
return QStringLiteral("%1 %2 %3").arg(COMPILER_TARGET_SYSTEM, COMPILER_TARGET_SYSTEM_VERSION, COMPILER_TARGET_SYSTEM_PROCESSOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -71,11 +71,29 @@ class Config {
|
|||||||
/// 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;
|
||||||
|
|
||||||
|
/// A short string identifying this build's valid artifacts int he updater. For example, "lin64" or "win32".
|
||||||
|
QString BUILD_ARTIFACT;
|
||||||
|
|
||||||
/// A string containing the build timestamp
|
/// A string containing the build timestamp
|
||||||
QString BUILD_DATE;
|
QString BUILD_DATE;
|
||||||
|
|
||||||
|
/// A string identifying the compiler use to build
|
||||||
|
QString COMPILER_NAME;
|
||||||
|
|
||||||
|
/// A string identifying the compiler version used to build
|
||||||
|
QString COMPILER_VERSION;
|
||||||
|
|
||||||
|
/// A string identifying the compiler target system os
|
||||||
|
QString COMPILER_TARGET_SYSTEM;
|
||||||
|
|
||||||
|
/// A String identifying the compiler target system version
|
||||||
|
QString COMPILER_TARGET_SYSTEM_VERSION;
|
||||||
|
|
||||||
|
/// A String identifying the compiler target processor
|
||||||
|
QString COMPILER_TARGET_SYSTEM_PROCESSOR;
|
||||||
|
|
||||||
/// URL for the updater's channel
|
/// URL for the updater's channel
|
||||||
QString UPDATER_BASE;
|
QString UPDATER_GITHUB_REPO;
|
||||||
|
|
||||||
/// The public key used to sign releases for the Sparkle updater appcast
|
/// The public key used to sign releases for the Sparkle updater appcast
|
||||||
QString MAC_SPARKLE_PUB_KEY;
|
QString MAC_SPARKLE_PUB_KEY;
|
||||||
@ -134,6 +152,9 @@ class Config {
|
|||||||
*/
|
*/
|
||||||
QString META_URL;
|
QString META_URL;
|
||||||
|
|
||||||
|
QString GLFW_LIBRARY_NAME;
|
||||||
|
QString OPENAL_LIBRARY_NAME;
|
||||||
|
|
||||||
QString BUG_TRACKER_URL;
|
QString BUG_TRACKER_URL;
|
||||||
QString TRANSLATIONS_URL;
|
QString TRANSLATIONS_URL;
|
||||||
QString MATRIX_URL;
|
QString MATRIX_URL;
|
||||||
@ -172,6 +193,18 @@ class Config {
|
|||||||
* \return The version number in string format (major.minor.revision.build).
|
* \return The version number in string format (major.minor.revision.build).
|
||||||
*/
|
*/
|
||||||
QString printableVersionString() const;
|
QString printableVersionString() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compiler ID String
|
||||||
|
* \return a string of the form "Name - Version" of just "Name" if the version is empty
|
||||||
|
*/
|
||||||
|
QString compilerID() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief System ID String
|
||||||
|
* \return a string of the form "OS Verison Processor"
|
||||||
|
*/
|
||||||
|
QString systemID() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const Config BuildConfig;
|
extern const Config BuildConfig;
|
||||||
|
163
cmake/CompilerWarnings.cmake
Normal file
163
cmake/CompilerWarnings.cmake
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
#
|
||||||
|
# Function to set compiler warnings with reasonable defaults at the project level.
|
||||||
|
# Taken from https://github.com/aminya/project_options/blob/main/src/CompilerWarnings.cmake
|
||||||
|
# under the folowing license:
|
||||||
|
#
|
||||||
|
# MIT License
|
||||||
|
#
|
||||||
|
# Copyright (c) 2022-2100 Amin Yahyaabadi
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in all
|
||||||
|
# copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
include_guard()
|
||||||
|
|
||||||
|
function(_set_project_warnings_add_target_link_option TARGET OPTIONS)
|
||||||
|
target_link_options(${_project_name} INTERFACE ${OPTIONS})
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Set the compiler warnings
|
||||||
|
#
|
||||||
|
# https://clang.llvm.org/docs/DiagnosticsReference.html
|
||||||
|
# https://github.com/lefticus/cppbestpractices/blob/master/02-Use_the_Tools_Available.md
|
||||||
|
function(
|
||||||
|
set_project_warnings
|
||||||
|
_project_name
|
||||||
|
MSVC_WARNINGS
|
||||||
|
CLANG_WARNINGS
|
||||||
|
GCC_WARNINGS
|
||||||
|
)
|
||||||
|
if("${MSVC_WARNINGS}" STREQUAL "")
|
||||||
|
set(MSVC_WARNINGS
|
||||||
|
/W4 # Baseline reasonable warnings
|
||||||
|
/w14242 # 'identifier': conversion from 'type1' to 'type1', possible loss of data
|
||||||
|
/w14254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
|
||||||
|
/w14263 # 'function': member function does not override any base class virtual member function
|
||||||
|
/w14265 # 'classname': class has virtual functions, but destructor is not virtual instances of this class may not
|
||||||
|
# be destructed correctly
|
||||||
|
/w14287 # 'operator': unsigned/negative constant mismatch
|
||||||
|
/we4289 # nonstandard extension used: 'variable': loop control variable declared in the for-loop is used outside
|
||||||
|
# the for-loop scope
|
||||||
|
/w14296 # 'operator': expression is always 'boolean_value'
|
||||||
|
/w14311 # 'variable': pointer truncation from 'type1' to 'type2'
|
||||||
|
/w14545 # expression before comma evaluates to a function which is missing an argument list
|
||||||
|
/w14546 # function call before comma missing argument list
|
||||||
|
/w14547 # 'operator': operator before comma has no effect; expected operator with side-effect
|
||||||
|
/w14549 # 'operator': operator before comma has no effect; did you intend 'operator'?
|
||||||
|
/w14555 # expression has no effect; expected expression with side- effect
|
||||||
|
/w14619 # pragma warning: there is no warning number 'number'
|
||||||
|
/w14640 # Enable warning on thread un-safe static member initialization
|
||||||
|
/w14826 # Conversion from 'type1' to 'type_2' is sign-extended. This may cause unexpected runtime behavior.
|
||||||
|
/w14905 # wide string literal cast to 'LPSTR'
|
||||||
|
/w14906 # string literal cast to 'LPWSTR'
|
||||||
|
/w14928 # illegal copy-initialization; more than one user-defined conversion has been implicitly applied
|
||||||
|
/permissive- # standards conformance mode for MSVC compiler.
|
||||||
|
|
||||||
|
/we4062 # forbid omitting a possible value of an enum in a switch statement
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if("${CLANG_WARNINGS}" STREQUAL "")
|
||||||
|
set(CLANG_WARNINGS
|
||||||
|
-Wall
|
||||||
|
-Wextra # reasonable and standard
|
||||||
|
-Wshadow # warn the user if a variable declaration shadows one from a parent context
|
||||||
|
-Wnon-virtual-dtor # warn the user if a class with virtual functions has a non-virtual destructor. This helps
|
||||||
|
# catch hard to track down memory errors
|
||||||
|
-Wold-style-cast # warn for c-style casts
|
||||||
|
-Wcast-align # warn for potential performance problem casts
|
||||||
|
-Wunused # warn on anything being unused
|
||||||
|
-Woverloaded-virtual # warn if you overload (not override) a virtual function
|
||||||
|
-Wpedantic # warn if non-standard C++ is used
|
||||||
|
-Wconversion # warn on type conversions that may lose data
|
||||||
|
-Wsign-conversion # warn on sign conversions
|
||||||
|
-Wnull-dereference # warn if a null dereference is detected
|
||||||
|
-Wdouble-promotion # warn if float is implicit promoted to double
|
||||||
|
-Wformat=2 # warn on security issues around functions that format output (ie printf)
|
||||||
|
-Wimplicit-fallthrough # warn on statements that fallthrough without an explicit annotation
|
||||||
|
# -Wgnu-zero-variadic-macro-arguments (part of -pedantic) is triggered by every qCDebug() call and therefore results
|
||||||
|
# in a lot of noise. This warning is only notifying us that clang is emulating the GCC behaviour
|
||||||
|
# instead of the exact standard wording so we can safely ignore it
|
||||||
|
-Wno-gnu-zero-variadic-macro-arguments
|
||||||
|
|
||||||
|
-Werror=switch # forbid omitting a possible value of an enum in a switch statement
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if("${GCC_WARNINGS}" STREQUAL "")
|
||||||
|
set(GCC_WARNINGS
|
||||||
|
${CLANG_WARNINGS}
|
||||||
|
-Wmisleading-indentation # warn if indentation implies blocks where blocks do not exist
|
||||||
|
-Wduplicated-cond # warn if if / else chain has duplicated conditions
|
||||||
|
-Wduplicated-branches # warn if if / else branches have duplicated code
|
||||||
|
-Wlogical-op # warn about logical operations being used where bitwise were probably wanted
|
||||||
|
-Wuseless-cast # warn if you perform a cast to the same type
|
||||||
|
|
||||||
|
-Werror=switch # forbid omitting a possible value of an enum in a switch statement
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
set(PROJECT_WARNINGS_CXX ${MSVC_WARNINGS})
|
||||||
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
|
||||||
|
set(PROJECT_WARNINGS_CXX ${CLANG_WARNINGS})
|
||||||
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
|
set(PROJECT_WARNINGS_CXX ${GCC_WARNINGS})
|
||||||
|
else()
|
||||||
|
message(AUTHOR_WARNING "No compiler warnings set for CXX compiler: '${CMAKE_CXX_COMPILER_ID}'")
|
||||||
|
# TODO support Intel compiler
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add C warnings
|
||||||
|
set(PROJECT_WARNINGS_C "${PROJECT_WARNINGS_CXX}")
|
||||||
|
list(
|
||||||
|
REMOVE_ITEM
|
||||||
|
PROJECT_WARNINGS_C
|
||||||
|
-Wnon-virtual-dtor
|
||||||
|
-Wold-style-cast
|
||||||
|
-Woverloaded-virtual
|
||||||
|
-Wuseless-cast
|
||||||
|
-Wextra-semi
|
||||||
|
|
||||||
|
-Werror=switch # forbid omitting a possible value of an enum in a switch statement
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_options(
|
||||||
|
${_project_name}
|
||||||
|
INTERFACE # C++ warnings
|
||||||
|
$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_WARNINGS_CXX}>
|
||||||
|
# C warnings
|
||||||
|
$<$<COMPILE_LANGUAGE:C>:${PROJECT_WARNINGS_C}>
|
||||||
|
)
|
||||||
|
|
||||||
|
# If we are using the compiler as a linker driver pass the warnings to it
|
||||||
|
# (most useful when using LTO or warnings as errors)
|
||||||
|
if(CMAKE_CXX_LINK_EXECUTABLE MATCHES "^<CMAKE_CXX_COMPILER>")
|
||||||
|
_set_project_warnings_add_target_link_option(
|
||||||
|
${_project_name} "$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_WARNINGS_CXX}>"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_C_LINK_EXECUTABLE MATCHES "^<CMAKE_C_COMPILER>")
|
||||||
|
_set_project_warnings_add_target_link_option(
|
||||||
|
${_project_name} "$<$<COMPILE_LANGUAGE:C>:${PROJECT_WARNINGS_C}>"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endfunction()
|
@ -67,5 +67,16 @@
|
|||||||
<string>Alternate</string>
|
<string>Alternate</string>
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>Curseforge</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>curseforge</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
64
flake.lock
generated
64
flake.lock
generated
@ -3,11 +3,11 @@
|
|||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1673956053,
|
"lastModified": 1696426674,
|
||||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||||
"owner": "edolstra",
|
"owner": "edolstra",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-compat",
|
||||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -18,14 +18,16 @@
|
|||||||
},
|
},
|
||||||
"flake-parts": {
|
"flake-parts": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs-lib": "nixpkgs-lib"
|
"nixpkgs-lib": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1690933134,
|
"lastModified": 1706830856,
|
||||||
"narHash": "sha256-ab989mN63fQZBFrkk4Q8bYxQCktuHmBIBqUG1jl6/FQ=",
|
"narHash": "sha256-a0NYyp+h9hlb7ddVz4LUn1vT/PLwqfrWYcHMvFB1xYg=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-parts",
|
"repo": "flake-parts",
|
||||||
"rev": "59cf3f1447cfc75087e7273b04b31e689a8599fb",
|
"rev": "b253292d9c0a5ead9bc98c4e9a26c6312e27d69f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -39,11 +41,11 @@
|
|||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1685518550,
|
"lastModified": 1701680307,
|
||||||
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
|
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
|
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -60,11 +62,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1660459072,
|
"lastModified": 1703887061,
|
||||||
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
|
"narHash": "sha256-gGPa9qWNc6eCXT/+Z5/zMkyYOuRZqeFZBDbopNZQkuY=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "gitignore.nix",
|
"repo": "gitignore.nix",
|
||||||
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
|
"rev": "43e1aa1308018f37118e34d3a9cb4f5e75dc11d5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -76,11 +78,11 @@
|
|||||||
"libnbtplusplus": {
|
"libnbtplusplus": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1690036783,
|
"lastModified": 1699286814,
|
||||||
"narHash": "sha256-A5kTgICnx+Qdq3Fir/bKTfdTt/T1NQP2SC+nhN1ENug=",
|
"narHash": "sha256-yy0q+bky80LtK1GWzz7qpM+aAGrOqLuewbid8WT1ilk=",
|
||||||
"owner": "PrismLauncher",
|
"owner": "PrismLauncher",
|
||||||
"repo": "libnbtplusplus",
|
"repo": "libnbtplusplus",
|
||||||
"rev": "a5e8fd52b8bf4ab5d5bcc042b2a247867589985f",
|
"rev": "23b955121b8217c1c348a9ed2483167a6f3ff4ad",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -91,11 +93,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1691218994,
|
"lastModified": 1708751719,
|
||||||
"narHash": "sha256-46GJ5vLf9H+Oh7Jii2gJI9GATJHGbx2iQpon5nUSFPI=",
|
"narHash": "sha256-0uWOKSpXJXmXswOvDM5Vk3blB74apFB6rNGWV5IjoN0=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "0d2fb29f5071a12d7983319c2c2576be6a130582",
|
"rev": "f63ce824cd2f036216eb5f637dfef31e1a03ee89",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -105,24 +107,6 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs-lib": {
|
|
||||||
"locked": {
|
|
||||||
"dir": "lib",
|
|
||||||
"lastModified": 1690881714,
|
|
||||||
"narHash": "sha256-h/nXluEqdiQHs1oSgkOOWF+j8gcJMWhwnZ9PFabN6q0=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "9e1960bc196baf6881340d53dccb203a951745a2",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"dir": "lib",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pre-commit-hooks": {
|
"pre-commit-hooks": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": [
|
"flake-compat": [
|
||||||
@ -138,11 +122,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1691256628,
|
"lastModified": 1708018599,
|
||||||
"narHash": "sha256-M0YXHemR3zbyhM7PvJa5lzGhWVf6kM/fpZ4cWe/VIhI=",
|
"narHash": "sha256-M+Ng6+SePmA8g06CmUZWi1AjG2tFBX9WCXElBHEKnyM=",
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "pre-commit-hooks.nix",
|
"repo": "pre-commit-hooks.nix",
|
||||||
"rev": "3139c4d1f7732cab89f06492bdd4677b877e3785",
|
"rev": "5df5a70ad7575f6601d91f0efec95dd9bc619431",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
42
flake.nix
42
flake.nix
@ -1,14 +1,24 @@
|
|||||||
{
|
{
|
||||||
description = "A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once (Fork of MultiMC)";
|
description = "A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once (Fork of MultiMC)";
|
||||||
|
|
||||||
|
nixConfig = {
|
||||||
|
extra-substituters = ["https://cache.garnix.io"];
|
||||||
|
extra-trusted-public-keys = ["cache.garnix.io:CTFPyKSLcx5RMJKfLo5EEPUObbA78b0YQ2DTCJXqr9g="];
|
||||||
|
};
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
||||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
flake-parts = {
|
||||||
|
url = "github:hercules-ci/flake-parts";
|
||||||
|
inputs.nixpkgs-lib.follows = "nixpkgs";
|
||||||
|
};
|
||||||
pre-commit-hooks = {
|
pre-commit-hooks = {
|
||||||
url = "github:cachix/pre-commit-hooks.nix";
|
url = "github:cachix/pre-commit-hooks.nix";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs = {
|
||||||
inputs.nixpkgs-stable.follows = "nixpkgs";
|
nixpkgs.follows = "nixpkgs";
|
||||||
inputs.flake-compat.follows = "flake-compat";
|
nixpkgs-stable.follows = "nixpkgs";
|
||||||
|
flake-compat.follows = "flake-compat";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
flake-compat = {
|
flake-compat = {
|
||||||
url = "github:edolstra/flake-compat";
|
url = "github:edolstra/flake-compat";
|
||||||
@ -20,8 +30,24 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = inputs:
|
outputs = {
|
||||||
inputs.flake-parts.lib.mkFlake
|
flake-parts,
|
||||||
{inherit inputs;}
|
pre-commit-hooks,
|
||||||
{imports = [./nix];};
|
...
|
||||||
|
} @ inputs:
|
||||||
|
flake-parts.lib.mkFlake {inherit inputs;} {
|
||||||
|
imports = [
|
||||||
|
pre-commit-hooks.flakeModule
|
||||||
|
|
||||||
|
./nix/dev.nix
|
||||||
|
./nix/distribution.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
systems = [
|
||||||
|
"x86_64-linux"
|
||||||
|
"aarch64-linux"
|
||||||
|
"x86_64-darwin"
|
||||||
|
"aarch64-darwin"
|
||||||
|
];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
id: org.prismlauncher.PrismLauncher
|
id: org.prismlauncher.PrismLauncher
|
||||||
runtime: org.kde.Platform
|
runtime: org.kde.Platform
|
||||||
runtime-version: "5.15-22.08"
|
runtime-version: 5.15-23.08
|
||||||
sdk: org.kde.Sdk
|
sdk: org.kde.Sdk
|
||||||
sdk-extensions:
|
sdk-extensions:
|
||||||
- org.freedesktop.Sdk.Extension.openjdk17
|
- org.freedesktop.Sdk.Extension.openjdk17
|
||||||
@ -104,9 +104,9 @@ modules:
|
|||||||
- install -Dm755 ../data/gamemoderun -t /app/bin
|
- install -Dm755 ../data/gamemoderun -t /app/bin
|
||||||
sources:
|
sources:
|
||||||
- type: archive
|
- type: archive
|
||||||
archive-type: tar-gzip
|
dest-filename: gamemode.tar.gz
|
||||||
url: https://api.github.com/repos/FeralInteractive/gamemode/tarball/1.7
|
url: https://api.github.com/repos/FeralInteractive/gamemode/tarball/1.8.1
|
||||||
sha256: 57ce73ba605d1cf12f8d13725006a895182308d93eba0f69f285648449641803
|
sha256: 969cf85b5ca3944f3e315cd73a0ee9bea4f9c968cd7d485e9f4745bc1e679c4e
|
||||||
x-checker-data:
|
x-checker-data:
|
||||||
type: json
|
type: json
|
||||||
url: https://api.github.com/repos/FeralInteractive/gamemode/releases/latest
|
url: https://api.github.com/repos/FeralInteractive/gamemode/releases/latest
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 45094ca570be383d06df729b6972830ec63bd3df
|
Subproject commit f2b0c16a2a217a1822ce5a6538ba8f755ed1dd32
|
@ -1,5 +1,6 @@
|
|||||||
builds:
|
builds:
|
||||||
exclude: []
|
exclude:
|
||||||
|
- "*.x86_64-darwin.*"
|
||||||
include:
|
include:
|
||||||
- "checks.x86_64-linux.*"
|
- "checks.x86_64-linux.*"
|
||||||
- "devShells.*.*"
|
- "devShells.*.*"
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
* Copyright (C) 2022 Tayou <git@tayou.org>
|
* Copyright (C) 2022 Tayou <git@tayou.org>
|
||||||
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
|
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
|
||||||
* Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com>
|
* Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com>
|
||||||
* Copyright (C) 2023 seth <getchoo at tuta dot io>
|
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -59,6 +58,7 @@
|
|||||||
#include "ui/pages/global/APIPage.h"
|
#include "ui/pages/global/APIPage.h"
|
||||||
#include "ui/pages/global/AccountListPage.h"
|
#include "ui/pages/global/AccountListPage.h"
|
||||||
#include "ui/pages/global/CustomCommandsPage.h"
|
#include "ui/pages/global/CustomCommandsPage.h"
|
||||||
|
#include "ui/pages/global/EnvironmentVariablesPage.h"
|
||||||
#include "ui/pages/global/ExternalToolsPage.h"
|
#include "ui/pages/global/ExternalToolsPage.h"
|
||||||
#include "ui/pages/global/JavaPage.h"
|
#include "ui/pages/global/JavaPage.h"
|
||||||
#include "ui/pages/global/LanguagePage.h"
|
#include "ui/pages/global/LanguagePage.h"
|
||||||
@ -123,6 +123,7 @@
|
|||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
#include <LocalPeer.h>
|
#include <LocalPeer.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include <sys.h>
|
#include <sys.h>
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
@ -131,16 +132,25 @@
|
|||||||
#include "gamemode_client.h"
|
#include "gamemode_client.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_MAC) && defined(SPARKLE_ENABLED)
|
#if defined(Q_OS_LINUX)
|
||||||
|
#include <sys/statvfs.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(Q_OS_MAC)
|
||||||
|
#if defined(SPARKLE_ENABLED)
|
||||||
#include "updater/MacSparkleUpdater.h"
|
#include "updater/MacSparkleUpdater.h"
|
||||||
#endif
|
#endif
|
||||||
|
#else
|
||||||
|
#include "updater/PrismExternalUpdater.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#include "WindowsConsole.h"
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define STRINGIFY(x) #x
|
#define STRINGIFY(x) #x
|
||||||
@ -169,25 +179,39 @@ void appDebugOutput(QtMsgType type, const QMessageLogContext& context, const QSt
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
std::tuple<QDateTime, QString, QString, QString, QString> read_lock_File(const QString& path)
|
||||||
|
{
|
||||||
|
auto contents = QString(FS::read(path));
|
||||||
|
auto lines = contents.split('\n');
|
||||||
|
|
||||||
|
QDateTime timestamp;
|
||||||
|
QString from, to, target, data_path;
|
||||||
|
for (auto line : lines) {
|
||||||
|
auto index = line.indexOf("=");
|
||||||
|
if (index < 0)
|
||||||
|
continue;
|
||||||
|
auto left = line.left(index);
|
||||||
|
auto right = line.mid(index + 1);
|
||||||
|
if (left.toLower() == "timestamp") {
|
||||||
|
timestamp = QDateTime::fromString(right, Qt::ISODate);
|
||||||
|
} else if (left.toLower() == "from") {
|
||||||
|
from = right;
|
||||||
|
} else if (left.toLower() == "to") {
|
||||||
|
to = right;
|
||||||
|
} else if (left.toLower() == "target") {
|
||||||
|
target = right;
|
||||||
|
} else if (left.toLower() == "data_path") {
|
||||||
|
data_path = right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::make_tuple(timestamp, from, to, target, data_path);
|
||||||
|
}
|
||||||
|
|
||||||
Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
{
|
{
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
// attach the parent console
|
// attach the parent console if stdout not already captured
|
||||||
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
if (AttachWindowsConsole()) {
|
||||||
// if attach succeeds, reopen and sync all the i/o
|
|
||||||
if (freopen("CON", "w", stdout)) {
|
|
||||||
std::cout.sync_with_stdio();
|
|
||||||
}
|
|
||||||
if (freopen("CON", "w", stderr)) {
|
|
||||||
std::cerr.sync_with_stdio();
|
|
||||||
}
|
|
||||||
if (freopen("CON", "r", stdin)) {
|
|
||||||
std::cin.sync_with_stdio();
|
|
||||||
}
|
|
||||||
auto out = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
DWORD written;
|
|
||||||
const char* endline = "\n";
|
|
||||||
WriteConsole(out, endline, strlen(endline), &written, NULL);
|
|
||||||
consoleAttached = true;
|
consoleAttached = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -212,8 +236,11 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
{ { "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" },
|
||||||
{ { "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 from specified zip (local path or URL)", "file" },
|
{ { "I", "import" }, "Import instance or resource from specified local path or URL", "url" },
|
||||||
{ "show", "Opens the window for the specified instance (by instance ID)", "show" } });
|
{ "show", "Opens the window for the specified instance (by instance ID)", "show" } });
|
||||||
|
// Has to be positional for some OS to handle that properly
|
||||||
|
parser.addPositionalArgument("URL", "Import the resource(s) at the given URL(s) (same as -I / --import)", "[URL...]");
|
||||||
|
|
||||||
parser.addHelpOption();
|
parser.addHelpOption();
|
||||||
parser.addVersionOption();
|
parser.addVersionOption();
|
||||||
|
|
||||||
@ -226,13 +253,13 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
m_instanceIdToShowWindowOf = parser.value("show");
|
m_instanceIdToShowWindowOf = parser.value("show");
|
||||||
|
|
||||||
for (auto zip_path : parser.values("import")) {
|
for (auto url : parser.values("import")) {
|
||||||
m_zipsToImport.append(QUrl::fromLocalFile(QFileInfo(zip_path).absoluteFilePath()));
|
m_urlsToImport.append(normalizeImportUrl(url));
|
||||||
}
|
}
|
||||||
|
|
||||||
// treat unspecified positional arguments as import urls
|
// treat unspecified positional arguments as import urls
|
||||||
for (auto zip_path : parser.positionalArguments()) {
|
for (auto url : parser.positionalArguments()) {
|
||||||
m_zipsToImport.append(QUrl::fromLocalFile(QFileInfo(zip_path).absoluteFilePath()));
|
m_urlsToImport.append(normalizeImportUrl(url));
|
||||||
}
|
}
|
||||||
|
|
||||||
// error if --launch is missing with --server or --profile
|
// error if --launch is missing with --server or --profile
|
||||||
@ -312,6 +339,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
.arg(dataPath));
|
.arg(dataPath));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
m_dataPath = dataPath;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Establish the mechanism for communication with an already running PrismLauncher that uses the same data path.
|
* Establish the mechanism for communication with an already running PrismLauncher that uses the same data path.
|
||||||
@ -331,11 +359,11 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
activate.command = "activate";
|
activate.command = "activate";
|
||||||
m_peerInstance->sendMessage(activate.serialize(), timeout);
|
m_peerInstance->sendMessage(activate.serialize(), timeout);
|
||||||
|
|
||||||
if (!m_zipsToImport.isEmpty()) {
|
if (!m_urlsToImport.isEmpty()) {
|
||||||
for (auto zip_url : m_zipsToImport) {
|
for (auto url : m_urlsToImport) {
|
||||||
ApplicationMessage import;
|
ApplicationMessage import;
|
||||||
import.command = "import";
|
import.command = "import";
|
||||||
import.args.insert("path", zip_url.toString());
|
import.args.insert("url", url.toString());
|
||||||
m_peerInstance->sendMessage(import.serialize(), timeout);
|
m_peerInstance->sendMessage(import.serialize(), timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -466,11 +494,15 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
qDebug() << BuildConfig.LAUNCHER_DISPLAYNAME << ", (c) 2013-2021 " << BuildConfig.LAUNCHER_COPYRIGHT;
|
qDebug() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME + ", " + QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", "));
|
||||||
qDebug() << "Version : " << BuildConfig.printableVersionString();
|
qDebug() << "Version : " << BuildConfig.printableVersionString();
|
||||||
qDebug() << "Platform : " << BuildConfig.BUILD_PLATFORM;
|
qDebug() << "Platform : " << BuildConfig.BUILD_PLATFORM;
|
||||||
qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT;
|
qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT;
|
||||||
qDebug() << "Git refspec : " << BuildConfig.GIT_REFSPEC;
|
qDebug() << "Git refspec : " << BuildConfig.GIT_REFSPEC;
|
||||||
|
qDebug() << "Compiled for : " << BuildConfig.systemID();
|
||||||
|
qDebug() << "Compiled by : " << BuildConfig.compilerID();
|
||||||
|
qDebug() << "Build Artifact : " << BuildConfig.BUILD_ARTIFACT;
|
||||||
|
qDebug() << "Updates Enabled : " << (updaterEnabled() ? "Yes" : "No");
|
||||||
if (adjustedBy.size()) {
|
if (adjustedBy.size()) {
|
||||||
qDebug() << "Work dir before adjustment : " << origcwdPath;
|
qDebug() << "Work dir before adjustment : " << origcwdPath;
|
||||||
qDebug() << "Work dir after adjustment : " << QDir::currentPath();
|
qDebug() << "Work dir after adjustment : " << QDir::currentPath();
|
||||||
@ -510,7 +542,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
m_settings.reset(new INISettingsObject({ BuildConfig.LAUNCHER_CONFIGFILE, "polymc.cfg", "multimc.cfg" }, this));
|
m_settings.reset(new INISettingsObject({ BuildConfig.LAUNCHER_CONFIGFILE, "polymc.cfg", "multimc.cfg" }, this));
|
||||||
|
|
||||||
// Theming
|
// Theming
|
||||||
m_settings->registerSetting("IconTheme", QString("pe_colored"));
|
m_settings->registerSetting("IconTheme", QString());
|
||||||
m_settings->registerSetting("ApplicationTheme", QString());
|
m_settings->registerSetting("ApplicationTheme", QString());
|
||||||
m_settings->registerSetting("BackgroundCat", QString("kitteh"));
|
m_settings->registerSetting("BackgroundCat", QString("kitteh"));
|
||||||
|
|
||||||
@ -519,6 +551,9 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
m_settings->registerSetting("MenuBarInsteadOfToolBar", false);
|
m_settings->registerSetting("MenuBarInsteadOfToolBar", false);
|
||||||
|
|
||||||
|
m_settings->registerSetting("NumberOfConcurrentTasks", 10);
|
||||||
|
m_settings->registerSetting("NumberOfConcurrentDownloads", 6);
|
||||||
|
|
||||||
QString defaultMonospace;
|
QString defaultMonospace;
|
||||||
int defaultSize = 11;
|
int defaultSize = 11;
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
@ -595,25 +630,30 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
m_settings->registerSetting("IgnoreJavaCompatibility", false);
|
m_settings->registerSetting("IgnoreJavaCompatibility", false);
|
||||||
m_settings->registerSetting("IgnoreJavaWizard", false);
|
m_settings->registerSetting("IgnoreJavaWizard", false);
|
||||||
|
|
||||||
// Mod loader settings
|
// Legacy settings
|
||||||
m_settings->registerSetting("DisableQuiltBeacon", false);
|
m_settings->registerSetting("OnlineFixes", false);
|
||||||
|
|
||||||
// Native library workarounds
|
// Native library workarounds
|
||||||
m_settings->registerSetting("UseNativeOpenAL", false);
|
m_settings->registerSetting("UseNativeOpenAL", false);
|
||||||
|
m_settings->registerSetting("CustomOpenALPath", "");
|
||||||
m_settings->registerSetting("UseNativeGLFW", false);
|
m_settings->registerSetting("UseNativeGLFW", false);
|
||||||
|
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);
|
||||||
m_settings->registerSetting("ShowGlobalGameTime", true);
|
m_settings->registerSetting("ShowGlobalGameTime", true);
|
||||||
m_settings->registerSetting("RecordGameTime", true);
|
m_settings->registerSetting("RecordGameTime", true);
|
||||||
|
m_settings->registerSetting("ShowGameTimeWithoutDays", false);
|
||||||
|
|
||||||
// Minecraft mods
|
// Minecraft mods
|
||||||
m_settings->registerSetting("ModMetadataDisabled", false);
|
m_settings->registerSetting("ModMetadataDisabled", false);
|
||||||
|
m_settings->registerSetting("ModDependenciesDisabled", false);
|
||||||
|
|
||||||
// Minecraft offline player name
|
// Minecraft offline player name
|
||||||
m_settings->registerSetting("LastOfflinePlayerName", "");
|
m_settings->registerSetting("LastOfflinePlayerName", "");
|
||||||
@ -627,6 +667,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);
|
||||||
|
|
||||||
@ -690,6 +733,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
m_settings->registerSetting("CloseAfterLaunch", false);
|
m_settings->registerSetting("CloseAfterLaunch", false);
|
||||||
m_settings->registerSetting("QuitAfterGameStop", false);
|
m_settings->registerSetting("QuitAfterGameStop", false);
|
||||||
|
|
||||||
|
m_settings->registerSetting("Env", QVariant(QMap<QString, QVariant>()));
|
||||||
|
|
||||||
// Custom Microsoft Authentication Client ID
|
// Custom Microsoft Authentication Client ID
|
||||||
m_settings->registerSetting("MSAClientIDOverride", "");
|
m_settings->registerSetting("MSAClientIDOverride", "");
|
||||||
|
|
||||||
@ -707,6 +752,9 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
m_settings->registerSetting("ModrinthToken", "");
|
m_settings->registerSetting("ModrinthToken", "");
|
||||||
m_settings->registerSetting("UserAgentOverride", "");
|
m_settings->registerSetting("UserAgentOverride", "");
|
||||||
|
|
||||||
|
// FTBApp instances
|
||||||
|
m_settings->registerSetting("FTBAppInstancesPath", "");
|
||||||
|
|
||||||
// Init page provider
|
// Init page provider
|
||||||
{
|
{
|
||||||
m_globalSettingsProvider = std::make_shared<GenericPageProvider>(tr("Settings"));
|
m_globalSettingsProvider = std::make_shared<GenericPageProvider>(tr("Settings"));
|
||||||
@ -715,6 +763,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
m_globalSettingsProvider->addPage<JavaPage>();
|
m_globalSettingsProvider->addPage<JavaPage>();
|
||||||
m_globalSettingsProvider->addPage<LanguagePage>();
|
m_globalSettingsProvider->addPage<LanguagePage>();
|
||||||
m_globalSettingsProvider->addPage<CustomCommandsPage>();
|
m_globalSettingsProvider->addPage<CustomCommandsPage>();
|
||||||
|
m_globalSettingsProvider->addPage<EnvironmentVariablesPage>();
|
||||||
m_globalSettingsProvider->addPage<ProxyPage>();
|
m_globalSettingsProvider->addPage<ProxyPage>();
|
||||||
m_globalSettingsProvider->addPage<ExternalToolsPage>();
|
m_globalSettingsProvider->addPage<ExternalToolsPage>();
|
||||||
m_globalSettingsProvider->addPage<AccountListPage>();
|
m_globalSettingsProvider->addPage<AccountListPage>();
|
||||||
@ -751,15 +800,6 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
qDebug() << "<> Translations loaded.";
|
qDebug() << "<> Translations loaded.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize the updater
|
|
||||||
if (BuildConfig.UPDATER_ENABLED) {
|
|
||||||
qDebug() << "Initializing updater";
|
|
||||||
#if defined(Q_OS_MAC) && defined(SPARKLE_ENABLED)
|
|
||||||
m_updater.reset(new MacSparkleUpdater());
|
|
||||||
#endif
|
|
||||||
qDebug() << "<> Updater started.";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Instance icons
|
// Instance icons
|
||||||
{
|
{
|
||||||
auto setting = APPLICATION->settings()->getSetting("IconsDir");
|
auto setting = APPLICATION->settings()->getSetting("IconsDir");
|
||||||
@ -772,7 +812,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Themes
|
// Themes
|
||||||
m_themeManager = std::make_unique<ThemeManager>(m_mainWindow);
|
m_themeManager = std::make_unique<ThemeManager>();
|
||||||
|
|
||||||
// initialize and load all instances
|
// initialize and load all instances
|
||||||
{
|
{
|
||||||
@ -858,14 +898,147 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
applyCurrentlySelectedTheme(true);
|
|
||||||
|
|
||||||
updateCapabilities();
|
updateCapabilities();
|
||||||
|
|
||||||
|
detectLibraries();
|
||||||
|
|
||||||
|
// check update locks
|
||||||
|
{
|
||||||
|
auto update_log_path = FS::PathCombine(m_dataPath, "logs", "prism_launcher_update.log");
|
||||||
|
|
||||||
|
auto update_lock = QFileInfo(FS::PathCombine(m_dataPath, ".prism_launcher_update.lock"));
|
||||||
|
if (update_lock.exists()) {
|
||||||
|
auto [timestamp, from, to, target, data_path] = read_lock_File(update_lock.absoluteFilePath());
|
||||||
|
auto infoMsg = tr("This installation has a update lock file present at: %1\n"
|
||||||
|
"\n"
|
||||||
|
"Timestamp: %2\n"
|
||||||
|
"Updating from version %3 to %4\n"
|
||||||
|
"Target install path: %5\n"
|
||||||
|
"Data Path: %6"
|
||||||
|
"\n"
|
||||||
|
"This likely means that a update attempt failed. Please ensure your installation is in working order before "
|
||||||
|
"proceeding.\n"
|
||||||
|
"Check the Prism Launcher updater log at: \n"
|
||||||
|
"%7\n"
|
||||||
|
"for details on the last update attempt.\n"
|
||||||
|
"\n"
|
||||||
|
"To delete this lock and proceed select \"Ignore\" below.")
|
||||||
|
.arg(update_lock.absoluteFilePath())
|
||||||
|
.arg(timestamp.toString(Qt::ISODate), from, to, target, data_path)
|
||||||
|
.arg(update_log_path);
|
||||||
|
auto msgBox = QMessageBox(QMessageBox::Warning, tr("Update In Progress"), infoMsg, QMessageBox::Ignore | QMessageBox::Abort);
|
||||||
|
msgBox.setDefaultButton(QMessageBox::Abort);
|
||||||
|
msgBox.setModal(true);
|
||||||
|
msgBox.setDetailedText(FS::read(update_log_path));
|
||||||
|
msgBox.setMinimumWidth(460);
|
||||||
|
msgBox.adjustSize();
|
||||||
|
auto res = msgBox.exec();
|
||||||
|
switch (res) {
|
||||||
|
case QMessageBox::Ignore: {
|
||||||
|
FS::deletePath(update_lock.absoluteFilePath());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QMessageBox::Abort:
|
||||||
|
[[fallthrough]];
|
||||||
|
default: {
|
||||||
|
qDebug() << "Exiting because update lockfile is present";
|
||||||
|
QMetaObject::invokeMethod(
|
||||||
|
this, []() { exit(1); }, Qt::QueuedConnection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto update_fail_marker = QFileInfo(FS::PathCombine(m_dataPath, ".prism_launcher_update.fail"));
|
||||||
|
if (update_fail_marker.exists()) {
|
||||||
|
auto infoMsg = tr("An update attempt failed\n"
|
||||||
|
"\n"
|
||||||
|
"Please ensure your installation is in working order before "
|
||||||
|
"proceeding.\n"
|
||||||
|
"Check the Prism Launcher updater log at: \n"
|
||||||
|
"%1\n"
|
||||||
|
"for details on the last update attempt.")
|
||||||
|
.arg(update_log_path);
|
||||||
|
auto msgBox = QMessageBox(QMessageBox::Warning, tr("Update Failed"), infoMsg, QMessageBox::Ignore | QMessageBox::Abort);
|
||||||
|
msgBox.setDefaultButton(QMessageBox::Abort);
|
||||||
|
msgBox.setModal(true);
|
||||||
|
msgBox.setDetailedText(FS::read(update_log_path));
|
||||||
|
msgBox.setMinimumWidth(460);
|
||||||
|
msgBox.adjustSize();
|
||||||
|
auto res = msgBox.exec();
|
||||||
|
switch (res) {
|
||||||
|
case QMessageBox::Ignore: {
|
||||||
|
FS::deletePath(update_fail_marker.absoluteFilePath());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QMessageBox::Abort:
|
||||||
|
[[fallthrough]];
|
||||||
|
default: {
|
||||||
|
qDebug() << "Exiting because update lockfile is present";
|
||||||
|
QMetaObject::invokeMethod(
|
||||||
|
this, []() { exit(1); }, Qt::QueuedConnection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto update_success_marker = QFileInfo(FS::PathCombine(m_dataPath, ".prism_launcher_update.success"));
|
||||||
|
if (update_success_marker.exists()) {
|
||||||
|
auto infoMsg = tr("Update succeeded\n"
|
||||||
|
"\n"
|
||||||
|
"You are now running %1 .\n"
|
||||||
|
"Check the Prism Launcher updater log at: \n"
|
||||||
|
"%1\n"
|
||||||
|
"for details.")
|
||||||
|
.arg(BuildConfig.printableVersionString())
|
||||||
|
.arg(update_log_path);
|
||||||
|
auto msgBox = new QMessageBox(QMessageBox::Information, tr("Update Succeeded"), infoMsg, QMessageBox::Ok);
|
||||||
|
msgBox->setDefaultButton(QMessageBox::Ok);
|
||||||
|
msgBox->setDetailedText(FS::read(update_log_path));
|
||||||
|
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
msgBox->setMinimumWidth(460);
|
||||||
|
msgBox->adjustSize();
|
||||||
|
msgBox->open();
|
||||||
|
FS::deletePath(update_success_marker.absoluteFilePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// notify user if /tmp is mounted with `noexec` (#1693)
|
||||||
|
{
|
||||||
|
bool is_tmp_noexec = false;
|
||||||
|
|
||||||
|
#if defined(Q_OS_LINUX)
|
||||||
|
|
||||||
|
struct statvfs tmp_stat;
|
||||||
|
statvfs("/tmp", &tmp_stat);
|
||||||
|
is_tmp_noexec = tmp_stat.f_flag & ST_NOEXEC;
|
||||||
|
|
||||||
|
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||||
|
|
||||||
|
struct statfs tmp_stat;
|
||||||
|
statfs("/tmp", &tmp_stat);
|
||||||
|
is_tmp_noexec = tmp_stat.f_flags & MNT_NOEXEC;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (is_tmp_noexec) {
|
||||||
|
auto infoMsg =
|
||||||
|
tr("Your /tmp directory is currently mounted with the 'noexec' flag enabled.\n"
|
||||||
|
"Some versions of Minecraft may not launch.\n");
|
||||||
|
auto msgBox = new QMessageBox(QMessageBox::Information, tr("Incompatible system configuration"), infoMsg, QMessageBox::Ok);
|
||||||
|
msgBox->setDefaultButton(QMessageBox::Ok);
|
||||||
|
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
msgBox->setMinimumWidth(460);
|
||||||
|
msgBox->adjustSize();
|
||||||
|
msgBox->open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (createSetupWizard()) {
|
if (createSetupWizard()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_themeManager->applyCurrentlySelectedTheme(true);
|
||||||
performMainStartupAction();
|
performMainStartupAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -891,10 +1064,20 @@ bool Application::createSetupWizard()
|
|||||||
}();
|
}();
|
||||||
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 themeInterventionRequired = settings()->get("ApplicationTheme") == "";
|
bool validWidgets = m_themeManager->isValidApplicationTheme(settings()->get("ApplicationTheme").toString());
|
||||||
|
bool validIcons = m_themeManager->isValidIconTheme(settings()->get("IconTheme").toString());
|
||||||
|
bool themeInterventionRequired = !validWidgets || !validIcons;
|
||||||
bool wizardRequired = javaRequired || languageRequired || pasteInterventionRequired || themeInterventionRequired;
|
bool wizardRequired = javaRequired || languageRequired || pasteInterventionRequired || themeInterventionRequired;
|
||||||
|
|
||||||
if (wizardRequired) {
|
if (wizardRequired) {
|
||||||
|
// set default theme after going into theme wizard
|
||||||
|
if (!validIcons)
|
||||||
|
settings()->set("IconTheme", QString("pe_colored"));
|
||||||
|
if (!validWidgets)
|
||||||
|
settings()->set("ApplicationTheme", QString("system"));
|
||||||
|
|
||||||
|
m_themeManager->applyCurrentlySelectedTheme(true);
|
||||||
|
|
||||||
m_setupWizard = new SetupWizard(nullptr);
|
m_setupWizard = new SetupWizard(nullptr);
|
||||||
if (languageRequired) {
|
if (languageRequired) {
|
||||||
m_setupWizard->addPage(new LanguageWizardPage(m_setupWizard));
|
m_setupWizard->addPage(new LanguageWizardPage(m_setupWizard));
|
||||||
@ -909,9 +1092,9 @@ bool Application::createSetupWizard()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (themeInterventionRequired) {
|
if (themeInterventionRequired) {
|
||||||
settings()->set("ApplicationTheme", QString("system")); // set default theme after going into theme wizard
|
|
||||||
m_setupWizard->addPage(new ThemeWizardPage(m_setupWizard));
|
m_setupWizard->addPage(new ThemeWizardPage(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 true;
|
||||||
@ -919,6 +1102,26 @@ bool Application::createSetupWizard()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Application::updaterEnabled()
|
||||||
|
{
|
||||||
|
#if defined(Q_OS_MAC)
|
||||||
|
return BuildConfig.UPDATER_ENABLED;
|
||||||
|
#else
|
||||||
|
return BuildConfig.UPDATER_ENABLED && QFileInfo(FS::PathCombine(m_rootPath, updaterBinaryName())).isFile();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Application::updaterBinaryName()
|
||||||
|
{
|
||||||
|
auto exe_name = QStringLiteral("%1_updater").arg(BuildConfig.LAUNCHER_APP_BINARY_NAME);
|
||||||
|
#if defined Q_OS_WIN32
|
||||||
|
exe_name.append(".exe");
|
||||||
|
#else
|
||||||
|
exe_name.prepend("bin/");
|
||||||
|
#endif
|
||||||
|
return exe_name;
|
||||||
|
}
|
||||||
|
|
||||||
bool Application::event(QEvent* event)
|
bool Application::event(QEvent* event)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
@ -970,7 +1173,7 @@ void Application::performMainStartupAction()
|
|||||||
qDebug() << " Launching with account" << m_profileToUse;
|
qDebug() << " Launching with account" << m_profileToUse;
|
||||||
}
|
}
|
||||||
|
|
||||||
launch(inst, true, false, nullptr, serverToJoin, accountToUse);
|
launch(inst, true, false, serverToJoin, accountToUse);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -987,9 +1190,23 @@ void Application::performMainStartupAction()
|
|||||||
showMainWindow(false);
|
showMainWindow(false);
|
||||||
qDebug() << "<> Main window shown.";
|
qDebug() << "<> Main window shown.";
|
||||||
}
|
}
|
||||||
if (!m_zipsToImport.isEmpty()) {
|
|
||||||
qDebug() << "<> Importing from zip:" << m_zipsToImport;
|
// initialize the updater
|
||||||
m_mainWindow->processURLs(m_zipsToImport);
|
if (updaterEnabled()) {
|
||||||
|
qDebug() << "Initializing updater";
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
#if defined(SPARKLE_ENABLED)
|
||||||
|
m_updater.reset(new MacSparkleUpdater());
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
m_updater.reset(new PrismExternalUpdater(m_mainWindow, m_rootPath, m_dataPath));
|
||||||
|
#endif
|
||||||
|
qDebug() << "<> Updater started.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_urlsToImport.isEmpty()) {
|
||||||
|
qDebug() << "<> Importing from url:" << m_urlsToImport;
|
||||||
|
m_mainWindow->processURLs(m_urlsToImport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1031,12 +1248,12 @@ void Application::messageReceived(const QByteArray& message)
|
|||||||
if (command == "activate") {
|
if (command == "activate") {
|
||||||
showMainWindow();
|
showMainWindow();
|
||||||
} else if (command == "import") {
|
} else if (command == "import") {
|
||||||
QString path = received.args["path"];
|
QString url = received.args["url"];
|
||||||
if (path.isEmpty()) {
|
if (url.isEmpty()) {
|
||||||
qWarning() << "Received" << command << "message without a zip path/URL.";
|
qWarning() << "Received" << command << "message without a zip path/URL.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_mainWindow->processURLs({ QUrl::fromLocalFile(QFileInfo(path).absoluteFilePath()) });
|
m_mainWindow->processURLs({ normalizeImportUrl(url) });
|
||||||
} 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"];
|
||||||
@ -1069,7 +1286,7 @@ void Application::messageReceived(const QByteArray& message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
launch(instance, true, false, nullptr, serverObject, accountObject);
|
launch(instance, true, false, serverObject, accountObject);
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Received invalid message" << message;
|
qWarning() << "Received invalid message" << message;
|
||||||
}
|
}
|
||||||
@ -1088,26 +1305,6 @@ std::shared_ptr<JavaInstallList> Application::javalist()
|
|||||||
return m_javalist;
|
return m_javalist;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<ITheme*> Application::getValidApplicationThemes()
|
|
||||||
{
|
|
||||||
return m_themeManager->getValidApplicationThemes();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::applyCurrentlySelectedTheme(bool initial)
|
|
||||||
{
|
|
||||||
m_themeManager->applyCurrentlySelectedTheme(initial);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::setApplicationTheme(const QString& name)
|
|
||||||
{
|
|
||||||
m_themeManager->setApplicationTheme(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::setIconTheme(const QString& name)
|
|
||||||
{
|
|
||||||
m_themeManager->setIconTheme(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
QIcon Application::getThemedIcon(const QString& name)
|
QIcon Application::getThemedIcon(const QString& name)
|
||||||
{
|
{
|
||||||
if (name == "logo") {
|
if (name == "logo") {
|
||||||
@ -1116,16 +1313,6 @@ QIcon Application::getThemedIcon(const QString& name)
|
|||||||
return QIcon::fromTheme(name);
|
return QIcon::fromTheme(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<CatPack*> Application::getValidCatPacks()
|
|
||||||
{
|
|
||||||
return m_themeManager->getValidCatPacks();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Application::getCatPack(QString catName)
|
|
||||||
{
|
|
||||||
return m_themeManager->getCatPack(catName);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Application::openJsonEditor(const QString& filename)
|
bool Application::openJsonEditor(const QString& filename)
|
||||||
{
|
{
|
||||||
const QString file = QDir::current().absoluteFilePath(filename);
|
const QString file = QDir::current().absoluteFilePath(filename);
|
||||||
@ -1140,7 +1327,6 @@ bool Application::openJsonEditor(const QString& filename)
|
|||||||
bool Application::launch(InstancePtr instance,
|
bool Application::launch(InstancePtr instance,
|
||||||
bool online,
|
bool online,
|
||||||
bool demo,
|
bool demo,
|
||||||
BaseProfilerFactory* profiler,
|
|
||||||
MinecraftServerTargetPtr serverToJoin,
|
MinecraftServerTargetPtr serverToJoin,
|
||||||
MinecraftAccountPtr accountToUse)
|
MinecraftAccountPtr accountToUse)
|
||||||
{
|
{
|
||||||
@ -1148,7 +1334,7 @@ bool Application::launch(InstancePtr instance,
|
|||||||
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.";
|
||||||
} else if (instance->canLaunch()) {
|
} else if (instance->canLaunch()) {
|
||||||
auto& extras = m_instanceExtras[instance->id()];
|
auto& extras = m_instanceExtras[instance->id()];
|
||||||
auto& window = extras.window;
|
auto window = extras.window;
|
||||||
if (window) {
|
if (window) {
|
||||||
if (!window->saveAll()) {
|
if (!window->saveAll()) {
|
||||||
return false;
|
return false;
|
||||||
@ -1159,7 +1345,7 @@ bool Application::launch(InstancePtr instance,
|
|||||||
controller->setInstance(instance);
|
controller->setInstance(instance);
|
||||||
controller->setOnline(online);
|
controller->setOnline(online);
|
||||||
controller->setDemo(demo);
|
controller->setDemo(demo);
|
||||||
controller->setProfiler(profiler);
|
controller->setProfiler(profilers().value(instance->settings()->get("Profiler").toString(), nullptr).get());
|
||||||
controller->setServerToJoin(serverToJoin);
|
controller->setServerToJoin(serverToJoin);
|
||||||
controller->setAccountToUse(accountToUse);
|
controller->setAccountToUse(accountToUse);
|
||||||
if (window) {
|
if (window) {
|
||||||
@ -1331,6 +1517,17 @@ InstanceWindow* Application::showInstanceWindow(InstancePtr instance, QString pa
|
|||||||
auto& window = extras.window;
|
auto& window = extras.window;
|
||||||
|
|
||||||
if (window) {
|
if (window) {
|
||||||
|
// If the window is minimized on macOS or Windows, activate and bring it up
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
if (window->isMinimized()) {
|
||||||
|
window->setWindowState(window->windowState() & ~Qt::WindowMinimized);
|
||||||
|
}
|
||||||
|
#elif defined(Q_OS_WIN)
|
||||||
|
if (window->isMinimized()) {
|
||||||
|
window->showNormal();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
window->raise();
|
window->raise();
|
||||||
window->activateWindow();
|
window->activateWindow();
|
||||||
} else {
|
} else {
|
||||||
@ -1338,6 +1535,7 @@ InstanceWindow* Application::showInstanceWindow(InstancePtr instance, QString pa
|
|||||||
m_openWindows++;
|
m_openWindows++;
|
||||||
connect(window, &InstanceWindow::isClosing, this, &Application::on_windowClose);
|
connect(window, &InstanceWindow::isClosing, this, &Application::on_windowClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!page.isEmpty()) {
|
if (!page.isEmpty()) {
|
||||||
window->selectPage(page);
|
window->selectPage(page);
|
||||||
}
|
}
|
||||||
@ -1451,6 +1649,15 @@ void Application::updateCapabilities()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::detectLibraries()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
m_detectedGLFWPath = MangoHud::findLibrary(BuildConfig.GLFW_LIBRARY_NAME);
|
||||||
|
m_detectedOpenALPath = MangoHud::findLibrary(BuildConfig.OPENAL_LIBRARY_NAME);
|
||||||
|
qDebug() << "Detected native libraries:" << m_detectedGLFWPath << m_detectedOpenALPath;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
QString Application::getJarPath(QString jarFile)
|
QString Application::getJarPath(QString jarFile)
|
||||||
{
|
{
|
||||||
QStringList potentialPaths = {
|
QStringList potentialPaths = {
|
||||||
@ -1629,3 +1836,13 @@ void Application::triggerUpdateCheck()
|
|||||||
qDebug() << "Updater not available.";
|
qDebug() << "Updater not available.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QUrl Application::normalizeImportUrl(QString const& url)
|
||||||
|
{
|
||||||
|
auto local_file = QFileInfo(url);
|
||||||
|
if (local_file.exists()) {
|
||||||
|
return QUrl::fromLocalFile(local_file.absoluteFilePath());
|
||||||
|
} else {
|
||||||
|
return QUrl::fromUserInput(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -71,6 +71,7 @@ class TranslationsModel;
|
|||||||
class ITheme;
|
class ITheme;
|
||||||
class MCEditTool;
|
class MCEditTool;
|
||||||
class ThemeManager;
|
class ThemeManager;
|
||||||
|
class IconTheme;
|
||||||
|
|
||||||
namespace Meta {
|
namespace Meta {
|
||||||
class Index;
|
class Index;
|
||||||
@ -109,17 +110,7 @@ class Application : public QApplication {
|
|||||||
|
|
||||||
QIcon getThemedIcon(const QString& name);
|
QIcon getThemedIcon(const QString& name);
|
||||||
|
|
||||||
void setIconTheme(const QString& name);
|
ThemeManager* themeManager() { return m_themeManager.get(); }
|
||||||
|
|
||||||
void applyCurrentlySelectedTheme(bool initial = false);
|
|
||||||
|
|
||||||
QList<ITheme*> getValidApplicationThemes();
|
|
||||||
|
|
||||||
void setApplicationTheme(const QString& name);
|
|
||||||
|
|
||||||
QList<CatPack*> getValidCatPacks();
|
|
||||||
|
|
||||||
QString getCatPack(QString catName = "");
|
|
||||||
|
|
||||||
shared_qobject_ptr<ExternalUpdater> updater() { return m_updater; }
|
shared_qobject_ptr<ExternalUpdater> updater() { return m_updater; }
|
||||||
|
|
||||||
@ -151,6 +142,8 @@ class Application : public QApplication {
|
|||||||
|
|
||||||
void updateCapabilities();
|
void updateCapabilities();
|
||||||
|
|
||||||
|
void detectLibraries();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Finds and returns the full path to a jar file.
|
* Finds and returns the full path to a jar file.
|
||||||
* Returns a null-string if it could not be found.
|
* Returns a null-string if it could not be found.
|
||||||
@ -166,6 +159,9 @@ class Application : public QApplication {
|
|||||||
/// this is the root of the 'installation'. Used for automatic updates
|
/// this is the root of the 'installation'. Used for automatic updates
|
||||||
const QString& root() { return m_rootPath; }
|
const QString& root() { return m_rootPath; }
|
||||||
|
|
||||||
|
/// the data path the application is using
|
||||||
|
const QString& dataRoot() { return m_dataPath; }
|
||||||
|
|
||||||
bool isPortable() { return m_portable; }
|
bool isPortable() { return m_portable; }
|
||||||
|
|
||||||
const Capabilities capabilities() { return m_capabilities; }
|
const Capabilities capabilities() { return m_capabilities; }
|
||||||
@ -186,6 +182,11 @@ class Application : public QApplication {
|
|||||||
|
|
||||||
int suitableMaxMem();
|
int suitableMaxMem();
|
||||||
|
|
||||||
|
bool updaterEnabled();
|
||||||
|
QString updaterBinaryName();
|
||||||
|
|
||||||
|
QUrl normalizeImportUrl(QString const& url);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void updateAllowedChanged(bool status);
|
void updateAllowedChanged(bool status);
|
||||||
void globalSettingsAboutToOpen();
|
void globalSettingsAboutToOpen();
|
||||||
@ -200,7 +201,6 @@ class Application : public QApplication {
|
|||||||
bool launch(InstancePtr instance,
|
bool launch(InstancePtr instance,
|
||||||
bool online = true,
|
bool online = true,
|
||||||
bool demo = false,
|
bool demo = false,
|
||||||
BaseProfilerFactory* profiler = nullptr,
|
|
||||||
MinecraftServerTargetPtr serverToJoin = nullptr,
|
MinecraftServerTargetPtr serverToJoin = nullptr,
|
||||||
MinecraftAccountPtr accountToUse = nullptr);
|
MinecraftAccountPtr accountToUse = nullptr);
|
||||||
bool kill(InstancePtr instance);
|
bool kill(InstancePtr instance);
|
||||||
@ -250,6 +250,7 @@ class Application : public QApplication {
|
|||||||
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
|
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
|
||||||
|
|
||||||
QString m_rootPath;
|
QString m_rootPath;
|
||||||
|
QString m_dataPath;
|
||||||
Status m_status = Application::StartingUp;
|
Status m_status = Application::StartingUp;
|
||||||
Capabilities m_capabilities;
|
Capabilities m_capabilities;
|
||||||
bool m_portable = false;
|
bool m_portable = false;
|
||||||
@ -284,11 +285,13 @@ class Application : public QApplication {
|
|||||||
SetupWizard* m_setupWizard = nullptr;
|
SetupWizard* m_setupWizard = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
QString m_detectedGLFWPath;
|
||||||
|
QString m_detectedOpenALPath;
|
||||||
QString m_instanceIdToLaunch;
|
QString m_instanceIdToLaunch;
|
||||||
QString m_serverToJoin;
|
QString m_serverToJoin;
|
||||||
QString m_profileToUse;
|
QString m_profileToUse;
|
||||||
bool m_liveCheck = false;
|
bool m_liveCheck = false;
|
||||||
QList<QUrl> m_zipsToImport;
|
QList<QUrl> m_urlsToImport;
|
||||||
QString m_instanceIdToShowWindowOf;
|
QString m_instanceIdToShowWindowOf;
|
||||||
std::unique_ptr<QFile> logFile;
|
std::unique_ptr<QFile> logFile;
|
||||||
};
|
};
|
||||||
|
@ -3,6 +3,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) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||||
|
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -63,6 +64,8 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
|
|||||||
|
|
||||||
m_settings->registerSetting("lastLaunchTime", 0);
|
m_settings->registerSetting("lastLaunchTime", 0);
|
||||||
m_settings->registerSetting("totalTimePlayed", 0);
|
m_settings->registerSetting("totalTimePlayed", 0);
|
||||||
|
if (m_settings->get("totalTimePlayed").toLongLong() < 0)
|
||||||
|
m_settings->reset("totalTimePlayed");
|
||||||
m_settings->registerSetting("lastTimePlayed", 0);
|
m_settings->registerSetting("lastTimePlayed", 0);
|
||||||
|
|
||||||
m_settings->registerSetting("linkedInstances", "[]");
|
m_settings->registerSetting("linkedInstances", "[]");
|
||||||
@ -100,6 +103,8 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
|
|||||||
m_settings->registerSetting("ManagedPackName", "");
|
m_settings->registerSetting("ManagedPackName", "");
|
||||||
m_settings->registerSetting("ManagedPackVersionID", "");
|
m_settings->registerSetting("ManagedPackVersionID", "");
|
||||||
m_settings->registerSetting("ManagedPackVersionName", "");
|
m_settings->registerSetting("ManagedPackVersionName", "");
|
||||||
|
|
||||||
|
m_settings->registerSetting("Profiler", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BaseInstance::getPreLaunchCommand()
|
QString BaseInstance::getPreLaunchCommand()
|
||||||
@ -385,7 +390,7 @@ QString BaseInstance::name() const
|
|||||||
|
|
||||||
QString BaseInstance::windowTitle() const
|
QString BaseInstance::windowTitle() const
|
||||||
{
|
{
|
||||||
return BuildConfig.LAUNCHER_DISPLAYNAME + ": " + name().replace(QRegularExpression("\\s+"), " ");
|
return BuildConfig.LAUNCHER_DISPLAYNAME + ": " + name();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: why is this here? move it to MinecraftInstance!!!
|
// FIXME: why is this here? move it to MinecraftInstance!!!
|
||||||
|
@ -3,6 +3,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) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||||
|
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -38,6 +39,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
#include <QMenu>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
@ -62,7 +64,7 @@ class LaunchTask;
|
|||||||
class BaseInstance;
|
class BaseInstance;
|
||||||
|
|
||||||
// pointer for lazy people
|
// pointer for lazy people
|
||||||
typedef std::shared_ptr<BaseInstance> InstancePtr;
|
using InstancePtr = std::shared_ptr<BaseInstance>;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Base class for instances.
|
* \brief Base class for instances.
|
||||||
@ -86,7 +88,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// virtual destructor to make sure the destruction is COMPLETE
|
/// virtual destructor to make sure the destruction is COMPLETE
|
||||||
virtual ~BaseInstance(){};
|
virtual ~BaseInstance() {}
|
||||||
|
|
||||||
virtual void saveNow() = 0;
|
virtual void saveNow() = 0;
|
||||||
|
|
||||||
@ -146,7 +148,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
void copyManagedPack(BaseInstance& other);
|
void copyManagedPack(BaseInstance& other);
|
||||||
|
|
||||||
/// guess log level from a line of game log
|
/// guess log level from a line of game log
|
||||||
virtual MessageLevel::Enum guessLevel([[maybe_unused]] const QString& line, MessageLevel::Enum level) { return level; };
|
virtual MessageLevel::Enum guessLevel([[maybe_unused]] const QString& line, MessageLevel::Enum level) { return level; }
|
||||||
|
|
||||||
virtual QStringList extraArguments();
|
virtual QStringList extraArguments();
|
||||||
|
|
||||||
@ -246,6 +248,8 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
virtual bool canEdit() const = 0;
|
virtual bool canEdit() const = 0;
|
||||||
virtual bool canExport() const = 0;
|
virtual bool canExport() const = 0;
|
||||||
|
|
||||||
|
virtual void populateLaunchMenu(QMenu* menu) = 0;
|
||||||
|
|
||||||
bool reloadSettings();
|
bool reloadSettings();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -267,7 +271,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
protected:
|
protected:
|
||||||
void changeStatus(Status newStatus);
|
void changeStatus(Status newStatus);
|
||||||
|
|
||||||
SettingsObjectPtr globalSettings() const { return m_global_settings.lock(); };
|
SettingsObjectPtr globalSettings() const { return m_global_settings.lock(); }
|
||||||
|
|
||||||
bool isSpecificSettingsLoaded() const { return m_specific_settings_loaded; }
|
bool isSpecificSettingsLoaded() const { return m_specific_settings_loaded; }
|
||||||
void setSpecificSettingsLoaded(bool loaded) { m_specific_settings_loaded = loaded; }
|
void setSpecificSettingsLoaded(bool loaded) { m_specific_settings_loaded = loaded; }
|
||||||
@ -282,6 +286,8 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
|
|
||||||
void runningStatusChanged(bool running);
|
void runningStatusChanged(bool running);
|
||||||
|
|
||||||
|
void profilerChanged();
|
||||||
|
|
||||||
void statusChanged(Status from, Status to);
|
void statusChanged(Status from, Status to);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
@ -43,9 +43,8 @@ class BaseVersion {
|
|||||||
* the kind of version this is (Stable, Beta, Snapshot, whatever)
|
* the kind of version this is (Stable, Beta, Snapshot, whatever)
|
||||||
*/
|
*/
|
||||||
virtual QString typeString() const = 0;
|
virtual QString typeString() const = 0;
|
||||||
|
virtual bool operator<(BaseVersion& a) { return name() < a.name(); }
|
||||||
virtual bool operator<(BaseVersion& a) { return name() < a.name(); };
|
virtual bool operator>(BaseVersion& a) { return name() > a.name(); }
|
||||||
virtual bool operator>(BaseVersion& a) { return name() > a.name(); };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(BaseVersion::Ptr)
|
Q_DECLARE_METATYPE(BaseVersion::Ptr)
|
||||||
|
@ -51,7 +51,7 @@ class BaseVersionList : public QAbstractListModel {
|
|||||||
ArchitectureRole,
|
ArchitectureRole,
|
||||||
SortRole
|
SortRole
|
||||||
};
|
};
|
||||||
typedef QList<int> RoleList;
|
using RoleList = QList<int>;
|
||||||
|
|
||||||
explicit BaseVersionList(QObject* parent = 0);
|
explicit BaseVersionList(QObject* parent = 0);
|
||||||
|
|
||||||
|
@ -136,6 +136,16 @@ set(NET_SOURCES
|
|||||||
net/Validator.h
|
net/Validator.h
|
||||||
net/Upload.cpp
|
net/Upload.cpp
|
||||||
net/Upload.h
|
net/Upload.h
|
||||||
|
net/HeaderProxy.h
|
||||||
|
net/RawHeaderProxy.h
|
||||||
|
net/ApiHeaderProxy.h
|
||||||
|
net/StaticHeaderProxy.h
|
||||||
|
net/ApiDownload.h
|
||||||
|
net/ApiDownload.cpp
|
||||||
|
net/ApiUpload.cpp
|
||||||
|
net/ApiUpload.h
|
||||||
|
net/NetRequest.cpp
|
||||||
|
net/NetRequest.h
|
||||||
)
|
)
|
||||||
|
|
||||||
# Game launch logic
|
# Game launch logic
|
||||||
@ -172,6 +182,11 @@ set(MAC_UPDATE_SOURCES
|
|||||||
updater/MacSparkleUpdater.mm
|
updater/MacSparkleUpdater.mm
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(PRISM_UPDATE_SOURCES
|
||||||
|
updater/PrismExternalUpdater.h
|
||||||
|
updater/PrismExternalUpdater.cpp
|
||||||
|
)
|
||||||
|
|
||||||
# Backend for the news bar... there's usually no news.
|
# Backend for the news bar... there's usually no news.
|
||||||
set(NEWS_SOURCES
|
set(NEWS_SOURCES
|
||||||
# News System
|
# News System
|
||||||
@ -207,13 +222,9 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/auth/MinecraftAccount.h
|
minecraft/auth/MinecraftAccount.h
|
||||||
minecraft/auth/Parsers.cpp
|
minecraft/auth/Parsers.cpp
|
||||||
minecraft/auth/Parsers.h
|
minecraft/auth/Parsers.h
|
||||||
minecraft/auth/Yggdrasil.cpp
|
|
||||||
minecraft/auth/Yggdrasil.h
|
|
||||||
|
|
||||||
minecraft/auth/flows/AuthFlow.cpp
|
minecraft/auth/flows/AuthFlow.cpp
|
||||||
minecraft/auth/flows/AuthFlow.h
|
minecraft/auth/flows/AuthFlow.h
|
||||||
minecraft/auth/flows/Mojang.cpp
|
|
||||||
minecraft/auth/flows/Mojang.h
|
|
||||||
minecraft/auth/flows/MSA.cpp
|
minecraft/auth/flows/MSA.cpp
|
||||||
minecraft/auth/flows/MSA.h
|
minecraft/auth/flows/MSA.h
|
||||||
minecraft/auth/flows/Offline.cpp
|
minecraft/auth/flows/Offline.cpp
|
||||||
@ -227,12 +238,8 @@ set(MINECRAFT_SOURCES
|
|||||||
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/MinecraftProfileStepMojang.h
|
|
||||||
minecraft/auth/steps/MSAStep.cpp
|
minecraft/auth/steps/MSAStep.cpp
|
||||||
minecraft/auth/steps/MSAStep.h
|
minecraft/auth/steps/MSAStep.h
|
||||||
minecraft/auth/steps/XboxAuthorizationStep.cpp
|
minecraft/auth/steps/XboxAuthorizationStep.cpp
|
||||||
@ -241,8 +248,6 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/auth/steps/XboxProfileStep.h
|
minecraft/auth/steps/XboxProfileStep.h
|
||||||
minecraft/auth/steps/XboxUserStep.cpp
|
minecraft/auth/steps/XboxUserStep.cpp
|
||||||
minecraft/auth/steps/XboxUserStep.h
|
minecraft/auth/steps/XboxUserStep.h
|
||||||
minecraft/auth/steps/YggdrasilStep.cpp
|
|
||||||
minecraft/auth/steps/YggdrasilStep.h
|
|
||||||
|
|
||||||
minecraft/gameoptions/GameOptions.h
|
minecraft/gameoptions/GameOptions.h
|
||||||
minecraft/gameoptions/GameOptions.cpp
|
minecraft/gameoptions/GameOptions.cpp
|
||||||
@ -566,6 +571,9 @@ set(ATLAUNCHER_SOURCES
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(LINKEXE_SOURCES
|
set(LINKEXE_SOURCES
|
||||||
|
WindowsConsole.cpp
|
||||||
|
WindowsConsole.h
|
||||||
|
|
||||||
filelink/FileLink.h
|
filelink/FileLink.h
|
||||||
filelink/FileLink.cpp
|
filelink/FileLink.cpp
|
||||||
FileSystem.h
|
FileSystem.h
|
||||||
@ -577,6 +585,63 @@ set(LINKEXE_SOURCES
|
|||||||
DesktopServices.cpp
|
DesktopServices.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(PRISMUPDATER_SOURCES
|
||||||
|
updater/prismupdater/PrismUpdater.h
|
||||||
|
updater/prismupdater/PrismUpdater.cpp
|
||||||
|
updater/prismupdater/UpdaterDialogs.h
|
||||||
|
updater/prismupdater/UpdaterDialogs.cpp
|
||||||
|
updater/prismupdater/GitHubRelease.h
|
||||||
|
updater/prismupdater/GitHubRelease.cpp
|
||||||
|
|
||||||
|
Json.h
|
||||||
|
Json.cpp
|
||||||
|
FileSystem.h
|
||||||
|
FileSystem.cpp
|
||||||
|
StringUtils.h
|
||||||
|
StringUtils.cpp
|
||||||
|
DesktopServices.h
|
||||||
|
DesktopServices.cpp
|
||||||
|
Version.h
|
||||||
|
Version.cpp
|
||||||
|
Markdown.h
|
||||||
|
Markdown.cpp
|
||||||
|
|
||||||
|
# Zip
|
||||||
|
MMCZip.h
|
||||||
|
MMCZip.cpp
|
||||||
|
|
||||||
|
# Time
|
||||||
|
MMCTime.h
|
||||||
|
MMCTime.cpp
|
||||||
|
|
||||||
|
net/ByteArraySink.h
|
||||||
|
net/ChecksumValidator.h
|
||||||
|
net/Download.cpp
|
||||||
|
net/Download.h
|
||||||
|
net/FileSink.cpp
|
||||||
|
net/FileSink.h
|
||||||
|
net/HttpMetaCache.cpp
|
||||||
|
net/HttpMetaCache.h
|
||||||
|
net/Logging.h
|
||||||
|
net/Logging.cpp
|
||||||
|
net/NetAction.h
|
||||||
|
net/NetRequest.cpp
|
||||||
|
net/NetRequest.h
|
||||||
|
net/NetJob.cpp
|
||||||
|
net/NetJob.h
|
||||||
|
net/NetUtils.h
|
||||||
|
net/Sink.h
|
||||||
|
net/Validator.h
|
||||||
|
net/HeaderProxy.h
|
||||||
|
net/RawHeaderProxy.h
|
||||||
|
|
||||||
|
ui/dialogs/ProgressDialog.cpp
|
||||||
|
ui/dialogs/ProgressDialog.h
|
||||||
|
ui/widgets/SubTaskProgressBar.h
|
||||||
|
ui/widgets/SubTaskProgressBar.cpp
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
######## Logging categories ########
|
######## Logging categories ########
|
||||||
|
|
||||||
ecm_qt_declare_logging_category(CORE_SOURCES
|
ecm_qt_declare_logging_category(CORE_SOURCES
|
||||||
@ -673,6 +738,8 @@ set(LOGIC_SOURCES
|
|||||||
|
|
||||||
if(APPLE AND Launcher_ENABLE_UPDATER)
|
if(APPLE AND Launcher_ENABLE_UPDATER)
|
||||||
set (LOGIC_SOURCES ${LOGIC_SOURCES} ${MAC_UPDATE_SOURCES})
|
set (LOGIC_SOURCES ${LOGIC_SOURCES} ${MAC_UPDATE_SOURCES})
|
||||||
|
else()
|
||||||
|
set (LOGIC_SOURCES ${LOGIC_SOURCES} ${PRISM_UPDATE_SOURCES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
SET(LAUNCHER_SOURCES
|
SET(LAUNCHER_SOURCES
|
||||||
@ -762,6 +829,8 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/themes/ITheme.h
|
ui/themes/ITheme.h
|
||||||
ui/themes/SystemTheme.cpp
|
ui/themes/SystemTheme.cpp
|
||||||
ui/themes/SystemTheme.h
|
ui/themes/SystemTheme.h
|
||||||
|
ui/themes/IconTheme.cpp
|
||||||
|
ui/themes/IconTheme.h
|
||||||
ui/themes/ThemeManager.cpp
|
ui/themes/ThemeManager.cpp
|
||||||
ui/themes/ThemeManager.h
|
ui/themes/ThemeManager.h
|
||||||
ui/themes/CatPack.cpp
|
ui/themes/CatPack.cpp
|
||||||
@ -820,6 +889,8 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/pages/global/AccountListPage.h
|
ui/pages/global/AccountListPage.h
|
||||||
ui/pages/global/CustomCommandsPage.cpp
|
ui/pages/global/CustomCommandsPage.cpp
|
||||||
ui/pages/global/CustomCommandsPage.h
|
ui/pages/global/CustomCommandsPage.h
|
||||||
|
ui/pages/global/EnvironmentVariablesPage.cpp
|
||||||
|
ui/pages/global/EnvironmentVariablesPage.h
|
||||||
ui/pages/global/ExternalToolsPage.cpp
|
ui/pages/global/ExternalToolsPage.cpp
|
||||||
ui/pages/global/ExternalToolsPage.h
|
ui/pages/global/ExternalToolsPage.h
|
||||||
ui/pages/global/JavaPage.cpp
|
ui/pages/global/JavaPage.cpp
|
||||||
@ -902,6 +973,9 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/pages/modplatform/ImportPage.cpp
|
ui/pages/modplatform/ImportPage.cpp
|
||||||
ui/pages/modplatform/ImportPage.h
|
ui/pages/modplatform/ImportPage.h
|
||||||
|
|
||||||
|
ui/pages/modplatform/OptionalModDialog.cpp
|
||||||
|
ui/pages/modplatform/OptionalModDialog.h
|
||||||
|
|
||||||
ui/pages/modplatform/modrinth/ModrinthResourceModels.cpp
|
ui/pages/modplatform/modrinth/ModrinthResourceModels.cpp
|
||||||
ui/pages/modplatform/modrinth/ModrinthResourceModels.h
|
ui/pages/modplatform/modrinth/ModrinthResourceModels.h
|
||||||
ui/pages/modplatform/modrinth/ModrinthResourcePages.cpp
|
ui/pages/modplatform/modrinth/ModrinthResourcePages.cpp
|
||||||
@ -930,8 +1004,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/dialogs/IconPickerDialog.h
|
ui/dialogs/IconPickerDialog.h
|
||||||
ui/dialogs/ImportResourceDialog.cpp
|
ui/dialogs/ImportResourceDialog.cpp
|
||||||
ui/dialogs/ImportResourceDialog.h
|
ui/dialogs/ImportResourceDialog.h
|
||||||
ui/dialogs/LoginDialog.cpp
|
|
||||||
ui/dialogs/LoginDialog.h
|
|
||||||
ui/dialogs/MSALoginDialog.cpp
|
ui/dialogs/MSALoginDialog.cpp
|
||||||
ui/dialogs/MSALoginDialog.h
|
ui/dialogs/MSALoginDialog.h
|
||||||
ui/dialogs/OfflineLoginDialog.cpp
|
ui/dialogs/OfflineLoginDialog.cpp
|
||||||
@ -962,12 +1034,16 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/dialogs/ChooseProviderDialog.cpp
|
ui/dialogs/ChooseProviderDialog.cpp
|
||||||
ui/dialogs/ModUpdateDialog.cpp
|
ui/dialogs/ModUpdateDialog.cpp
|
||||||
ui/dialogs/ModUpdateDialog.h
|
ui/dialogs/ModUpdateDialog.h
|
||||||
|
ui/dialogs/InstallLoaderDialog.cpp
|
||||||
|
ui/dialogs/InstallLoaderDialog.h
|
||||||
|
|
||||||
# GUI - widgets
|
# GUI - widgets
|
||||||
ui/widgets/Common.cpp
|
ui/widgets/Common.cpp
|
||||||
ui/widgets/Common.h
|
ui/widgets/Common.h
|
||||||
ui/widgets/CustomCommands.cpp
|
ui/widgets/CustomCommands.cpp
|
||||||
ui/widgets/CustomCommands.h
|
ui/widgets/CustomCommands.h
|
||||||
|
ui/widgets/EnvironmentVariables.cpp
|
||||||
|
ui/widgets/EnvironmentVariables.h
|
||||||
ui/widgets/DropLabel.cpp
|
ui/widgets/DropLabel.cpp
|
||||||
ui/widgets/DropLabel.h
|
ui/widgets/DropLabel.h
|
||||||
ui/widgets/FocusLineEdit.cpp
|
ui/widgets/FocusLineEdit.cpp
|
||||||
@ -1026,6 +1102,23 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/instanceview/VisualGroup.h
|
ui/instanceview/VisualGroup.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (NOT Apple)
|
||||||
|
set(LAUNCHER_SOURCES
|
||||||
|
${LAUNCHER_SOURCES}
|
||||||
|
|
||||||
|
ui/dialogs/UpdateAvailableDialog.h
|
||||||
|
ui/dialogs/UpdateAvailableDialog.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(LAUNCHER_SOURCES
|
||||||
|
WindowsConsole.cpp
|
||||||
|
WindowsConsole.h
|
||||||
|
${LAUNCHER_SOURCES}
|
||||||
|
)
|
||||||
|
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
|
||||||
@ -1056,10 +1149,12 @@ qt_wrap_ui(LAUNCHER_UI
|
|||||||
ui/pages/modplatform/legacy_ftb/Page.ui
|
ui/pages/modplatform/legacy_ftb/Page.ui
|
||||||
ui/pages/modplatform/import_ftb/ImportFTBPage.ui
|
ui/pages/modplatform/import_ftb/ImportFTBPage.ui
|
||||||
ui/pages/modplatform/ImportPage.ui
|
ui/pages/modplatform/ImportPage.ui
|
||||||
|
ui/pages/modplatform/OptionalModDialog.ui
|
||||||
ui/pages/modplatform/modrinth/ModrinthPage.ui
|
ui/pages/modplatform/modrinth/ModrinthPage.ui
|
||||||
ui/pages/modplatform/technic/TechnicPage.ui
|
ui/pages/modplatform/technic/TechnicPage.ui
|
||||||
ui/widgets/InstanceCardWidget.ui
|
ui/widgets/InstanceCardWidget.ui
|
||||||
ui/widgets/CustomCommands.ui
|
ui/widgets/CustomCommands.ui
|
||||||
|
ui/widgets/EnvironmentVariables.ui
|
||||||
ui/widgets/InfoFrame.ui
|
ui/widgets/InfoFrame.ui
|
||||||
ui/widgets/ModFilterWidget.ui
|
ui/widgets/ModFilterWidget.ui
|
||||||
ui/widgets/SubTaskProgressBar.ui
|
ui/widgets/SubTaskProgressBar.ui
|
||||||
@ -1080,7 +1175,6 @@ qt_wrap_ui(LAUNCHER_UI
|
|||||||
ui/dialogs/MSALoginDialog.ui
|
ui/dialogs/MSALoginDialog.ui
|
||||||
ui/dialogs/OfflineLoginDialog.ui
|
ui/dialogs/OfflineLoginDialog.ui
|
||||||
ui/dialogs/AboutDialog.ui
|
ui/dialogs/AboutDialog.ui
|
||||||
ui/dialogs/LoginDialog.ui
|
|
||||||
ui/dialogs/EditAccountDialog.ui
|
ui/dialogs/EditAccountDialog.ui
|
||||||
ui/dialogs/ReviewMessageBox.ui
|
ui/dialogs/ReviewMessageBox.ui
|
||||||
ui/dialogs/ScrollMessageBox.ui
|
ui/dialogs/ScrollMessageBox.ui
|
||||||
@ -1088,6 +1182,14 @@ qt_wrap_ui(LAUNCHER_UI
|
|||||||
ui/dialogs/ChooseProviderDialog.ui
|
ui/dialogs/ChooseProviderDialog.ui
|
||||||
)
|
)
|
||||||
|
|
||||||
|
qt_wrap_ui(PRISM_UPDATE_UI
|
||||||
|
ui/dialogs/UpdateAvailableDialog.ui
|
||||||
|
)
|
||||||
|
|
||||||
|
if (NOT Apple)
|
||||||
|
set (LAUNCHER_UI ${LAUNCHER_UI} ${PRISM_UPDATE_UI})
|
||||||
|
endif()
|
||||||
|
|
||||||
qt_add_resources(LAUNCHER_RESOURCES
|
qt_add_resources(LAUNCHER_RESOURCES
|
||||||
resources/backgrounds/backgrounds.qrc
|
resources/backgrounds/backgrounds.qrc
|
||||||
resources/multimc/multimc.qrc
|
resources/multimc/multimc.qrc
|
||||||
@ -1104,14 +1206,31 @@ qt_add_resources(LAUNCHER_RESOURCES
|
|||||||
../${Launcher_Branding_LogoQRC}
|
../${Launcher_Branding_LogoQRC}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
qt_wrap_ui(PRISMUPDATER_UI
|
||||||
|
updater/prismupdater/SelectReleaseDialog.ui
|
||||||
|
ui/widgets/SubTaskProgressBar.ui
|
||||||
|
ui/dialogs/ProgressDialog.ui
|
||||||
|
)
|
||||||
|
|
||||||
######## Windows resource files ########
|
######## Windows resource files ########
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(LAUNCHER_RCS ${CMAKE_CURRENT_BINARY_DIR}/../${Launcher_Branding_WindowsRC})
|
set(LAUNCHER_RCS ${CMAKE_CURRENT_BINARY_DIR}/../${Launcher_Branding_WindowsRC})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
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
|
||||||
|
"${Launcher_MSVC_WARNINGS}"
|
||||||
|
"${Launcher_CLANG_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_link_libraries(Launcher_logic
|
target_link_libraries(Launcher_logic
|
||||||
systeminfo
|
systeminfo
|
||||||
Launcher_murmur2
|
Launcher_murmur2
|
||||||
@ -1193,8 +1312,51 @@ install(TARGETS ${Launcher_Name}
|
|||||||
FRAMEWORK DESTINATION ${FRAMEWORK_DEST_DIR} COMPONENT Runtime
|
FRAMEWORK DESTINATION ${FRAMEWORK_DEST_DIR} COMPONENT Runtime
|
||||||
)
|
)
|
||||||
|
|
||||||
if(WIN32)
|
if(Launcher_BUILD_UPDATER)
|
||||||
|
# Updater
|
||||||
|
add_library(prism_updater_logic STATIC ${PRISMUPDATER_SOURCES} ${TASKS_SOURCES} ${PRISMUPDATER_UI})
|
||||||
|
target_include_directories(prism_updater_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
target_link_libraries(prism_updater_logic
|
||||||
|
QuaZip::QuaZip
|
||||||
|
${ZLIB_LIBRARIES}
|
||||||
|
systeminfo
|
||||||
|
BuildConfig
|
||||||
|
ghcFilesystem::ghc_filesystem
|
||||||
|
Qt${QT_VERSION_MAJOR}::Widgets
|
||||||
|
Qt${QT_VERSION_MAJOR}::Core
|
||||||
|
Qt${QT_VERSION_MAJOR}::Network
|
||||||
|
${Launcher_QT_LIBS}
|
||||||
|
cmark::cmark
|
||||||
|
Katabasis
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable("${Launcher_Name}_updater" WIN32 updater/prismupdater/updater_main.cpp)
|
||||||
|
target_sources("${Launcher_Name}_updater" PRIVATE updater/prismupdater/updater.exe.manifest)
|
||||||
|
target_link_libraries("${Launcher_Name}_updater" prism_updater_logic)
|
||||||
|
|
||||||
|
if(DEFINED Launcher_APP_BINARY_NAME)
|
||||||
|
set_target_properties("${Launcher_Name}_updater" PROPERTIES OUTPUT_NAME "${Launcher_APP_BINARY_NAME}_updater")
|
||||||
|
endif()
|
||||||
|
if(DEFINED Launcher_BINARY_RPATH)
|
||||||
|
SET_TARGET_PROPERTIES("${Launcher_Name}_updater" PROPERTIES INSTALL_RPATH "${Launcher_BINARY_RPATH}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(TARGETS "${Launcher_Name}_updater"
|
||||||
|
BUNDLE DESTINATION "." COMPONENT Runtime
|
||||||
|
LIBRARY DESTINATION ${LIBRARY_DEST_DIR} COMPONENT Runtime
|
||||||
|
RUNTIME DESTINATION ${BINARY_DEST_DIR} COMPONENT Runtime
|
||||||
|
FRAMEWORK DESTINATION ${FRAMEWORK_DEST_DIR} COMPONENT Runtime
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32 OR (DEFINED Launcher_BUILD_FILELINKER AND Launcher_BUILD_FILELINKER))
|
||||||
|
# File link
|
||||||
add_library(filelink_logic STATIC ${LINKEXE_SOURCES})
|
add_library(filelink_logic STATIC ${LINKEXE_SOURCES})
|
||||||
|
set_project_warnings(filelink_logic
|
||||||
|
"${Launcher_MSVC_WARNINGS}"
|
||||||
|
"${Launcher_CLANG_WARNINGS}"
|
||||||
|
"${Launcher_GCC_WARNINGS}")
|
||||||
|
|
||||||
target_include_directories(filelink_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(filelink_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
target_link_libraries(filelink_logic
|
target_link_libraries(filelink_logic
|
||||||
systeminfo
|
systeminfo
|
||||||
@ -1207,7 +1369,7 @@ if(WIN32)
|
|||||||
${Launcher_QT_LIBS}
|
${Launcher_QT_LIBS}
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable("${Launcher_Name}_filelink" WIN32 filelink/main.cpp)
|
add_executable("${Launcher_Name}_filelink" WIN32 filelink/filelink_main.cpp)
|
||||||
|
|
||||||
target_sources("${Launcher_Name}_filelink" PRIVATE filelink/filelink.exe.manifest)
|
target_sources("${Launcher_Name}_filelink" PRIVATE filelink/filelink.exe.manifest)
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
class DataMigrationTask : public Task {
|
class DataMigrationTask : public Task {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit DataMigrationTask(QObject* parent, const QString& sourcePath, const QString& targetPath, const IPathMatcher::Ptr pathmatcher);
|
explicit DataMigrationTask(QObject* parent, const QString& sourcePath, const QString& targetPath, IPathMatcher::Ptr pathmatcher);
|
||||||
~DataMigrationTask() override = default;
|
~DataMigrationTask() override = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -37,143 +37,33 @@
|
|||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include "FileSystem.h"
|
||||||
/**
|
|
||||||
* This shouldn't exist, but until QTBUG-9328 and other unreported bugs are fixed, it needs to be a thing.
|
|
||||||
*/
|
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
bool IndirectOpen(T callable, qint64* pid_forked = nullptr)
|
|
||||||
{
|
|
||||||
auto pid = fork();
|
|
||||||
if (pid_forked) {
|
|
||||||
if (pid > 0)
|
|
||||||
*pid_forked = pid;
|
|
||||||
else
|
|
||||||
*pid_forked = 0;
|
|
||||||
}
|
|
||||||
if (pid == -1) {
|
|
||||||
qWarning() << "IndirectOpen failed to fork: " << errno;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// child - do the stuff
|
|
||||||
if (pid == 0) {
|
|
||||||
// unset all this garbage so it doesn't get passed to the child process
|
|
||||||
qunsetenv("LD_PRELOAD");
|
|
||||||
qunsetenv("LD_LIBRARY_PATH");
|
|
||||||
qunsetenv("LD_DEBUG");
|
|
||||||
qunsetenv("QT_PLUGIN_PATH");
|
|
||||||
qunsetenv("QT_FONTPATH");
|
|
||||||
|
|
||||||
// open the URL
|
|
||||||
auto status = callable();
|
|
||||||
|
|
||||||
// detach from the parent process group.
|
|
||||||
setsid();
|
|
||||||
|
|
||||||
// die. now. do not clean up anything, it would just hang forever.
|
|
||||||
_exit(status ? 0 : 1);
|
|
||||||
} else {
|
|
||||||
// parent - assume it worked.
|
|
||||||
int status;
|
|
||||||
while (waitpid(pid, &status, 0)) {
|
|
||||||
if (WIFEXITED(status)) {
|
|
||||||
return WEXITSTATUS(status) == 0;
|
|
||||||
}
|
|
||||||
if (WIFSIGNALED(status)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace DesktopServices {
|
namespace DesktopServices {
|
||||||
bool openDirectory(const QString& path, bool ensureExists)
|
bool openPath(const QFileInfo& path, bool ensureFolderPathExists)
|
||||||
{
|
{
|
||||||
qDebug() << "Opening directory" << path;
|
qDebug() << "Opening path" << path;
|
||||||
QDir parentPath;
|
if (ensureFolderPathExists) {
|
||||||
QDir dir(path);
|
FS::ensureFolderPathExists(path);
|
||||||
if (!dir.exists()) {
|
|
||||||
parentPath.mkpath(dir.absolutePath());
|
|
||||||
}
|
}
|
||||||
auto f = [&]() { return QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath())); };
|
return openUrl(QUrl::fromLocalFile(QFileInfo(path).absoluteFilePath()));
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
|
||||||
if (!isSandbox()) {
|
|
||||||
return IndirectOpen(f);
|
|
||||||
} else {
|
|
||||||
return f();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return f();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool openFile(const QString& path)
|
bool openPath(const QString& path, bool ensureFolderPathExists)
|
||||||
{
|
{
|
||||||
qDebug() << "Opening file" << path;
|
return openPath(QFileInfo(path), ensureFolderPathExists);
|
||||||
auto f = [&]() { return QDesktopServices::openUrl(QUrl::fromLocalFile(path)); };
|
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
|
||||||
if (!isSandbox()) {
|
|
||||||
return IndirectOpen(f);
|
|
||||||
} else {
|
|
||||||
return f();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return f();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool openFile(const QString& application, const QString& path, const QString& workingDirectory, qint64* pid)
|
|
||||||
{
|
|
||||||
qDebug() << "Opening file" << path << "using" << application;
|
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
|
||||||
// FIXME: the pid here is fake. So if something depends on it, it will likely misbehave
|
|
||||||
if (!isSandbox()) {
|
|
||||||
return IndirectOpen([&]() { return QProcess::startDetached(application, QStringList() << path, workingDirectory); }, pid);
|
|
||||||
} else {
|
|
||||||
return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool run(const QString& application, const QStringList& args, const QString& workingDirectory, qint64* pid)
|
bool run(const QString& application, const QStringList& args, const QString& workingDirectory, qint64* pid)
|
||||||
{
|
{
|
||||||
qDebug() << "Running" << application << "with args" << args.join(' ');
|
qDebug() << "Running" << application << "with args" << args.join(' ');
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
|
||||||
if (!isSandbox()) {
|
|
||||||
// FIXME: the pid here is fake. So if something depends on it, it will likely misbehave
|
|
||||||
return IndirectOpen([&]() { return QProcess::startDetached(application, args, workingDirectory); }, pid);
|
|
||||||
} else {
|
|
||||||
return QProcess::startDetached(application, args, workingDirectory, pid);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return QProcess::startDetached(application, args, workingDirectory, pid);
|
return QProcess::startDetached(application, args, workingDirectory, pid);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool openUrl(const QUrl& url)
|
bool openUrl(const QUrl& url)
|
||||||
{
|
{
|
||||||
qDebug() << "Opening URL" << url.toString();
|
qDebug() << "Opening URL" << url.toString();
|
||||||
auto f = [&]() { return QDesktopServices::openUrl(url); };
|
return QDesktopServices::openUrl(url);
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
|
||||||
if (!isSandbox()) {
|
|
||||||
return IndirectOpen(f);
|
|
||||||
} else {
|
|
||||||
return f();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return f();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isFlatpak()
|
bool isFlatpak()
|
||||||
@ -194,9 +84,4 @@ bool isSnap()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSandbox()
|
|
||||||
{
|
|
||||||
return isSnap() || isFlatpak();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace DesktopServices
|
} // namespace DesktopServices
|
||||||
|
@ -3,31 +3,30 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
|
class QFileInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This wraps around QDesktopServices and adds workarounds where needed
|
* This wraps around QDesktopServices and adds workarounds where needed
|
||||||
* Use this instead of QDesktopServices!
|
* Use this instead of QDesktopServices!
|
||||||
*/
|
*/
|
||||||
namespace DesktopServices {
|
namespace DesktopServices {
|
||||||
/**
|
/**
|
||||||
* Open a file in whatever application is applicable
|
* Open a path in whatever application is applicable.
|
||||||
|
* @param ensureFolderPathExists Make sure the path exists
|
||||||
*/
|
*/
|
||||||
bool openFile(const QString& path);
|
bool openPath(const QFileInfo& path, bool ensureFolderPathExists = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a file in the specified application
|
* Open a path in whatever application is applicable.
|
||||||
|
* @param ensureFolderPathExists Make sure the path exists
|
||||||
*/
|
*/
|
||||||
bool openFile(const QString& application, const QString& path, const QString& workingDirectory = QString(), qint64* pid = 0);
|
bool openPath(const QString& path, bool ensureFolderPathExists = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run an application
|
* Run an application
|
||||||
*/
|
*/
|
||||||
bool run(const QString& application, const QStringList& args, const QString& workingDirectory = QString(), qint64* pid = 0);
|
bool run(const QString& application, const QStringList& args, const QString& workingDirectory = QString(), qint64* pid = 0);
|
||||||
|
|
||||||
/**
|
|
||||||
* Open a directory
|
|
||||||
*/
|
|
||||||
bool openDirectory(const QString& path, bool ensureExists = false);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open the URL, most likely in a browser. Maybe.
|
* Open the URL, most likely in a browser. Maybe.
|
||||||
*/
|
*/
|
||||||
@ -42,9 +41,4 @@ bool isFlatpak();
|
|||||||
* Determine whether the launcher is running in a Snap environment
|
* Determine whether the launcher is running in a Snap environment
|
||||||
*/
|
*/
|
||||||
bool isSnap();
|
bool isSnap();
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the launcher is running in a sandboxed (Flatpak or Snap) environment
|
|
||||||
*/
|
|
||||||
bool isSandbox();
|
|
||||||
} // namespace DesktopServices
|
} // namespace DesktopServices
|
||||||
|
@ -1,4 +1,37 @@
|
|||||||
// Licensed under the Apache-2.0 license. See README.md for details.
|
// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2024 TheKodeToad <TheKodeToad@proton.me>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This file incorporates work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
@ -8,12 +41,12 @@
|
|||||||
|
|
||||||
class Exception : public std::exception {
|
class Exception : public std::exception {
|
||||||
public:
|
public:
|
||||||
Exception(const QString& message) : std::exception(), m_message(message) { qCritical() << "Exception:" << message; }
|
Exception(const QString& message) : std::exception(), m_message(message.toUtf8()) { qCritical() << "Exception:" << message; }
|
||||||
Exception(const Exception& other) : std::exception(), m_message(other.cause()) {}
|
Exception(const Exception& other) : std::exception(), m_message(other.m_message) {}
|
||||||
virtual ~Exception() noexcept {}
|
virtual ~Exception() noexcept {}
|
||||||
const char* what() const noexcept { return m_message.toLatin1().constData(); }
|
const char* what() const noexcept { return m_message.constData(); }
|
||||||
QString cause() const { return m_message; }
|
QString cause() const { return QString::fromUtf8(m_message); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_message;
|
QByteArray m_message;
|
||||||
};
|
};
|
||||||
|
@ -267,10 +267,7 @@ bool FileIgnoreProxy::filterAcceptsRow(int sourceRow, const QModelIndex& sourceP
|
|||||||
|
|
||||||
bool FileIgnoreProxy::ignoreFile(QFileInfo fileInfo) const
|
bool FileIgnoreProxy::ignoreFile(QFileInfo fileInfo) const
|
||||||
{
|
{
|
||||||
auto fileName = fileInfo.fileName();
|
return m_ignoreFiles.contains(fileInfo.fileName()) || m_ignoreFilePaths.covers(relPath(fileInfo.absoluteFilePath()));
|
||||||
auto path = relPath(fileInfo.absoluteFilePath());
|
|
||||||
return std::any_of(m_ignoreFiles.cbegin(), m_ignoreFiles.cend(), [fileName](auto iFileName) { return fileName == iFileName; }) ||
|
|
||||||
m_ignoreFilePaths.covers(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileIgnoreProxy::filterFile(const QString& fileName) const
|
bool FileIgnoreProxy::filterFile(const QString& fileName) const
|
||||||
|
@ -123,26 +123,35 @@ namespace fs = ghc::filesystem;
|
|||||||
|
|
||||||
#if defined(__MINGW32__)
|
#if defined(__MINGW32__)
|
||||||
|
|
||||||
typedef struct _DUPLICATE_EXTENTS_DATA {
|
struct _DUPLICATE_EXTENTS_DATA {
|
||||||
HANDLE FileHandle;
|
HANDLE FileHandle;
|
||||||
LARGE_INTEGER SourceFileOffset;
|
LARGE_INTEGER SourceFileOffset;
|
||||||
LARGE_INTEGER TargetFileOffset;
|
LARGE_INTEGER TargetFileOffset;
|
||||||
LARGE_INTEGER ByteCount;
|
LARGE_INTEGER ByteCount;
|
||||||
} DUPLICATE_EXTENTS_DATA, *PDUPLICATE_EXTENTS_DATA;
|
};
|
||||||
|
|
||||||
typedef struct _FSCTL_GET_INTEGRITY_INFORMATION_BUFFER {
|
using DUPLICATE_EXTENTS_DATA = _DUPLICATE_EXTENTS_DATA;
|
||||||
|
using PDUPLICATE_EXTENTS_DATA = _DUPLICATE_EXTENTS_DATA*;
|
||||||
|
|
||||||
|
struct _FSCTL_GET_INTEGRITY_INFORMATION_BUFFER {
|
||||||
WORD ChecksumAlgorithm; // Checksum algorithm. e.g. CHECKSUM_TYPE_UNCHANGED, CHECKSUM_TYPE_NONE, CHECKSUM_TYPE_CRC32
|
WORD ChecksumAlgorithm; // Checksum algorithm. e.g. CHECKSUM_TYPE_UNCHANGED, CHECKSUM_TYPE_NONE, CHECKSUM_TYPE_CRC32
|
||||||
WORD Reserved; // Must be 0
|
WORD Reserved; // Must be 0
|
||||||
DWORD Flags; // FSCTL_INTEGRITY_FLAG_xxx
|
DWORD Flags; // FSCTL_INTEGRITY_FLAG_xxx
|
||||||
DWORD ChecksumChunkSizeInBytes;
|
DWORD ChecksumChunkSizeInBytes;
|
||||||
DWORD ClusterSizeInBytes;
|
DWORD ClusterSizeInBytes;
|
||||||
} FSCTL_GET_INTEGRITY_INFORMATION_BUFFER, *PFSCTL_GET_INTEGRITY_INFORMATION_BUFFER;
|
};
|
||||||
|
|
||||||
typedef struct _FSCTL_SET_INTEGRITY_INFORMATION_BUFFER {
|
using FSCTL_GET_INTEGRITY_INFORMATION_BUFFER = _FSCTL_GET_INTEGRITY_INFORMATION_BUFFER;
|
||||||
|
using PFSCTL_GET_INTEGRITY_INFORMATION_BUFFER = _FSCTL_GET_INTEGRITY_INFORMATION_BUFFER*;
|
||||||
|
|
||||||
|
struct _FSCTL_SET_INTEGRITY_INFORMATION_BUFFER {
|
||||||
WORD ChecksumAlgorithm; // Checksum algorithm. e.g. CHECKSUM_TYPE_UNCHANGED, CHECKSUM_TYPE_NONE, CHECKSUM_TYPE_CRC32
|
WORD ChecksumAlgorithm; // Checksum algorithm. e.g. CHECKSUM_TYPE_UNCHANGED, CHECKSUM_TYPE_NONE, CHECKSUM_TYPE_CRC32
|
||||||
WORD Reserved; // Must be 0
|
WORD Reserved; // Must be 0
|
||||||
DWORD Flags; // FSCTL_INTEGRITY_FLAG_xxx
|
DWORD Flags; // FSCTL_INTEGRITY_FLAG_xxx
|
||||||
} FSCTL_SET_INTEGRITY_INFORMATION_BUFFER, *PFSCTL_SET_INTEGRITY_INFORMATION_BUFFER;
|
};
|
||||||
|
|
||||||
|
using FSCTL_SET_INTEGRITY_INFORMATION_BUFFER = _FSCTL_SET_INTEGRITY_INFORMATION_BUFFER;
|
||||||
|
using PFSCTL_SET_INTEGRITY_INFORMATION_BUFFER = _FSCTL_SET_INTEGRITY_INFORMATION_BUFFER*;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -194,6 +203,40 @@ void write(const QString& filename, const QByteArray& data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void appendSafe(const QString& filename, const QByteArray& data)
|
||||||
|
{
|
||||||
|
ensureExists(QFileInfo(filename).dir());
|
||||||
|
QByteArray buffer;
|
||||||
|
try {
|
||||||
|
buffer = read(filename);
|
||||||
|
} catch (FileSystemException&) {
|
||||||
|
buffer = QByteArray();
|
||||||
|
}
|
||||||
|
buffer.append(data);
|
||||||
|
QSaveFile file(filename);
|
||||||
|
if (!file.open(QSaveFile::WriteOnly)) {
|
||||||
|
throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString());
|
||||||
|
}
|
||||||
|
if (buffer.size() != file.write(buffer)) {
|
||||||
|
throw FileSystemException("Error writing data to " + filename + ": " + file.errorString());
|
||||||
|
}
|
||||||
|
if (!file.commit()) {
|
||||||
|
throw FileSystemException("Error while committing data to " + filename + ": " + file.errorString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(const QString& filename, const QByteArray& data)
|
||||||
|
{
|
||||||
|
ensureExists(QFileInfo(filename).dir());
|
||||||
|
QFile file(filename);
|
||||||
|
if (!file.open(QFile::Append)) {
|
||||||
|
throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString());
|
||||||
|
}
|
||||||
|
if (data.size() != file.write(data)) {
|
||||||
|
throw FileSystemException("Error writing data to " + filename + ": " + file.errorString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray read(const QString& filename)
|
QByteArray read(const QString& filename)
|
||||||
{
|
{
|
||||||
QFile file(filename);
|
QFile file(filename);
|
||||||
@ -229,15 +272,41 @@ bool ensureFilePathExists(QString filenamepath)
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ensureFolderPathExists(QString foldernamepath)
|
bool ensureFolderPathExists(const QFileInfo folderPath)
|
||||||
{
|
{
|
||||||
QFileInfo a(foldernamepath);
|
|
||||||
QDir dir;
|
QDir dir;
|
||||||
QString ensuredPath = a.filePath();
|
QString ensuredPath = folderPath.filePath();
|
||||||
bool success = dir.mkpath(ensuredPath);
|
bool success = dir.mkpath(ensuredPath);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ensureFolderPathExists(const QString folderPathName)
|
||||||
|
{
|
||||||
|
return ensureFolderPathExists(QFileInfo(folderPathName));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool copyFileAttributes(QString src, QString dst)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
auto attrs = GetFileAttributesW(src.toStdWString().c_str());
|
||||||
|
if (attrs == INVALID_FILE_ATTRIBUTES)
|
||||||
|
return false;
|
||||||
|
return SetFileAttributesW(dst.toStdWString().c_str(), attrs);
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// needs folders to exists
|
||||||
|
void copyFolderAttributes(QString src, QString dst, QString relative)
|
||||||
|
{
|
||||||
|
auto path = PathCombine(src, relative);
|
||||||
|
QDir dsrc(src);
|
||||||
|
while ((path = QFileInfo(path).path()).length() >= src.length()) {
|
||||||
|
auto dst_path = PathCombine(dst, dsrc.relativeFilePath(path));
|
||||||
|
copyFileAttributes(path, dst_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Copies a directory and it's contents from src to dest
|
* @brief Copies a directory and it's contents from src to dest
|
||||||
* @param offset subdirectory form src to copy to dest
|
* @param offset subdirectory form src to copy to dest
|
||||||
@ -265,6 +334,9 @@ bool copy::operator()(const QString& offset, bool dryRun)
|
|||||||
if (!m_followSymlinks)
|
if (!m_followSymlinks)
|
||||||
opt |= copy_opts::copy_symlinks;
|
opt |= copy_opts::copy_symlinks;
|
||||||
|
|
||||||
|
if (m_overwrite)
|
||||||
|
opt |= copy_opts::overwrite_existing;
|
||||||
|
|
||||||
// Function that'll do the actual copying
|
// Function that'll do the actual copying
|
||||||
auto copy_file = [&](QString src_path, QString relative_dst_path) {
|
auto copy_file = [&](QString src_path, QString relative_dst_path) {
|
||||||
if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist))
|
if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist))
|
||||||
@ -273,6 +345,9 @@ bool copy::operator()(const QString& offset, bool dryRun)
|
|||||||
auto dst_path = PathCombine(dst, relative_dst_path);
|
auto dst_path = PathCombine(dst, relative_dst_path);
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
ensureFilePathExists(dst_path);
|
ensureFilePathExists(dst_path);
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
copyFolderAttributes(src, dst, relative_dst_path);
|
||||||
|
#endif
|
||||||
fs::copy(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), opt, err);
|
fs::copy(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), opt, err);
|
||||||
}
|
}
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -872,6 +947,8 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
|
|||||||
<< "\n";
|
<< "\n";
|
||||||
stream << "Type=Application"
|
stream << "Type=Application"
|
||||||
<< "\n";
|
<< "\n";
|
||||||
|
stream << "Categories=Game;ActionGame;AdventureGame;Simulation"
|
||||||
|
<< "\n";
|
||||||
stream << "Exec=\"" << target.toLocal8Bit() << "\"" << argstring.toLocal8Bit() << "\n";
|
stream << "Exec=\"" << target.toLocal8Bit() << "\"" << argstring.toLocal8Bit() << "\n";
|
||||||
stream << "Name=" << name.toLocal8Bit() << "\n";
|
stream << "Name=" << name.toLocal8Bit() << "\n";
|
||||||
if (!icon.isEmpty()) {
|
if (!icon.isEmpty()) {
|
||||||
|
@ -61,6 +61,16 @@ class FileSystemException : public ::Exception {
|
|||||||
*/
|
*/
|
||||||
void write(const QString& filename, const QByteArray& data);
|
void write(const QString& filename, const QByteArray& data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* append data to a file safely
|
||||||
|
*/
|
||||||
|
void appendSafe(const QString& filename, const QByteArray& data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* append data to a file
|
||||||
|
*/
|
||||||
|
void append(const QString& filename, const QByteArray& data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* read data from a file safely\
|
* read data from a file safely\
|
||||||
*/
|
*/
|
||||||
@ -81,7 +91,13 @@ bool ensureFilePathExists(QString filenamepath);
|
|||||||
* Creates all the folders in a path for the specified path
|
* Creates all the folders in a path for the specified path
|
||||||
* last segment of the path is treated as a folder name and is created!
|
* last segment of the path is treated as a folder name and is created!
|
||||||
*/
|
*/
|
||||||
bool ensureFolderPathExists(QString filenamepath);
|
bool ensureFolderPathExists(const QFileInfo folderPath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates all the folders in a path for the specified path
|
||||||
|
* last segment of the path is treated as a folder name and is created!
|
||||||
|
*/
|
||||||
|
bool ensureFolderPathExists(const QString folderPathName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Copies a directory and it's contents from src to dest
|
* @brief Copies a directory and it's contents from src to dest
|
||||||
@ -109,11 +125,16 @@ class copy : public QObject {
|
|||||||
m_whitelist = whitelist;
|
m_whitelist = whitelist;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
copy& overwrite(const bool overwrite)
|
||||||
|
{
|
||||||
|
m_overwrite = overwrite;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
|
bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
|
||||||
|
|
||||||
int totalCopied() { return m_copied; }
|
qsizetype totalCopied() { return m_copied; }
|
||||||
int totalFailed() { return m_failedPaths.length(); }
|
qsizetype totalFailed() { return m_failedPaths.length(); }
|
||||||
QStringList failed() { return m_failedPaths; }
|
QStringList failed() { return m_failedPaths; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@ -128,9 +149,10 @@ class copy : public QObject {
|
|||||||
bool m_followSymlinks = true;
|
bool m_followSymlinks = true;
|
||||||
const IPathMatcher* m_matcher = nullptr;
|
const IPathMatcher* m_matcher = nullptr;
|
||||||
bool m_whitelist = false;
|
bool m_whitelist = false;
|
||||||
|
bool m_overwrite = false;
|
||||||
QDir m_src;
|
QDir m_src;
|
||||||
QDir m_dst;
|
QDir m_dst;
|
||||||
int m_copied;
|
qsizetype m_copied;
|
||||||
QStringList m_failedPaths;
|
QStringList m_failedPaths;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -474,8 +496,8 @@ class clone : public QObject {
|
|||||||
|
|
||||||
bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
|
bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
|
||||||
|
|
||||||
int totalCloned() { return m_cloned; }
|
qsizetype totalCloned() { return m_cloned; }
|
||||||
int totalFailed() { return m_failedClones.length(); }
|
qsizetype totalFailed() { return m_failedClones.length(); }
|
||||||
|
|
||||||
QList<QPair<QString, QString>> failed() { return m_failedClones; }
|
QList<QPair<QString, QString>> failed() { return m_failedClones; }
|
||||||
|
|
||||||
@ -491,7 +513,7 @@ class clone : public QObject {
|
|||||||
bool m_whitelist = false;
|
bool m_whitelist = false;
|
||||||
QDir m_src;
|
QDir m_src;
|
||||||
QDir m_dst;
|
QDir m_dst;
|
||||||
int m_cloned;
|
qsizetype m_cloned;
|
||||||
QList<QPair<QString, QString>> m_failedClones;
|
QList<QPair<QString, QString>> m_failedClones;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -16,6 +16,12 @@ bool ExactFilter::accepts(const QString& value)
|
|||||||
return value == pattern;
|
return value == pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExactIfPresentFilter::ExactIfPresentFilter(const QString& pattern) : pattern(pattern) {}
|
||||||
|
bool ExactIfPresentFilter::accepts(const QString& value)
|
||||||
|
{
|
||||||
|
return value.isEmpty() || value == pattern;
|
||||||
|
}
|
||||||
|
|
||||||
RegexpFilter::RegexpFilter(const QString& regexp, bool invert) : invert(invert)
|
RegexpFilter::RegexpFilter(const QString& regexp, bool invert) : invert(invert)
|
||||||
{
|
{
|
||||||
pattern.setPattern(regexp);
|
pattern.setPattern(regexp);
|
||||||
|
@ -29,6 +29,16 @@ class ExactFilter : public Filter {
|
|||||||
QString pattern;
|
QString pattern;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ExactIfPresentFilter : public Filter {
|
||||||
|
public:
|
||||||
|
ExactIfPresentFilter(const QString& pattern);
|
||||||
|
~ExactIfPresentFilter() override = default;
|
||||||
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString pattern;
|
||||||
|
};
|
||||||
|
|
||||||
class RegexpFilter : public Filter {
|
class RegexpFilter : public Filter {
|
||||||
public:
|
public:
|
||||||
RegexpFilter(const QString& regexp, bool invert);
|
RegexpFilter(const QString& regexp, bool invert);
|
||||||
|
@ -43,10 +43,10 @@ void InstanceCopyTask::executeTask()
|
|||||||
QFileInfo dotMCDir(FS::PathCombine(m_stagingPath, ".minecraft"));
|
QFileInfo dotMCDir(FS::PathCombine(m_stagingPath, ".minecraft"));
|
||||||
|
|
||||||
QString staging_mc_dir;
|
QString staging_mc_dir;
|
||||||
if (mcDir.exists() && !dotMCDir.exists())
|
if (dotMCDir.exists() && !mcDir.exists())
|
||||||
staging_mc_dir = mcDir.filePath();
|
|
||||||
else
|
|
||||||
staging_mc_dir = dotMCDir.filePath();
|
staging_mc_dir = dotMCDir.filePath();
|
||||||
|
else
|
||||||
|
staging_mc_dir = mcDir.filePath();
|
||||||
|
|
||||||
FS::copy savesCopy(FS::PathCombine(m_origInstance->gameRoot(), "saves"), FS::PathCombine(staging_mc_dir, "saves"));
|
FS::copy savesCopy(FS::PathCombine(m_origInstance->gameRoot(), "saves"), FS::PathCombine(staging_mc_dir, "saves"));
|
||||||
savesCopy.followSymlinks(true);
|
savesCopy.followSymlinks(true);
|
||||||
@ -142,9 +142,8 @@ void InstanceCopyTask::copyFinished()
|
|||||||
if (!m_keepPlaytime) {
|
if (!m_keepPlaytime) {
|
||||||
inst->resetTimePlayed();
|
inst->resetTimePlayed();
|
||||||
}
|
}
|
||||||
if (m_useLinks)
|
|
||||||
inst->addLinkedInstanceId(m_origInstance->id());
|
|
||||||
if (m_useLinks) {
|
if (m_useLinks) {
|
||||||
|
inst->addLinkedInstanceId(m_origInstance->id());
|
||||||
auto allowed_symlinks_file = QFileInfo(FS::PathCombine(inst->gameRoot(), "allowed_symlinks.txt"));
|
auto allowed_symlinks_file = QFileInfo(FS::PathCombine(inst->gameRoot(), "allowed_symlinks.txt"));
|
||||||
|
|
||||||
QByteArray allowed_symlinks;
|
QByteArray allowed_symlinks;
|
||||||
|
@ -50,13 +50,16 @@
|
|||||||
#include "modplatform/technic/TechnicPackProcessor.h"
|
#include "modplatform/technic/TechnicPackProcessor.h"
|
||||||
|
|
||||||
#include "settings/INISettingsObject.h"
|
#include "settings/INISettingsObject.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
|
#include "net/ApiDownload.h"
|
||||||
|
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <quazip/quazipdir.h>
|
#include <quazip/quazipdir.h>
|
||||||
|
|
||||||
InstanceImportTask::InstanceImportTask(const QUrl sourceUrl, QWidget* parent, QMap<QString, QString>&& extra_info)
|
InstanceImportTask::InstanceImportTask(const QUrl& sourceUrl, QWidget* parent, QMap<QString, QString>&& extra_info)
|
||||||
: m_sourceUrl(sourceUrl), m_extra_info(extra_info), m_parent(parent)
|
: m_sourceUrl(sourceUrl), m_extra_info(extra_info), m_parent(parent)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -88,25 +91,27 @@ void InstanceImportTask::executeTask()
|
|||||||
setStatus(tr("Downloading modpack:\n%1").arg(m_sourceUrl.toString()));
|
setStatus(tr("Downloading modpack:\n%1").arg(m_sourceUrl.toString()));
|
||||||
m_downloadRequired = true;
|
m_downloadRequired = true;
|
||||||
|
|
||||||
const QString path(m_sourceUrl.host() + '/' + m_sourceUrl.path());
|
downloadFromUrl();
|
||||||
|
|
||||||
auto entry = APPLICATION->metacache()->resolveEntry("general", path);
|
|
||||||
entry->setStale(true);
|
|
||||||
m_archivePath = entry->getFullPath();
|
|
||||||
|
|
||||||
m_filesNetJob.reset(new NetJob(tr("Modpack download"), APPLICATION->network()));
|
|
||||||
m_filesNetJob->addNetAction(Net::Download::makeCached(m_sourceUrl, entry));
|
|
||||||
|
|
||||||
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded);
|
|
||||||
connect(m_filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged);
|
|
||||||
connect(m_filesNetJob.get(), &NetJob::stepProgress, this, &InstanceImportTask::propagateStepProgress);
|
|
||||||
connect(m_filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::downloadFailed);
|
|
||||||
connect(m_filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::downloadAborted);
|
|
||||||
|
|
||||||
m_filesNetJob->start();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InstanceImportTask::downloadFromUrl()
|
||||||
|
{
|
||||||
|
const QString path = m_sourceUrl.host() + '/' + m_sourceUrl.path();
|
||||||
|
auto entry = APPLICATION->metacache()->resolveEntry("general", path);
|
||||||
|
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();
|
||||||
|
|
||||||
|
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded);
|
||||||
|
connect(m_filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged);
|
||||||
|
connect(m_filesNetJob.get(), &NetJob::stepProgress, this, &InstanceImportTask::propagateStepProgress);
|
||||||
|
connect(m_filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::downloadFailed);
|
||||||
|
connect(m_filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::downloadAborted);
|
||||||
|
m_filesNetJob->start();
|
||||||
|
}
|
||||||
|
|
||||||
void InstanceImportTask::downloadSucceeded()
|
void InstanceImportTask::downloadSucceeded()
|
||||||
{
|
{
|
||||||
processZipPack();
|
processZipPack();
|
||||||
@ -159,8 +164,8 @@ void InstanceImportTask::processZipPack()
|
|||||||
} else if (technicFound) {
|
} else if (technicFound) {
|
||||||
// process as Technic pack
|
// process as Technic pack
|
||||||
qDebug() << "Technic:" << technicFound;
|
qDebug() << "Technic:" << technicFound;
|
||||||
extractDir.mkpath(".minecraft");
|
extractDir.mkpath("minecraft");
|
||||||
extractDir.cd(".minecraft");
|
extractDir.cd("minecraft");
|
||||||
m_modpackType = ModpackType::Technic;
|
m_modpackType = ModpackType::Technic;
|
||||||
} else {
|
} else {
|
||||||
QStringList paths_to_ignore{ "overrides/" };
|
QStringList paths_to_ignore{ "overrides/" };
|
||||||
|
@ -54,7 +54,7 @@ class FileResolvingTask;
|
|||||||
class InstanceImportTask : public InstanceTask {
|
class InstanceImportTask : public InstanceTask {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
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; }
|
const QVector<Flame::File>& getBlockedFiles() const { return m_blockedMods; }
|
||||||
@ -101,4 +101,5 @@ class InstanceImportTask : public InstanceTask {
|
|||||||
|
|
||||||
// FIXME: nuke
|
// FIXME: nuke
|
||||||
QWidget* m_parent;
|
QWidget* m_parent;
|
||||||
|
void downloadFromUrl();
|
||||||
};
|
};
|
||||||
|
@ -2,6 +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 TheKodeToad <TheKodeToad@proton.me>
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -96,7 +97,11 @@ Qt::DropActions InstanceList::supportedDropActions() const
|
|||||||
return Qt::MoveAction;
|
return Qt::MoveAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstanceList::canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const
|
bool InstanceList::canDropMimeData(const QMimeData* data,
|
||||||
|
[[maybe_unused]] Qt::DropAction action,
|
||||||
|
[[maybe_unused]] int row,
|
||||||
|
[[maybe_unused]] int column,
|
||||||
|
[[maybe_unused]] const QModelIndex& parent) const
|
||||||
{
|
{
|
||||||
if (data && data->hasFormat("application/x-instanceid")) {
|
if (data && data->hasFormat("application/x-instanceid")) {
|
||||||
return true;
|
return true;
|
||||||
@ -104,7 +109,11 @@ bool InstanceList::canDropMimeData(const QMimeData* data, Qt::DropAction action,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstanceList::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent)
|
bool InstanceList::dropMimeData(const QMimeData* data,
|
||||||
|
[[maybe_unused]] Qt::DropAction action,
|
||||||
|
[[maybe_unused]] int row,
|
||||||
|
[[maybe_unused]] int column,
|
||||||
|
[[maybe_unused]] const QModelIndex& parent)
|
||||||
{
|
{
|
||||||
if (data && data->hasFormat("application/x-instanceid")) {
|
if (data && data->hasFormat("application/x-instanceid")) {
|
||||||
return true;
|
return true;
|
||||||
@ -229,8 +238,11 @@ GroupId InstanceList::getInstanceGroup(const InstanceId& id) const
|
|||||||
return GroupId();
|
return GroupId();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceList::setInstanceGroup(const InstanceId& id, const GroupId& name)
|
void InstanceList::setInstanceGroup(const InstanceId& id, GroupId name)
|
||||||
{
|
{
|
||||||
|
if (name.isEmpty() && !name.isNull())
|
||||||
|
name = QString();
|
||||||
|
|
||||||
auto inst = getInstanceById(id);
|
auto inst = getInstanceById(id);
|
||||||
if (!inst) {
|
if (!inst) {
|
||||||
qDebug() << "Attempt to set a null instance's group";
|
qDebug() << "Attempt to set a null instance's group";
|
||||||
@ -241,6 +253,7 @@ void InstanceList::setInstanceGroup(const InstanceId& id, const GroupId& name)
|
|||||||
auto iter = m_instanceGroupIndex.find(inst->id());
|
auto iter = m_instanceGroupIndex.find(inst->id());
|
||||||
if (iter != m_instanceGroupIndex.end()) {
|
if (iter != m_instanceGroupIndex.end()) {
|
||||||
if (*iter != name) {
|
if (*iter != name) {
|
||||||
|
decreaseGroupCount(*iter);
|
||||||
*iter = name;
|
*iter = name;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
@ -250,7 +263,7 @@ void InstanceList::setInstanceGroup(const InstanceId& id, const GroupId& name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
m_groupNameCache.insert(name);
|
increaseGroupCount(name);
|
||||||
auto idx = getInstIndex(inst.get());
|
auto idx = getInstIndex(inst.get());
|
||||||
emit dataChanged(index(idx), index(idx), { GroupRole });
|
emit dataChanged(index(idx), index(idx), { GroupRole });
|
||||||
saveGroupList();
|
saveGroupList();
|
||||||
@ -259,29 +272,55 @@ void InstanceList::setInstanceGroup(const InstanceId& id, const GroupId& name)
|
|||||||
|
|
||||||
QStringList InstanceList::getGroups()
|
QStringList InstanceList::getGroups()
|
||||||
{
|
{
|
||||||
return m_groupNameCache.values();
|
return m_groupNameCache.keys();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceList::deleteGroup(const QString& name)
|
void InstanceList::deleteGroup(const GroupId& name)
|
||||||
{
|
{
|
||||||
|
m_groupNameCache.remove(name);
|
||||||
|
m_collapsedGroups.remove(name);
|
||||||
|
|
||||||
bool removed = false;
|
bool removed = false;
|
||||||
qDebug() << "Delete group" << name;
|
qDebug() << "Delete group" << name;
|
||||||
for (auto& instance : m_instances) {
|
for (auto& instance : m_instances) {
|
||||||
const auto& instID = instance->id();
|
const QString& instID = instance->id();
|
||||||
auto instGroupName = getInstanceGroup(instID);
|
const QString instGroupName = getInstanceGroup(instID);
|
||||||
if (instGroupName == name) {
|
if (instGroupName == name) {
|
||||||
m_instanceGroupIndex.remove(instID);
|
m_instanceGroupIndex.remove(instID);
|
||||||
qDebug() << "Remove" << instID << "from group" << name;
|
qDebug() << "Remove" << instID << "from group" << name;
|
||||||
removed = true;
|
removed = true;
|
||||||
auto idx = getInstIndex(instance.get());
|
auto idx = getInstIndex(instance.get());
|
||||||
if (idx > 0) {
|
if (idx >= 0)
|
||||||
emit dataChanged(index(idx), index(idx), { GroupRole });
|
emit dataChanged(index(idx), index(idx), { GroupRole });
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (removed) {
|
if (removed)
|
||||||
saveGroupList();
|
saveGroupList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstanceList::renameGroup(const QString& src, const QString& dst)
|
||||||
|
{
|
||||||
|
m_groupNameCache.remove(src);
|
||||||
|
if (m_collapsedGroups.remove(src))
|
||||||
|
m_collapsedGroups.insert(dst);
|
||||||
|
|
||||||
|
bool modified = false;
|
||||||
|
qDebug() << "Rename group" << src << "to" << dst;
|
||||||
|
for (auto& instance : m_instances) {
|
||||||
|
const QString& instID = instance->id();
|
||||||
|
const QString instGroupName = getInstanceGroup(instID);
|
||||||
|
if (instGroupName == src) {
|
||||||
|
m_instanceGroupIndex[instID] = dst;
|
||||||
|
increaseGroupCount(dst);
|
||||||
|
qDebug() << "Set" << instID << "group to" << dst;
|
||||||
|
modified = true;
|
||||||
|
auto idx = getInstIndex(instance.get());
|
||||||
|
if (idx >= 0)
|
||||||
|
emit dataChanged(index(idx), index(idx), { GroupRole });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (modified)
|
||||||
|
saveGroupList();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstanceList::isGroupCollapsed(const QString& group)
|
bool InstanceList::isGroupCollapsed(const QString& group)
|
||||||
@ -297,12 +336,13 @@ bool InstanceList::trashInstance(const InstanceId& id)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cachedGroupId = m_instanceGroupIndex[id];
|
QString cachedGroupId = m_instanceGroupIndex[id];
|
||||||
|
|
||||||
qDebug() << "Will trash instance" << id;
|
qDebug() << "Will trash instance" << id;
|
||||||
QString trashedLoc;
|
QString trashedLoc;
|
||||||
|
|
||||||
if (m_instanceGroupIndex.remove(id)) {
|
if (m_instanceGroupIndex.remove(id)) {
|
||||||
|
decreaseGroupCount(cachedGroupId);
|
||||||
saveGroupList();
|
saveGroupList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,7 +380,7 @@ void InstanceList::undoTrashInstance()
|
|||||||
QFile(top.trashPath).rename(top.polyPath);
|
QFile(top.trashPath).rename(top.polyPath);
|
||||||
|
|
||||||
m_instanceGroupIndex[top.id] = top.groupName;
|
m_instanceGroupIndex[top.id] = top.groupName;
|
||||||
m_groupNameCache.insert(top.groupName);
|
increaseGroupCount(top.groupName);
|
||||||
|
|
||||||
saveGroupList();
|
saveGroupList();
|
||||||
emit instancesChanged();
|
emit instancesChanged();
|
||||||
@ -354,7 +394,10 @@ void InstanceList::deleteInstance(const InstanceId& id)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString cachedGroupId = m_instanceGroupIndex[id];
|
||||||
|
|
||||||
if (m_instanceGroupIndex.remove(id)) {
|
if (m_instanceGroupIndex.remove(id)) {
|
||||||
|
decreaseGroupCount(cachedGroupId);
|
||||||
saveGroupList();
|
saveGroupList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -602,6 +645,25 @@ InstancePtr InstanceList::loadInstance(const InstanceId& id)
|
|||||||
return inst;
|
return inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InstanceList::increaseGroupCount(const QString& group)
|
||||||
|
{
|
||||||
|
if (group.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
++m_groupNameCache[group];
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstanceList::decreaseGroupCount(const QString& group)
|
||||||
|
{
|
||||||
|
if (group.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (--m_groupNameCache[group] < 1) {
|
||||||
|
m_groupNameCache.remove(group);
|
||||||
|
m_collapsedGroups.remove(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void InstanceList::saveGroupList()
|
void InstanceList::saveGroupList()
|
||||||
{
|
{
|
||||||
qDebug() << "Will save group list now.";
|
qDebug() << "Will save group list now.";
|
||||||
@ -613,7 +675,7 @@ void InstanceList::saveGroupList()
|
|||||||
QString groupFileName = m_instDir + "/instgroups.json";
|
QString groupFileName = m_instDir + "/instgroups.json";
|
||||||
QMap<QString, QSet<QString>> reverseGroupMap;
|
QMap<QString, QSet<QString>> reverseGroupMap;
|
||||||
for (auto iter = m_instanceGroupIndex.begin(); iter != m_instanceGroupIndex.end(); iter++) {
|
for (auto iter = m_instanceGroupIndex.begin(); iter != m_instanceGroupIndex.end(); iter++) {
|
||||||
QString id = iter.key();
|
const QString& id = iter.key();
|
||||||
QString group = iter.value();
|
QString group = iter.value();
|
||||||
if (group.isEmpty())
|
if (group.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
@ -703,17 +765,22 @@ void InstanceList::loadGroupList()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSet<QString> groupSet;
|
|
||||||
m_instanceGroupIndex.clear();
|
m_instanceGroupIndex.clear();
|
||||||
|
m_groupNameCache.clear();
|
||||||
|
|
||||||
// Iterate through all the groups.
|
// Iterate through all the groups.
|
||||||
QJsonObject groupMapping = rootObj.value("groups").toObject();
|
QJsonObject groupMapping = rootObj.value("groups").toObject();
|
||||||
for (QJsonObject::iterator iter = groupMapping.begin(); iter != groupMapping.end(); iter++) {
|
for (QJsonObject::iterator iter = groupMapping.begin(); iter != groupMapping.end(); iter++) {
|
||||||
QString groupName = iter.key();
|
QString groupName = iter.key();
|
||||||
|
|
||||||
|
if (iter.key().isEmpty()) {
|
||||||
|
qWarning() << "Redundant empty group found";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// If not an object, complain and skip to the next one.
|
// If not an object, complain and skip to the next one.
|
||||||
if (!iter.value().isObject()) {
|
if (!iter.value().isObject()) {
|
||||||
qWarning() << QString("Group '%1' in the group list should be an object.").arg(groupName).toUtf8();
|
qWarning() << QString("Group '%1' in the group list should be an object").arg(groupName).toUtf8();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -725,23 +792,19 @@ void InstanceList::loadGroupList()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// keep a list/set of groups for choosing
|
|
||||||
groupSet.insert(groupName);
|
|
||||||
|
|
||||||
auto hidden = groupObj.value("hidden").toBool(false);
|
auto hidden = groupObj.value("hidden").toBool(false);
|
||||||
if (hidden) {
|
if (hidden)
|
||||||
m_collapsedGroups.insert(groupName);
|
m_collapsedGroups.insert(groupName);
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate through the list of instances in the group.
|
// Iterate through the list of instances in the group.
|
||||||
QJsonArray instancesArray = groupObj.value("instances").toArray();
|
QJsonArray instancesArray = groupObj.value("instances").toArray();
|
||||||
|
|
||||||
for (QJsonArray::iterator iter2 = instancesArray.begin(); iter2 != instancesArray.end(); iter2++) {
|
for (auto value : instancesArray) {
|
||||||
m_instanceGroupIndex[(*iter2).toString()] = groupName;
|
m_instanceGroupIndex[value.toString()] = groupName;
|
||||||
|
increaseGroupCount(groupName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_groupsLoaded = true;
|
m_groupsLoaded = true;
|
||||||
m_groupNameCache.unite(groupSet);
|
|
||||||
qDebug() << "Group list loaded.";
|
qDebug() << "Group list loaded.";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -751,7 +814,7 @@ void InstanceList::instanceDirContentsChanged(const QString& path)
|
|||||||
emit instancesChanged();
|
emit instancesChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceList::on_InstFolderChanged(const Setting& setting, QVariant value)
|
void InstanceList::on_InstFolderChanged([[maybe_unused]] const Setting& setting, QVariant value)
|
||||||
{
|
{
|
||||||
QString newInstDir = QDir(value.toString()).canonicalPath();
|
QString newInstDir = QDir(value.toString()).canonicalPath();
|
||||||
if (newInstDir != m_instDir) {
|
if (newInstDir != m_instDir) {
|
||||||
@ -760,6 +823,9 @@ void InstanceList::on_InstFolderChanged(const Setting& setting, QVariant value)
|
|||||||
}
|
}
|
||||||
m_instDir = newInstDir;
|
m_instDir = newInstDir;
|
||||||
m_groupsLoaded = false;
|
m_groupsLoaded = false;
|
||||||
|
beginRemoveRows(QModelIndex(), 0, count());
|
||||||
|
m_instances.erase(m_instances.begin(), m_instances.end());
|
||||||
|
endRemoveRows();
|
||||||
emit instancesChanged();
|
emit instancesChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -789,7 +855,7 @@ class InstanceStaging : public Task {
|
|||||||
, m_groupName(std::move(groupName))
|
, m_groupName(std::move(groupName))
|
||||||
{
|
{
|
||||||
m_child.reset(child);
|
m_child.reset(child);
|
||||||
connect(child, &Task::succeeded, this, &InstanceStaging::childSucceded);
|
connect(child, &Task::succeeded, this, &InstanceStaging::childSucceeded);
|
||||||
connect(child, &Task::failed, this, &InstanceStaging::childFailed);
|
connect(child, &Task::failed, this, &InstanceStaging::childFailed);
|
||||||
connect(child, &Task::aborted, this, &InstanceStaging::childAborted);
|
connect(child, &Task::aborted, this, &InstanceStaging::childAborted);
|
||||||
connect(child, &Task::abortStatusChanged, this, &InstanceStaging::setAbortable);
|
connect(child, &Task::abortStatusChanged, this, &InstanceStaging::setAbortable);
|
||||||
@ -797,7 +863,7 @@ class InstanceStaging : public Task {
|
|||||||
connect(child, &Task::details, this, &InstanceStaging::setDetails);
|
connect(child, &Task::details, this, &InstanceStaging::setDetails);
|
||||||
connect(child, &Task::progress, this, &InstanceStaging::setProgress);
|
connect(child, &Task::progress, this, &InstanceStaging::setProgress);
|
||||||
connect(child, &Task::stepProgress, this, &InstanceStaging::propagateStepProgress);
|
connect(child, &Task::stepProgress, this, &InstanceStaging::propagateStepProgress);
|
||||||
connect(&m_backoffTimer, &QTimer::timeout, this, &InstanceStaging::childSucceded);
|
connect(&m_backoffTimer, &QTimer::timeout, this, &InstanceStaging::childSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~InstanceStaging(){};
|
virtual ~InstanceStaging(){};
|
||||||
@ -819,7 +885,7 @@ class InstanceStaging : public Task {
|
|||||||
QStringList warnings() const override { return m_child->warnings(); }
|
QStringList warnings() const override { return m_child->warnings(); }
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void childSucceded()
|
void childSucceeded()
|
||||||
{
|
{
|
||||||
unsigned sleepTime = backoff();
|
unsigned sleepTime = backoff();
|
||||||
if (m_parent->commitStagedInstance(m_stagingPath, m_instance_name, m_groupName, *m_child.get())) {
|
if (m_parent->commitStagedInstance(m_stagingPath, m_instance_name, m_groupName, *m_child.get())) {
|
||||||
@ -884,9 +950,12 @@ QString InstanceList::getStagedInstancePath()
|
|||||||
|
|
||||||
bool InstanceList::commitStagedInstance(const QString& path,
|
bool InstanceList::commitStagedInstance(const QString& path,
|
||||||
InstanceName const& instanceName,
|
InstanceName const& instanceName,
|
||||||
const QString& groupName,
|
QString groupName,
|
||||||
InstanceTask const& commiting)
|
InstanceTask const& commiting)
|
||||||
{
|
{
|
||||||
|
if (groupName.isEmpty() && !groupName.isNull())
|
||||||
|
groupName = QString();
|
||||||
|
|
||||||
QDir dir;
|
QDir dir;
|
||||||
QString instID;
|
QString instID;
|
||||||
InstancePtr inst;
|
InstancePtr inst;
|
||||||
@ -917,7 +986,7 @@ bool InstanceList::commitStagedInstance(const QString& path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_instanceGroupIndex[instID] = groupName;
|
m_instanceGroupIndex[instID] = groupName;
|
||||||
m_groupNameCache.insert(groupName);
|
increaseGroupCount(groupName);
|
||||||
}
|
}
|
||||||
|
|
||||||
instanceSet.insert(instID);
|
instanceSet.insert(instID);
|
||||||
|
@ -1,16 +1,36 @@
|
|||||||
/* Copyright 2013-2021 MultiMC Contributors
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* you may not use this file except in compliance with the License.
|
* it under the terms of the GNU General Public License as published by
|
||||||
* You may obtain a copy of the License at
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* 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.
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* You should have received a copy of the GNU General Public License
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
*
|
||||||
* See the License for the specific language governing permissions and
|
* This file incorporates work covered by the following copyright and
|
||||||
* limitations under the License.
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -86,9 +106,10 @@ class InstanceList : public QAbstractListModel {
|
|||||||
bool isGroupCollapsed(const QString& groupName);
|
bool isGroupCollapsed(const QString& groupName);
|
||||||
|
|
||||||
GroupId getInstanceGroup(const InstanceId& id) const;
|
GroupId getInstanceGroup(const InstanceId& id) const;
|
||||||
void setInstanceGroup(const InstanceId& id, const GroupId& name);
|
void setInstanceGroup(const InstanceId& id, GroupId name);
|
||||||
|
|
||||||
void deleteGroup(const GroupId& name);
|
void deleteGroup(const GroupId& name);
|
||||||
|
void renameGroup(const GroupId& src, const GroupId& dst);
|
||||||
bool trashInstance(const InstanceId& id);
|
bool trashInstance(const InstanceId& id);
|
||||||
bool trashedSomething();
|
bool trashedSomething();
|
||||||
void undoTrashInstance();
|
void undoTrashInstance();
|
||||||
@ -109,7 +130,7 @@ class InstanceList : public QAbstractListModel {
|
|||||||
* should_override is used when another similar instance already exists, and we want to override it
|
* should_override is used when another similar instance already exists, and we want to override it
|
||||||
* - for instance, when updating it.
|
* - for instance, when updating it.
|
||||||
*/
|
*/
|
||||||
bool commitStagedInstance(const QString& keyPath, const InstanceName& instanceName, const QString& groupName, const InstanceTask&);
|
bool commitStagedInstance(const QString& keyPath, const InstanceName& instanceName, QString groupName, const InstanceTask&);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy a previously created staging area given by @keyPath - used when creation fails.
|
* Destroy a previously created staging area given by @keyPath - used when creation fails.
|
||||||
@ -158,12 +179,16 @@ class InstanceList : public QAbstractListModel {
|
|||||||
QList<InstanceId> discoverInstances();
|
QList<InstanceId> discoverInstances();
|
||||||
InstancePtr loadInstance(const InstanceId& id);
|
InstancePtr loadInstance(const InstanceId& id);
|
||||||
|
|
||||||
|
void increaseGroupCount(const QString& group);
|
||||||
|
void decreaseGroupCount(const QString& group);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_watchLevel = 0;
|
int m_watchLevel = 0;
|
||||||
int totalPlayTime = 0;
|
int totalPlayTime = 0;
|
||||||
bool m_dirty = false;
|
bool m_dirty = false;
|
||||||
QList<InstancePtr> m_instances;
|
QList<InstancePtr> m_instances;
|
||||||
QSet<QString> m_groupNameCache;
|
// id -> refs
|
||||||
|
QMap<QString, int> m_groupNameCache;
|
||||||
|
|
||||||
SettingsObjectPtr m_globalSettings;
|
SettingsObjectPtr m_globalSettings;
|
||||||
QString m_instDir;
|
QString m_instDir;
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
|
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& old_name, const QString& new_name)
|
InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& old_name, const QString& new_name)
|
||||||
{
|
{
|
||||||
auto dialog =
|
auto dialog =
|
||||||
@ -27,16 +29,15 @@ ShouldUpdate askIfShouldUpdate(QWidget* parent, QString original_version_name)
|
|||||||
"separate instance, or update the existing one?\n\nNOTE: Make sure you made a backup of your important instance data before "
|
"separate instance, or update the existing one?\n\nNOTE: Make sure you made a backup of your important instance data before "
|
||||||
"updating, as worlds can be corrupted and some configuration may be lost (due to pack overrides).")
|
"updating, as worlds can be corrupted and some configuration may be lost (due to pack overrides).")
|
||||||
.arg(original_version_name),
|
.arg(original_version_name),
|
||||||
QMessageBox::Information, QMessageBox::Ok | QMessageBox::Reset | QMessageBox::Abort);
|
QMessageBox::Information, QMessageBox::Cancel);
|
||||||
info->setButtonText(QMessageBox::Ok, QObject::tr("Update existing instance"));
|
QAbstractButton* update = info->addButton(QObject::tr("Update existing instance"), QMessageBox::AcceptRole);
|
||||||
info->setButtonText(QMessageBox::Abort, QObject::tr("Create new instance"));
|
QAbstractButton* skip = info->addButton(QObject::tr("Create new instance"), QMessageBox::ResetRole);
|
||||||
info->setButtonText(QMessageBox::Reset, QObject::tr("Cancel"));
|
|
||||||
|
|
||||||
info->exec();
|
info->exec();
|
||||||
|
|
||||||
if (info->clickedButton() == info->button(QMessageBox::Ok))
|
if (info->clickedButton() == update)
|
||||||
return ShouldUpdate::Update;
|
return ShouldUpdate::Update;
|
||||||
if (info->clickedButton() == info->button(QMessageBox::Abort))
|
if (info->clickedButton() == skip)
|
||||||
return ShouldUpdate::SkipUpdating;
|
return ShouldUpdate::SkipUpdating;
|
||||||
return ShouldUpdate::Cancel;
|
return ShouldUpdate::Cancel;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +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 TheKodeToad <TheKodeToad@proton.me>
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -35,12 +36,12 @@
|
|||||||
|
|
||||||
#include "LaunchController.h"
|
#include "LaunchController.h"
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
#include "minecraft/auth/AccountData.h"
|
||||||
#include "minecraft/auth/AccountList.h"
|
#include "minecraft/auth/AccountList.h"
|
||||||
|
|
||||||
#include "ui/InstanceWindow.h"
|
#include "ui/InstanceWindow.h"
|
||||||
#include "ui/MainWindow.h"
|
#include "ui/MainWindow.h"
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
#include "ui/dialogs/EditAccountDialog.h"
|
|
||||||
#include "ui/dialogs/ProfileSelectDialog.h"
|
#include "ui/dialogs/ProfileSelectDialog.h"
|
||||||
#include "ui/dialogs/ProfileSetupDialog.h"
|
#include "ui/dialogs/ProfileSetupDialog.h"
|
||||||
#include "ui/dialogs/ProgressDialog.h"
|
#include "ui/dialogs/ProgressDialog.h"
|
||||||
@ -87,8 +88,8 @@ void LaunchController::decideAccount()
|
|||||||
if (accounts->count() <= 0) {
|
if (accounts->count() <= 0) {
|
||||||
// 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 have at least one Microsoft or Mojang "
|
tr("In order to play Minecraft, you must have at least one Microsoft "
|
||||||
"account logged in. Mojang accounts can only be used offline. "
|
"account which owns Minecraft logged in. "
|
||||||
"Would you like to open the account manager to add an account now?"),
|
"Would you like to open the account manager to add an account now?"),
|
||||||
QMessageBox::Information, QMessageBox::Yes | QMessageBox::No)
|
QMessageBox::Information, QMessageBox::Yes | QMessageBox::No)
|
||||||
->exec();
|
->exec();
|
||||||
@ -105,7 +106,7 @@ void LaunchController::decideAccount()
|
|||||||
// Select the account to use. If the instance has a specific account set, that will be used. Otherwise, the default account will be used
|
// Select the account to use. If the instance has a specific account set, that will be used. Otherwise, the default account will be used
|
||||||
auto instanceAccountId = m_instance->settings()->get("InstanceAccountId").toString();
|
auto instanceAccountId = m_instance->settings()->get("InstanceAccountId").toString();
|
||||||
auto instanceAccountIndex = accounts->findAccountByProfileId(instanceAccountId);
|
auto instanceAccountIndex = accounts->findAccountByProfileId(instanceAccountId);
|
||||||
if (instanceAccountIndex == -1) {
|
if (instanceAccountIndex == -1 || instanceAccountId.isEmpty()) {
|
||||||
m_accountToUse = accounts->defaultAccount();
|
m_accountToUse = accounts->defaultAccount();
|
||||||
} else {
|
} else {
|
||||||
m_accountToUse = accounts->at(instanceAccountIndex);
|
m_accountToUse = accounts->at(instanceAccountIndex);
|
||||||
@ -142,6 +143,12 @@ void LaunchController::login()
|
|||||||
bool tryagain = true;
|
bool tryagain = true;
|
||||||
unsigned int tries = 0;
|
unsigned int tries = 0;
|
||||||
|
|
||||||
|
if (m_accountToUse->accountType() != AccountType::Offline && m_accountToUse->accountState() == AccountState::Offline) {
|
||||||
|
// Force account refresh on the account used to launch the instance updating the AccountState
|
||||||
|
// only on first try and if it is not meant to be offline
|
||||||
|
auto accounts = APPLICATION->accounts();
|
||||||
|
accounts->requestRefresh(m_accountToUse->internalId());
|
||||||
|
}
|
||||||
while (tryagain) {
|
while (tryagain) {
|
||||||
if (tries > 0 && tries % 3 == 0) {
|
if (tries > 0 && tries % 3 == 0) {
|
||||||
auto result =
|
auto result =
|
||||||
@ -160,7 +167,7 @@ void LaunchController::login()
|
|||||||
m_accountToUse->fillSession(m_session);
|
m_accountToUse->fillSession(m_session);
|
||||||
|
|
||||||
// Launch immediately in true offline mode
|
// Launch immediately in true offline mode
|
||||||
if (m_accountToUse->isOffline()) {
|
if (m_accountToUse->accountType() == AccountType::Offline) {
|
||||||
launchInstance();
|
launchInstance();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -248,12 +255,6 @@ void LaunchController::login()
|
|||||||
progDialog.execWithTask(task.get());
|
progDialog.execWithTask(task.get());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// FIXME: this is missing - the meaning is that the account is queued for refresh and we should wait for that
|
|
||||||
/*
|
|
||||||
case AccountState::Queued: {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
case AccountState::Expired: {
|
case AccountState::Expired: {
|
||||||
auto errorString = tr("The account has expired and needs to be logged into manually again.");
|
auto errorString = tr("The account has expired and needs to be logged into manually again.");
|
||||||
QMessageBox::warning(m_parentWidget, tr("Account refresh failed"), errorString, QMessageBox::StandardButton::Ok,
|
QMessageBox::warning(m_parentWidget, tr("Account refresh failed"), errorString, QMessageBox::StandardButton::Ok,
|
||||||
@ -361,22 +362,21 @@ void LaunchController::readyForLaunch()
|
|||||||
QString error;
|
QString error;
|
||||||
if (!m_profiler->check(&error)) {
|
if (!m_profiler->check(&error)) {
|
||||||
m_launcher->abort();
|
m_launcher->abort();
|
||||||
QMessageBox::critical(m_parentWidget, tr("Error!"), tr("Couldn't start profiler: %1").arg(error));
|
|
||||||
emitFailed("Profiler startup failed!");
|
emitFailed("Profiler startup failed!");
|
||||||
|
QMessageBox::critical(m_parentWidget, tr("Error!"), tr("Profiler check for %1 failed: %2").arg(m_profiler->name(), error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BaseProfiler* profilerInstance = m_profiler->createProfiler(m_launcher->instance(), this);
|
BaseProfiler* profilerInstance = m_profiler->createProfiler(m_launcher->instance(), this);
|
||||||
|
|
||||||
connect(profilerInstance, &BaseProfiler::readyToLaunch, [this](const QString& message) {
|
connect(profilerInstance, &BaseProfiler::readyToLaunch, [this](const QString& message) {
|
||||||
QMessageBox msg;
|
QMessageBox msg(m_parentWidget);
|
||||||
msg.setText(tr("The game launch is delayed until you press the "
|
msg.setText(tr("The game launch is delayed until you press the "
|
||||||
"button. This is the right time to setup the profiler, as the "
|
"button. This is the right time to setup the profiler, as the "
|
||||||
"profiler server is running now.\n\n%1")
|
"profiler server is running now.\n\n%1")
|
||||||
.arg(message));
|
.arg(message));
|
||||||
msg.setWindowTitle(tr("Waiting."));
|
msg.setWindowTitle(tr("Waiting."));
|
||||||
msg.setIcon(QMessageBox::Information);
|
msg.setIcon(QMessageBox::Information);
|
||||||
msg.addButton(tr("Launch"), QMessageBox::AcceptRole);
|
msg.addButton(tr("&Launch"), QMessageBox::AcceptRole);
|
||||||
msg.setModal(true);
|
|
||||||
msg.exec();
|
msg.exec();
|
||||||
m_launcher->proceed();
|
m_launcher->proceed();
|
||||||
});
|
});
|
||||||
|
@ -65,14 +65,9 @@ QStringList LoggedProcess::reprocess(const QByteArray& data, QTextDecoder& decod
|
|||||||
m_leftover_line = "";
|
m_leftover_line = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
auto lines = str.remove(QChar::CarriageReturn).split(QChar::LineFeed);
|
||||||
auto lines = str.remove(QChar::CarriageReturn).split(QChar::LineFeed, QString::SkipEmptyParts);
|
|
||||||
#else
|
|
||||||
auto lines = str.remove(QChar::CarriageReturn).split(QChar::LineFeed, Qt::SkipEmptyParts);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!str.endsWith(QChar::LineFeed))
|
m_leftover_line = lines.takeLast();
|
||||||
m_leftover_line = lines.takeLast();
|
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,19 +16,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <MMCTime.h>
|
#include <MMCTime.h>
|
||||||
|
#include <qobject.h>
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
|
||||||
QString Time::prettifyDuration(int64_t duration)
|
QString Time::prettifyDuration(int64_t duration, bool noDays)
|
||||||
{
|
{
|
||||||
int seconds = (int)(duration % 60);
|
int seconds = (int)(duration % 60);
|
||||||
duration /= 60;
|
duration /= 60;
|
||||||
int minutes = (int)(duration % 60);
|
int minutes = (int)(duration % 60);
|
||||||
duration /= 60;
|
duration /= 60;
|
||||||
int hours = (int)(duration % 24);
|
int hours = (int)(noDays ? duration : (duration % 24));
|
||||||
int days = (int)(duration / 24);
|
int days = (int)(noDays ? 0 : (duration / 24));
|
||||||
if ((hours == 0) && (days == 0)) {
|
if ((hours == 0) && (days == 0)) {
|
||||||
return QObject::tr("%1min %2s").arg(minutes).arg(seconds);
|
return QObject::tr("%1min %2s").arg(minutes).arg(seconds);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
namespace Time {
|
namespace Time {
|
||||||
|
|
||||||
QString prettifyDuration(int64_t duration);
|
QString prettifyDuration(int64_t duration, bool noDays = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns a string with short form time duration ie. `2days 1h3m4s56.0ms`.
|
* @brief Returns a string with short form time duration ie. `2days 1h3m4s56.0ms`.
|
||||||
|
@ -42,11 +42,15 @@
|
|||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
#if defined(LAUNCHER_APPLICATION)
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace MMCZip {
|
namespace MMCZip {
|
||||||
// ours
|
// ours
|
||||||
bool mergeZipFiles(QuaZip* into, QFileInfo from, QSet<QString>& contained, const FilterFunction filter)
|
bool mergeZipFiles(QuaZip* into, QFileInfo from, QSet<QString>& contained, const FilterFunction& filter)
|
||||||
{
|
{
|
||||||
QuaZip modZip(from.filePath());
|
QuaZip modZip(from.filePath());
|
||||||
modZip.open(QuaZip::mdUnzip);
|
modZip.open(QuaZip::mdUnzip);
|
||||||
@ -132,6 +136,7 @@ bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(LAUNCHER_APPLICATION)
|
||||||
// ours
|
// ours
|
||||||
bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod*>& mods)
|
bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod*>& mods)
|
||||||
{
|
{
|
||||||
@ -217,6 +222,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// ours
|
// ours
|
||||||
QString findFolderOfFileInZip(QuaZip* zip, const QString& what, const QStringList& ignore_paths, const QString& root)
|
QString findFolderOfFileInZip(QuaZip* zip, const QString& what, const QStringList& ignore_paths, const QString& root)
|
||||||
@ -422,6 +428,7 @@ bool collectFileListRecursively(const QString& rootDir, const QString& subDir, Q
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(LAUNCHER_APPLICATION)
|
||||||
void ExportToZipTask::executeTask()
|
void ExportToZipTask::executeTask()
|
||||||
{
|
{
|
||||||
setStatus("Adding files...");
|
setStatus("Adding files...");
|
||||||
@ -500,5 +507,6 @@ bool ExportToZipTask::abort()
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace MMCZip
|
} // namespace MMCZip
|
||||||
|
@ -48,7 +48,10 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
#if defined(LAUNCHER_APPLICATION)
|
||||||
#include "minecraft/mod/Mod.h"
|
#include "minecraft/mod/Mod.h"
|
||||||
|
#endif
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
namespace MMCZip {
|
namespace MMCZip {
|
||||||
@ -57,7 +60,7 @@ using FilterFunction = std::function<bool(const QString&)>;
|
|||||||
/**
|
/**
|
||||||
* Merge two zip files, using a filter function
|
* Merge two zip files, using a filter function
|
||||||
*/
|
*/
|
||||||
bool mergeZipFiles(QuaZip* into, QFileInfo from, QSet<QString>& contained, const FilterFunction filter = nullptr);
|
bool mergeZipFiles(QuaZip* into, QFileInfo from, QSet<QString>& contained, const FilterFunction& filter = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compress directory, by providing a list of files to compress
|
* Compress directory, by providing a list of files to compress
|
||||||
@ -79,11 +82,12 @@ bool compressDirFiles(QuaZip* zip, QString dir, QFileInfoList files, bool follow
|
|||||||
*/
|
*/
|
||||||
bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files, bool followSymlinks = false);
|
bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files, bool followSymlinks = false);
|
||||||
|
|
||||||
|
#if defined(LAUNCHER_APPLICATION)
|
||||||
/**
|
/**
|
||||||
* take a source jar, add mods to it, resulting in target jar
|
* take a source jar, add mods to it, resulting in target jar
|
||||||
*/
|
*/
|
||||||
bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod*>& mods);
|
bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod*>& mods);
|
||||||
|
#endif
|
||||||
/**
|
/**
|
||||||
* Find a single file in archive by file name (not path)
|
* Find a single file in archive by file name (not path)
|
||||||
*
|
*
|
||||||
@ -147,6 +151,7 @@ bool extractFile(QString fileCompressed, QString file, QString dir);
|
|||||||
*/
|
*/
|
||||||
bool collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList* files, FilterFunction excludeFilter);
|
bool collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList* files, FilterFunction excludeFilter);
|
||||||
|
|
||||||
|
#if defined(LAUNCHER_APPLICATION)
|
||||||
class ExportToZipTask : public Task {
|
class ExportToZipTask : public Task {
|
||||||
public:
|
public:
|
||||||
ExportToZipTask(QString outputPath, QDir dir, QFileInfoList files, QString destinationPrefix = "", bool followSymlinks = false)
|
ExportToZipTask(QString outputPath, QDir dir, QFileInfoList files, QString destinationPrefix = "", bool followSymlinks = false)
|
||||||
@ -167,7 +172,7 @@ class ExportToZipTask : public Task {
|
|||||||
void setExcludeFiles(QStringList excludeFiles) { m_exclude_files = excludeFiles; }
|
void setExcludeFiles(QStringList excludeFiles) { m_exclude_files = excludeFiles; }
|
||||||
void addExtraFile(QString fileName, QByteArray data) { m_extra_files.insert(fileName, data); }
|
void addExtraFile(QString fileName, QByteArray data) { m_extra_files.insert(fileName, data); }
|
||||||
|
|
||||||
typedef std::optional<QString> ZipResult;
|
using ZipResult = std::optional<QString>;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void executeTask() override;
|
virtual void executeTask() override;
|
||||||
@ -189,4 +194,5 @@ 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;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
} // namespace MMCZip
|
} // namespace MMCZip
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <QPixmapCache>
|
#include <QPixmapCache>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#define GET_TYPE() \
|
#define GET_TYPE() \
|
||||||
Qt::ConnectionType type; \
|
Qt::ConnectionType type; \
|
||||||
@ -100,10 +101,14 @@ class PixmapCache final : public QObject {
|
|||||||
*/
|
*/
|
||||||
bool _markCacheMissByEviciton()
|
bool _markCacheMissByEviciton()
|
||||||
{
|
{
|
||||||
|
static constexpr uint maxInt = static_cast<uint>(std::numeric_limits<int>::max());
|
||||||
|
static constexpr uint step = 10240;
|
||||||
|
static constexpr int oneSecond = 1000;
|
||||||
|
|
||||||
auto now = QTime::currentTime();
|
auto now = QTime::currentTime();
|
||||||
if (!m_last_cache_miss_by_eviciton.isNull()) {
|
if (!m_last_cache_miss_by_eviciton.isNull()) {
|
||||||
auto diff = m_last_cache_miss_by_eviciton.msecsTo(now);
|
auto diff = m_last_cache_miss_by_eviciton.msecsTo(now);
|
||||||
if (diff < 1000) { // less than a second ago
|
if (diff < oneSecond) { // less than a second ago
|
||||||
++m_consecutive_fast_evicitons;
|
++m_consecutive_fast_evicitons;
|
||||||
} else {
|
} else {
|
||||||
m_consecutive_fast_evicitons = 0;
|
m_consecutive_fast_evicitons = 0;
|
||||||
@ -111,11 +116,17 @@ class PixmapCache final : public QObject {
|
|||||||
}
|
}
|
||||||
m_last_cache_miss_by_eviciton = now;
|
m_last_cache_miss_by_eviciton = now;
|
||||||
if (m_consecutive_fast_evicitons >= m_consecutive_fast_evicitons_threshold) {
|
if (m_consecutive_fast_evicitons >= m_consecutive_fast_evicitons_threshold) {
|
||||||
// double the cache size
|
// increase the cache size
|
||||||
auto newSize = _cacheLimit() * 2;
|
uint newSize = _cacheLimit() + step;
|
||||||
qDebug() << m_consecutive_fast_evicitons << "pixmap cache misses by eviction happened too fast, doubling cache size to"
|
if (newSize >= maxInt) { // increase it until you overflow :D
|
||||||
<< newSize;
|
newSize = maxInt;
|
||||||
_setCacheLimit(newSize);
|
qDebug() << m_consecutive_fast_evicitons
|
||||||
|
<< tr("pixmap cache misses by eviction happened too fast, doing nothing as the cache size reached it's limit");
|
||||||
|
} else {
|
||||||
|
qDebug() << m_consecutive_fast_evicitons
|
||||||
|
<< tr("pixmap cache misses by eviction happened too fast, increasing cache size to") << static_cast<int>(newSize);
|
||||||
|
}
|
||||||
|
_setCacheLimit(static_cast<int>(newSize));
|
||||||
m_consecutive_fast_evicitons = 0;
|
m_consecutive_fast_evicitons = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
@ -26,6 +27,15 @@
|
|||||||
#include "Json.h"
|
#include "Json.h"
|
||||||
#include "MangoHud.h"
|
#include "MangoHud.h"
|
||||||
|
|
||||||
|
#ifdef __GLIBC__
|
||||||
|
#ifndef _GNU_SOURCE
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#define UNDEF_GNU_SOURCE
|
||||||
|
#endif
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <linux/limits.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace MangoHud {
|
namespace MangoHud {
|
||||||
|
|
||||||
QString getLibraryString()
|
QString getLibraryString()
|
||||||
@ -106,4 +116,37 @@ QString getLibraryString()
|
|||||||
|
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString findLibrary(QString libName)
|
||||||
|
{
|
||||||
|
#ifdef __GLIBC__
|
||||||
|
const char* library = libName.toLocal8Bit().constData();
|
||||||
|
|
||||||
|
void* handle = dlopen(library, RTLD_NOW);
|
||||||
|
if (!handle) {
|
||||||
|
qCritical() << "dlopen() failed:" << dlerror();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
char path[PATH_MAX];
|
||||||
|
if (dlinfo(handle, RTLD_DI_ORIGIN, path) == -1) {
|
||||||
|
qCritical() << "dlinfo() failed:" << dlerror();
|
||||||
|
dlclose(handle);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fullPath = FS::PathCombine(QString(path), libName);
|
||||||
|
|
||||||
|
dlclose(handle);
|
||||||
|
return fullPath;
|
||||||
|
#else
|
||||||
|
qWarning() << "MangoHud::findLibrary is not implemented on this platform";
|
||||||
|
return {};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
} // namespace MangoHud
|
} // namespace MangoHud
|
||||||
|
|
||||||
|
#ifdef UNDEF_GNU_SOURCE
|
||||||
|
#undef _GNU_SOURCE
|
||||||
|
#undef UNDEF_GNU_SOURCE
|
||||||
|
#endif
|
||||||
|
@ -24,4 +24,6 @@
|
|||||||
namespace MangoHud {
|
namespace MangoHud {
|
||||||
|
|
||||||
QString getLibraryString();
|
QString getLibraryString();
|
||||||
}
|
|
||||||
|
QString findLibrary(QString libName);
|
||||||
|
} // namespace MangoHud
|
||||||
|
@ -2,6 +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 TheKodeToad <TheKodeToad@proton.me>
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -52,7 +53,7 @@ class NullInstance : public BaseInstance {
|
|||||||
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, MinecraftServerTargetPtr) override { return nullptr; }
|
||||||
shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) override { return nullptr; }
|
shared_qobject_ptr<Task> createUpdateTask([[maybe_unused]] Net::Mode mode) override { return nullptr; }
|
||||||
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>(); }
|
||||||
@ -62,6 +63,7 @@ class NullInstance : public BaseInstance {
|
|||||||
bool canExport() const override { return false; }
|
bool canExport() const override { return false; }
|
||||||
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 {}
|
||||||
QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override
|
QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override
|
||||||
{
|
{
|
||||||
QStringList out;
|
QStringList out;
|
||||||
|
@ -12,7 +12,7 @@ struct PatchProblem {
|
|||||||
|
|
||||||
class ProblemProvider {
|
class ProblemProvider {
|
||||||
public:
|
public:
|
||||||
virtual ~ProblemProvider(){};
|
virtual ~ProblemProvider() {}
|
||||||
virtual const QList<PatchProblem> getProblems() const = 0;
|
virtual const QList<PatchProblem> getProblems() const = 0;
|
||||||
virtual ProblemSeverity getProblemSeverity() const = 0;
|
virtual ProblemSeverity getProblemSeverity() const = 0;
|
||||||
};
|
};
|
||||||
|
@ -90,7 +90,7 @@ void RecursiveFileSystemWatcher::fileChange(const QString& path)
|
|||||||
{
|
{
|
||||||
emit fileChanged(path);
|
emit fileChanged(path);
|
||||||
}
|
}
|
||||||
void RecursiveFileSystemWatcher::directoryChange(const QString& path)
|
void RecursiveFileSystemWatcher::directoryChange([[maybe_unused]] const QString& path)
|
||||||
{
|
{
|
||||||
setFiles(scanRecursive(m_root));
|
setFiles(scanRecursive(m_root));
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ class RecursiveFileSystemWatcher : public QObject {
|
|||||||
QDir rootDir() const { return m_root; }
|
QDir rootDir() const { return m_root; }
|
||||||
|
|
||||||
// WARNING: setting this to true may be bad for performance
|
// WARNING: setting this to true may be bad for performance
|
||||||
void setWatchFiles(const bool watchFiles);
|
void setWatchFiles(bool watchFiles);
|
||||||
bool watchFiles() const { return m_watchFiles; }
|
bool watchFiles() const { return m_watchFiles; }
|
||||||
|
|
||||||
void setMatcher(IPathMatcher::Ptr matcher) { m_matcher = matcher; }
|
void setMatcher(IPathMatcher::Ptr matcher) { m_matcher = matcher; }
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#include "minecraft/mod/ModFolderModel.h"
|
#include "minecraft/mod/ModFolderModel.h"
|
||||||
#include "minecraft/mod/ResourceFolderModel.h"
|
#include "minecraft/mod/ResourceFolderModel.h"
|
||||||
|
|
||||||
|
#include "net/ApiDownload.h"
|
||||||
|
|
||||||
ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack,
|
ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack,
|
||||||
ModPlatform::IndexedVersion version,
|
ModPlatform::IndexedVersion version,
|
||||||
const std::shared_ptr<ResourceFolderModel> packs,
|
const std::shared_ptr<ResourceFolderModel> packs,
|
||||||
@ -51,7 +53,7 @@ ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_filesNetJob->addNetAction(Net::Download::makeFile(m_pack_version.downloadUrl, dir.absoluteFilePath(getFilename())));
|
m_filesNetJob->addNetAction(Net::ApiDownload::makeFile(m_pack_version.downloadUrl, dir.absoluteFilePath(getFilename())));
|
||||||
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);
|
||||||
|
@ -32,7 +32,7 @@ class ResourceDownloadTask : public SequentialTask {
|
|||||||
public:
|
public:
|
||||||
explicit ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack,
|
explicit ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack,
|
||||||
ModPlatform::IndexedVersion version,
|
ModPlatform::IndexedVersion version,
|
||||||
const std::shared_ptr<ResourceFolderModel> packs,
|
std::shared_ptr<ResourceFolderModel> packs,
|
||||||
bool is_indexed = true,
|
bool is_indexed = true,
|
||||||
QString custom_target_folder = {});
|
QString custom_target_folder = {});
|
||||||
const QString& getFilename() const { return m_pack_version.fileName; }
|
const QString& getFilename() const { return m_pack_version.fileName; }
|
||||||
|
@ -35,6 +35,11 @@ QPixmap getFaceFromCache(QString username, int height, int width)
|
|||||||
QPixmap skinTexture(fskin.fileName());
|
QPixmap skinTexture(fskin.fileName());
|
||||||
if (!skinTexture.isNull()) {
|
if (!skinTexture.isNull()) {
|
||||||
QPixmap skin = QPixmap(8, 8);
|
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);
|
QPainter painter(&skin);
|
||||||
painter.drawPixmap(0, 0, skinTexture.copy(8, 8, 8, 8));
|
painter.drawPixmap(0, 0, skinTexture.copy(8, 8, 8, 8));
|
||||||
painter.drawPixmap(0, 0, skinTexture.copy(40, 8, 8, 8));
|
painter.drawPixmap(0, 0, skinTexture.copy(40, 8, 8, 8));
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
|
#include <qpair.h>
|
||||||
|
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
@ -149,7 +150,7 @@ QString StringUtils::truncateUrlHumanFriendly(QUrl& url, int max_len, bool hard_
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((url_compact.length() >= max_len) && hard_limit) {
|
if ((url_compact.length() >= max_len) && hard_limit) {
|
||||||
// still too long, truncate normaly
|
// still too long, truncate normally
|
||||||
url_compact = QString(str_url);
|
url_compact = QString(str_url);
|
||||||
auto to_remove = url_compact.length() - max_len + 3;
|
auto to_remove = url_compact.length() - max_len + 3;
|
||||||
url_compact.remove(url_compact.length() - to_remove - 1, to_remove);
|
url_compact.remove(url_compact.length() - to_remove - 1, to_remove);
|
||||||
@ -182,3 +183,32 @@ QString StringUtils::getRandomAlphaNumeric()
|
|||||||
{
|
{
|
||||||
return QUuid::createUuid().toString(QUuid::Id128);
|
return QUuid::createUuid().toString(QUuid::Id128);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPair<QString, QString> StringUtils::splitFirst(const QString& s, const QString& sep, Qt::CaseSensitivity cs)
|
||||||
|
{
|
||||||
|
QString left, right;
|
||||||
|
auto index = s.indexOf(sep, 0, cs);
|
||||||
|
left = s.mid(0, index);
|
||||||
|
right = s.mid(index + sep.length());
|
||||||
|
return qMakePair(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPair<QString, QString> StringUtils::splitFirst(const QString& s, QChar sep, Qt::CaseSensitivity cs)
|
||||||
|
{
|
||||||
|
QString left, right;
|
||||||
|
auto index = s.indexOf(sep, 0, cs);
|
||||||
|
left = s.mid(0, index);
|
||||||
|
right = s.mid(left.length() + 1);
|
||||||
|
return qMakePair(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPair<QString, QString> StringUtils::splitFirst(const QString& s, const QRegularExpression& re)
|
||||||
|
{
|
||||||
|
QString left, right;
|
||||||
|
QRegularExpressionMatch match;
|
||||||
|
auto index = s.indexOf(re, 0, &match);
|
||||||
|
left = s.mid(0, index);
|
||||||
|
auto end = match.hasMatch() ? left.length() + match.capturedLength() : left.length() + 1;
|
||||||
|
right = s.mid(end);
|
||||||
|
return qMakePair(left, right);
|
||||||
|
}
|
||||||
|
@ -36,8 +36,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QPair>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace StringUtils {
|
namespace StringUtils {
|
||||||
|
|
||||||
@ -70,12 +72,17 @@ int naturalCompare(const QString& s1, const QString& s2, Qt::CaseSensitivity cs)
|
|||||||
/**
|
/**
|
||||||
* @brief Truncate a url while keeping its readability py placing the `...` in the middle of the path
|
* @brief Truncate a url while keeping its readability py placing the `...` in the middle of the path
|
||||||
* @param url Url to truncate
|
* @param url Url to truncate
|
||||||
* @param max_len max lenght of url in charaters
|
* @param max_len max length of url in characters
|
||||||
* @param hard_limit if truncating the path can't get the url short enough, truncate it normaly.
|
* @param hard_limit if truncating the path can't get the url short enough, truncate it normally.
|
||||||
*/
|
*/
|
||||||
QString truncateUrlHumanFriendly(QUrl& url, int max_len, bool hard_limit = false);
|
QString truncateUrlHumanFriendly(QUrl& url, int max_len, bool hard_limit = false);
|
||||||
|
|
||||||
QString humanReadableFileSize(double bytes, bool use_si = false, int decimal_points = 1);
|
QString humanReadableFileSize(double bytes, bool use_si = false, int decimal_points = 1);
|
||||||
|
|
||||||
QString getRandomAlphaNumeric();
|
QString getRandomAlphaNumeric();
|
||||||
|
|
||||||
|
QPair<QString, QString> splitFirst(const QString& s, const QString& sep, Qt::CaseSensitivity cs = Qt::CaseSensitive);
|
||||||
|
QPair<QString, QString> splitFirst(const QString& s, QChar sep, Qt::CaseSensitivity cs = Qt::CaseSensitive);
|
||||||
|
QPair<QString, QString> splitFirst(const QString& s, const QRegularExpression& re);
|
||||||
|
|
||||||
} // namespace StringUtils
|
} // namespace StringUtils
|
||||||
|
@ -16,6 +16,8 @@ class Usable {
|
|||||||
friend class UseLock;
|
friend class UseLock;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
virtual ~Usable() {}
|
||||||
|
|
||||||
std::size_t useCount() const { return m_useCount; }
|
std::size_t useCount() const { return m_useCount; }
|
||||||
bool isInUse() const { return m_useCount > 0; }
|
bool isInUse() const { return m_useCount > 0; }
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ class Version {
|
|||||||
bool operator!=(const Version& other) const;
|
bool operator!=(const Version& other) const;
|
||||||
|
|
||||||
QString toString() const { return m_string; }
|
QString toString() const { return m_string; }
|
||||||
|
bool isEmpty() const { return m_string.isEmpty(); }
|
||||||
|
|
||||||
friend QDebug operator<<(QDebug debug, const Version& v);
|
friend QDebug operator<<(QDebug debug, const Version& v);
|
||||||
|
|
||||||
@ -63,7 +64,7 @@ class Version {
|
|||||||
struct Section {
|
struct Section {
|
||||||
explicit Section(QString fullString) : m_fullString(std::move(fullString))
|
explicit Section(QString fullString) : m_fullString(std::move(fullString))
|
||||||
{
|
{
|
||||||
int cutoff = m_fullString.size();
|
qsizetype cutoff = m_fullString.size();
|
||||||
for (int i = 0; i < m_fullString.size(); i++) {
|
for (int i = 0; i < m_fullString.size(); i++) {
|
||||||
if (!m_fullString[i].isDigit()) {
|
if (!m_fullString[i].isDigit()) {
|
||||||
cutoff = i;
|
cutoff = i;
|
||||||
@ -103,14 +104,8 @@ class Version {
|
|||||||
|
|
||||||
QString m_fullString;
|
QString m_fullString;
|
||||||
|
|
||||||
[[nodiscard]] inline bool isAppendix() const
|
[[nodiscard]] inline bool isAppendix() const { return m_stringPart.startsWith('+'); }
|
||||||
{
|
[[nodiscard]] inline bool isPreRelease() const { return m_stringPart.startsWith('-') && m_stringPart.length() > 1; }
|
||||||
return m_stringPart.startsWith('+');
|
|
||||||
}
|
|
||||||
[[nodiscard]] inline bool isPreRelease() const
|
|
||||||
{
|
|
||||||
return m_stringPart.startsWith('-') && m_stringPart.length() > 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator==(const Section& other) const
|
inline bool operator==(const Section& other) const
|
||||||
{
|
{
|
||||||
@ -156,14 +151,8 @@ class Version {
|
|||||||
return m_fullString < other.m_fullString;
|
return m_fullString < other.m_fullString;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator!=(const Section& other) const
|
inline bool operator!=(const Section& other) const { return !(*this == other); }
|
||||||
{
|
inline bool operator>(const Section& other) const { return !(*this < other || *this == other); }
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
inline bool operator>(const Section& other) const
|
|
||||||
{
|
|
||||||
return !(*this < other || *this == other);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -194,12 +194,12 @@ QVariant VersionProxyModel::data(const QModelIndex& index, int role) const
|
|||||||
switch (column) {
|
switch (column) {
|
||||||
case Name: {
|
case Name: {
|
||||||
if (hasRecommended) {
|
if (hasRecommended) {
|
||||||
auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
|
auto recommenced = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
|
||||||
if (value.toBool()) {
|
if (recommenced.toBool()) {
|
||||||
return APPLICATION->getThemedIcon("star");
|
return APPLICATION->getThemedIcon("star");
|
||||||
} else if (hasLatest) {
|
} else if (hasLatest) {
|
||||||
auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
|
auto latest = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
|
||||||
if (value.toBool()) {
|
if (latest.toBool()) {
|
||||||
return APPLICATION->getThemedIcon("bug");
|
return APPLICATION->getThemedIcon("bug");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,7 +228,7 @@ QVariant VersionProxyModel::data(const QModelIndex& index, int role) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex VersionProxyModel::parent(const QModelIndex& child) const
|
QModelIndex VersionProxyModel::parent([[maybe_unused]] const QModelIndex& child) const
|
||||||
{
|
{
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
}
|
}
|
||||||
@ -408,7 +408,9 @@ void VersionProxyModel::sourceRowsAboutToBeInserted(const QModelIndex& parent, i
|
|||||||
beginInsertRows(parent, first, last);
|
beginInsertRows(parent, first, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionProxyModel::sourceRowsInserted(const QModelIndex& parent, int first, int last)
|
void VersionProxyModel::sourceRowsInserted([[maybe_unused]] const QModelIndex& parent,
|
||||||
|
[[maybe_unused]] int first,
|
||||||
|
[[maybe_unused]] int last)
|
||||||
{
|
{
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
}
|
}
|
||||||
@ -418,7 +420,7 @@ void VersionProxyModel::sourceRowsAboutToBeRemoved(const QModelIndex& parent, in
|
|||||||
beginRemoveRows(parent, first, last);
|
beginRemoveRows(parent, first, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionProxyModel::sourceRowsRemoved(const QModelIndex& parent, int first, int last)
|
void VersionProxyModel::sourceRowsRemoved([[maybe_unused]] const QModelIndex& parent, [[maybe_unused]] int first, [[maybe_unused]] int last)
|
||||||
{
|
{
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ 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, Architecture, Path, Time };
|
||||||
typedef QHash<BaseVersionList::ModelRoles, std::shared_ptr<Filter>> FilterMap;
|
using FilterMap = QHash<BaseVersionList::ModelRoles, std::shared_ptr<Filter>>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VersionProxyModel(QObject* parent = 0);
|
VersionProxyModel(QObject* parent = 0);
|
||||||
@ -28,7 +28,7 @@ class VersionProxyModel : public QAbstractProxyModel {
|
|||||||
|
|
||||||
const FilterMap& filters() const;
|
const FilterMap& filters() const;
|
||||||
const QString& search() const;
|
const QString& search() const;
|
||||||
void setFilter(const BaseVersionList::ModelRoles column, Filter* filter);
|
void setFilter(BaseVersionList::ModelRoles column, Filter* filter);
|
||||||
void setSearch(const QString& search);
|
void setSearch(const QString& search);
|
||||||
void clearFilters();
|
void clearFilters();
|
||||||
QModelIndex getRecommended() const;
|
QModelIndex getRecommended() const;
|
||||||
|
128
launcher/WindowsConsole.cpp
Normal file
128
launcher/WindowsConsole.cpp
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <io.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
void RedirectHandle(DWORD handle, FILE* stream, const char* mode)
|
||||||
|
{
|
||||||
|
HANDLE stdHandle = GetStdHandle(handle);
|
||||||
|
if (stdHandle != INVALID_HANDLE_VALUE) {
|
||||||
|
int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
|
||||||
|
if (fileDescriptor != -1) {
|
||||||
|
FILE* file = _fdopen(fileDescriptor, mode);
|
||||||
|
if (file != NULL) {
|
||||||
|
int dup2Result = _dup2(_fileno(file), _fileno(stream));
|
||||||
|
if (dup2Result == 0) {
|
||||||
|
setvbuf(stream, NULL, _IONBF, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// taken from https://stackoverflow.com/a/25927081
|
||||||
|
// getting a proper output to console with redirection support on windows is apparently hell
|
||||||
|
void BindCrtHandlesToStdHandles(bool bindStdIn, bool bindStdOut, bool bindStdErr)
|
||||||
|
{
|
||||||
|
// Re-initialize the C runtime "FILE" handles with clean handles bound to "nul". We do this because it has been
|
||||||
|
// observed that the file number of our standard handle file objects can be assigned internally to a value of -2
|
||||||
|
// when not bound to a valid target, which represents some kind of unknown internal invalid state. In this state our
|
||||||
|
// call to "_dup2" fails, as it specifically tests to ensure that the target file number isn't equal to this value
|
||||||
|
// before allowing the operation to continue. We can resolve this issue by first "re-opening" the target files to
|
||||||
|
// use the "nul" device, which will place them into a valid state, after which we can redirect them to our target
|
||||||
|
// using the "_dup2" function.
|
||||||
|
if (bindStdIn) {
|
||||||
|
FILE* dummyFile;
|
||||||
|
freopen_s(&dummyFile, "nul", "r", stdin);
|
||||||
|
}
|
||||||
|
if (bindStdOut) {
|
||||||
|
FILE* dummyFile;
|
||||||
|
freopen_s(&dummyFile, "nul", "w", stdout);
|
||||||
|
}
|
||||||
|
if (bindStdErr) {
|
||||||
|
FILE* dummyFile;
|
||||||
|
freopen_s(&dummyFile, "nul", "w", stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirect unbuffered stdin from the current standard input handle
|
||||||
|
if (bindStdIn) {
|
||||||
|
RedirectHandle(STD_INPUT_HANDLE, stdin, "r");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirect unbuffered stdout to the current standard output handle
|
||||||
|
if (bindStdOut) {
|
||||||
|
RedirectHandle(STD_OUTPUT_HANDLE, stdout, "w");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirect unbuffered stderr to the current standard error handle
|
||||||
|
if (bindStdErr) {
|
||||||
|
RedirectHandle(STD_ERROR_HANDLE, stderr, "w");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the error state for each of the C++ standard stream objects. We need to do this, as attempts to access the
|
||||||
|
// standard streams before they refer to a valid target will cause the iostream objects to enter an error state. In
|
||||||
|
// versions of Visual Studio after 2005, this seems to always occur during startup regardless of whether anything
|
||||||
|
// has been read from or written to the targets or not.
|
||||||
|
if (bindStdIn) {
|
||||||
|
std::wcin.clear();
|
||||||
|
std::cin.clear();
|
||||||
|
}
|
||||||
|
if (bindStdOut) {
|
||||||
|
std::wcout.clear();
|
||||||
|
std::cout.clear();
|
||||||
|
}
|
||||||
|
if (bindStdErr) {
|
||||||
|
std::wcerr.clear();
|
||||||
|
std::cerr.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AttachWindowsConsole()
|
||||||
|
{
|
||||||
|
auto stdinType = GetFileType(GetStdHandle(STD_INPUT_HANDLE));
|
||||||
|
auto stdoutType = GetFileType(GetStdHandle(STD_OUTPUT_HANDLE));
|
||||||
|
auto stderrType = GetFileType(GetStdHandle(STD_ERROR_HANDLE));
|
||||||
|
|
||||||
|
bool bindStdIn = false;
|
||||||
|
bool bindStdOut = false;
|
||||||
|
bool bindStdErr = false;
|
||||||
|
|
||||||
|
if (stdinType == FILE_TYPE_CHAR || stdinType == FILE_TYPE_UNKNOWN) {
|
||||||
|
bindStdIn = true;
|
||||||
|
}
|
||||||
|
if (stdoutType == FILE_TYPE_CHAR || stdoutType == FILE_TYPE_UNKNOWN) {
|
||||||
|
bindStdOut = true;
|
||||||
|
}
|
||||||
|
if (stderrType == FILE_TYPE_CHAR || stderrType == FILE_TYPE_UNKNOWN) {
|
||||||
|
bindStdErr = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||||
|
BindCrtHandlesToStdHandles(bindStdIn, bindStdOut, bindStdErr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
|
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
@ -20,11 +19,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "FileLink.h"
|
#pragma once
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
void BindCrtHandlesToStdHandles(bool bindStdIn, bool bindStdOut, bool bindStdErr);
|
||||||
{
|
bool AttachWindowsConsole();
|
||||||
FileLinkApp ldh(argc, argv);
|
|
||||||
|
|
||||||
return ldh.exec();
|
|
||||||
}
|
|
@ -37,11 +37,7 @@
|
|||||||
#include <sys.h>
|
#include <sys.h>
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#include "WindowsConsole.h"
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Snippet from https://github.com/gulrak/filesystem#using-it-as-single-file-header
|
// Snippet from https://github.com/gulrak/filesystem#using-it-as-single-file-header
|
||||||
@ -67,21 +63,7 @@ FileLinkApp::FileLinkApp(int& argc, char** argv) : QCoreApplication(argc, argv),
|
|||||||
{
|
{
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
// attach the parent console
|
// attach the parent console
|
||||||
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
if (AttachWindowsConsole()) {
|
||||||
// if attach succeeds, reopen and sync all the i/o
|
|
||||||
if (freopen("CON", "w", stdout)) {
|
|
||||||
std::cout.sync_with_stdio();
|
|
||||||
}
|
|
||||||
if (freopen("CON", "w", stderr)) {
|
|
||||||
std::cerr.sync_with_stdio();
|
|
||||||
}
|
|
||||||
if (freopen("CON", "r", stdin)) {
|
|
||||||
std::cin.sync_with_stdio();
|
|
||||||
}
|
|
||||||
auto out = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
DWORD written;
|
|
||||||
const char* endline = "\n";
|
|
||||||
WriteConsole(out, endline, strlen(endline), &written, NULL);
|
|
||||||
consoleAttached = true;
|
consoleAttached = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -111,6 +93,7 @@ FileLinkApp::FileLinkApp(int& argc, char** argv) : QCoreApplication(argc, argv),
|
|||||||
joinServer(serverToJoin);
|
joinServer(serverToJoin);
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "no server to join";
|
qDebug() << "no server to join";
|
||||||
|
m_status = Failed;
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,6 +109,7 @@ void FileLinkApp::joinServer(QString server)
|
|||||||
connect(&socket, &QLocalSocket::readyRead, this, &FileLinkApp::readPathPairs);
|
connect(&socket, &QLocalSocket::readyRead, this, &FileLinkApp::readPathPairs);
|
||||||
|
|
||||||
connect(&socket, &QLocalSocket::errorOccurred, this, [&](QLocalSocket::LocalSocketError socketError) {
|
connect(&socket, &QLocalSocket::errorOccurred, this, [&](QLocalSocket::LocalSocketError socketError) {
|
||||||
|
m_status = Failed;
|
||||||
switch (socketError) {
|
switch (socketError) {
|
||||||
case QLocalSocket::ServerNotFoundError:
|
case QLocalSocket::ServerNotFoundError:
|
||||||
qDebug()
|
qDebug()
|
||||||
@ -150,6 +134,7 @@ void FileLinkApp::joinServer(QString server)
|
|||||||
|
|
||||||
connect(&socket, &QLocalSocket::disconnected, this, [&]() {
|
connect(&socket, &QLocalSocket::disconnected, this, [&]() {
|
||||||
qDebug() << "disconnected from server, should exit";
|
qDebug() << "disconnected from server, should exit";
|
||||||
|
m_status = Succeeded;
|
||||||
exit();
|
exit();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -188,7 +173,7 @@ void FileLinkApp::runLink()
|
|||||||
FS::LinkResult result = { src_path, dst_path, QString::fromStdString(os_err.message()), os_err.value() };
|
FS::LinkResult result = { src_path, dst_path, QString::fromStdString(os_err.message()), os_err.value() };
|
||||||
m_path_results.append(result);
|
m_path_results.append(result);
|
||||||
} else {
|
} else {
|
||||||
FS::LinkResult result = { src_path, dst_path };
|
FS::LinkResult result = { src_path, dst_path, "", 0 };
|
||||||
m_path_results.append(result);
|
m_path_results.append(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -248,7 +233,7 @@ void FileLinkApp::readPathPairs()
|
|||||||
in >> numLinks;
|
in >> numLinks;
|
||||||
qDebug() << "numLinks" << numLinks;
|
qDebug() << "numLinks" << numLinks;
|
||||||
|
|
||||||
for (int i = 0; i < numLinks; i++) {
|
for (quint32 i = 0; i < numLinks; i++) {
|
||||||
FS::LinkPair pair;
|
FS::LinkPair pair;
|
||||||
in >> pair.src;
|
in >> pair.src;
|
||||||
in >> pair.dst;
|
in >> pair.dst;
|
||||||
@ -271,7 +256,6 @@ FileLinkApp::~FileLinkApp()
|
|||||||
fclose(stdout);
|
fclose(stdout);
|
||||||
fclose(stdin);
|
fclose(stdin);
|
||||||
fclose(stderr);
|
fclose(stderr);
|
||||||
FreeConsole();
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -41,8 +41,10 @@ class FileLinkApp : public QCoreApplication {
|
|||||||
// friends for the purpose of limiting access to deprecated stuff
|
// friends for the purpose of limiting access to deprecated stuff
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
enum Status { Starting, Failed, Succeeded, Initialized };
|
||||||
FileLinkApp(int& argc, char** argv);
|
FileLinkApp(int& argc, char** argv);
|
||||||
virtual ~FileLinkApp();
|
virtual ~FileLinkApp();
|
||||||
|
Status status() const { return m_status; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void joinServer(QString server);
|
void joinServer(QString server);
|
||||||
@ -50,6 +52,8 @@ class FileLinkApp : public QCoreApplication {
|
|||||||
void runLink();
|
void runLink();
|
||||||
void sendResults();
|
void sendResults();
|
||||||
|
|
||||||
|
Status m_status = Status::Starting;
|
||||||
|
|
||||||
bool m_useHardLinks = false;
|
bool m_useHardLinks = false;
|
||||||
|
|
||||||
QDateTime m_startTime;
|
QDateTime m_startTime;
|
||||||
|
41
launcher/filelink/filelink_main.cpp
Normal file
41
launcher/filelink/filelink_main.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.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 "FileLink.h"
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
FileLinkApp ldh(argc, argv);
|
||||||
|
|
||||||
|
switch (ldh.status()) {
|
||||||
|
case FileLinkApp::Starting:
|
||||||
|
case FileLinkApp::Initialized: {
|
||||||
|
return ldh.exec();
|
||||||
|
}
|
||||||
|
case FileLinkApp::Failed:
|
||||||
|
return 1;
|
||||||
|
case FileLinkApp::Succeeded:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +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>
|
||||||
*
|
*
|
||||||
* 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 +43,7 @@
|
|||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include "icons/IconUtils.h"
|
||||||
|
|
||||||
#define MAX_SIZE 1024
|
#define MAX_SIZE 1024
|
||||||
|
|
||||||
@ -128,7 +130,7 @@ void IconList::directoryChanged(const QString& path)
|
|||||||
|
|
||||||
QString suffix = rmfile.suffix();
|
QString suffix = rmfile.suffix();
|
||||||
// The icon doesnt have a suffix, but it can have other .s in the name, so we account for those as well
|
// The icon doesnt have a suffix, but it can have other .s in the name, so we account for those as well
|
||||||
if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif")
|
if (!IconUtils::isIconSuffix(suffix))
|
||||||
key = rmfile.fileName();
|
key = rmfile.fileName();
|
||||||
|
|
||||||
int idx = getIconIndex(key);
|
int idx = getIconIndex(key);
|
||||||
@ -155,7 +157,7 @@ void IconList::directoryChanged(const QString& path)
|
|||||||
|
|
||||||
QString suffix = addfile.suffix();
|
QString suffix = addfile.suffix();
|
||||||
// The icon doesnt have a suffix, but it can have other .s in the name, so we account for those as well
|
// The icon doesnt have a suffix, but it can have other .s in the name, so we account for those as well
|
||||||
if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif")
|
if (!IconUtils::isIconSuffix(suffix))
|
||||||
key = addfile.fileName();
|
key = addfile.fileName();
|
||||||
|
|
||||||
if (addIcon(key, QString(), addfile.filePath(), IconType::FileBased)) {
|
if (addIcon(key, QString(), addfile.filePath(), IconType::FileBased)) {
|
||||||
@ -255,10 +257,7 @@ bool IconList::dropMimeData(const QMimeData* data,
|
|||||||
Qt::ItemFlags IconList::flags(const QModelIndex& index) const
|
Qt::ItemFlags IconList::flags(const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index);
|
Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index);
|
||||||
if (index.isValid())
|
return Qt::ItemIsDropEnabled | defaultFlags;
|
||||||
return Qt::ItemIsDropEnabled | defaultFlags;
|
|
||||||
else
|
|
||||||
return Qt::ItemIsDropEnabled | defaultFlags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant IconList::data(const QModelIndex& index, int role) const
|
QVariant IconList::data(const QModelIndex& index, int role) const
|
||||||
@ -290,19 +289,8 @@ int IconList::rowCount(const QModelIndex& parent) const
|
|||||||
|
|
||||||
void IconList::installIcons(const QStringList& iconFiles)
|
void IconList::installIcons(const QStringList& iconFiles)
|
||||||
{
|
{
|
||||||
for (QString file : iconFiles) {
|
for (QString file : iconFiles)
|
||||||
QFileInfo fileinfo(file);
|
installIcon(file, {});
|
||||||
if (!fileinfo.isReadable() || !fileinfo.isFile())
|
|
||||||
continue;
|
|
||||||
QString target = FS::PathCombine(getDirectory(), fileinfo.fileName());
|
|
||||||
|
|
||||||
QString suffix = fileinfo.suffix();
|
|
||||||
if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif")
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!QFile::copy(file, target))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IconList::installIcon(const QString& file, const QString& name)
|
void IconList::installIcon(const QString& file, const QString& name)
|
||||||
@ -311,18 +299,17 @@ void IconList::installIcon(const QString& file, const QString& name)
|
|||||||
if (!fileinfo.isReadable() || !fileinfo.isFile())
|
if (!fileinfo.isReadable() || !fileinfo.isFile())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QString target = FS::PathCombine(getDirectory(), name);
|
if (!IconUtils::isIconSuffix(fileinfo.suffix()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString target = FS::PathCombine(getDirectory(), name.isEmpty() ? fileinfo.fileName() : name);
|
||||||
QFile::copy(file, target);
|
QFile::copy(file, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IconList::iconFileExists(const QString& key) const
|
bool IconList::iconFileExists(const QString& key) const
|
||||||
{
|
{
|
||||||
auto iconEntry = icon(key);
|
auto iconEntry = icon(key);
|
||||||
if (!iconEntry) {
|
return iconEntry && iconEntry->has(IconType::FileBased);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return iconEntry->has(IconType::FileBased);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const MMCIcon* IconList::icon(const QString& key) const
|
const MMCIcon* IconList::icon(const QString& key) const
|
||||||
@ -335,18 +322,12 @@ const MMCIcon* IconList::icon(const QString& key) const
|
|||||||
|
|
||||||
bool IconList::deleteIcon(const QString& key)
|
bool IconList::deleteIcon(const QString& key)
|
||||||
{
|
{
|
||||||
if (!iconFileExists(key))
|
return iconFileExists(key) && QFile::remove(icon(key)->getFilePath());
|
||||||
return false;
|
|
||||||
|
|
||||||
return QFile::remove(icon(key)->getFilePath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IconList::trashIcon(const QString& key)
|
bool IconList::trashIcon(const QString& key)
|
||||||
{
|
{
|
||||||
if (!iconFileExists(key))
|
return iconFileExists(key) && FS::trash(icon(key)->getFilePath(), nullptr);
|
||||||
return false;
|
|
||||||
|
|
||||||
return FS::trash(icon(key)->getFilePath(), nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IconList::addThemeIcon(const QString& key)
|
bool IconList::addThemeIcon(const QString& key)
|
||||||
@ -357,20 +338,19 @@ bool IconList::addThemeIcon(const QString& key)
|
|||||||
oldOne.replace(Builtin, key);
|
oldOne.replace(Builtin, key);
|
||||||
dataChanged(index(*iter), index(*iter));
|
dataChanged(index(*iter), index(*iter));
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
// add a new icon
|
|
||||||
beginInsertRows(QModelIndex(), icons.size(), icons.size());
|
|
||||||
{
|
|
||||||
MMCIcon mmc_icon;
|
|
||||||
mmc_icon.m_name = key;
|
|
||||||
mmc_icon.m_key = key;
|
|
||||||
mmc_icon.replace(Builtin, key);
|
|
||||||
icons.push_back(mmc_icon);
|
|
||||||
name_index[key] = icons.size() - 1;
|
|
||||||
}
|
|
||||||
endInsertRows();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
// add a new icon
|
||||||
|
beginInsertRows(QModelIndex(), icons.size(), icons.size());
|
||||||
|
{
|
||||||
|
MMCIcon mmc_icon;
|
||||||
|
mmc_icon.m_name = key;
|
||||||
|
mmc_icon.m_key = key;
|
||||||
|
mmc_icon.replace(Builtin, key);
|
||||||
|
icons.push_back(mmc_icon);
|
||||||
|
name_index[key] = icons.size() - 1;
|
||||||
|
}
|
||||||
|
endInsertRows();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IconList::addIcon(const QString& key, const QString& name, const QString& path, const IconType type)
|
bool IconList::addIcon(const QString& key, const QString& name, const QString& path, const IconType type)
|
||||||
@ -385,20 +365,19 @@ bool IconList::addIcon(const QString& key, const QString& name, const QString& p
|
|||||||
oldOne.replace(type, icon, path);
|
oldOne.replace(type, icon, path);
|
||||||
dataChanged(index(*iter), index(*iter));
|
dataChanged(index(*iter), index(*iter));
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
// add a new icon
|
|
||||||
beginInsertRows(QModelIndex(), icons.size(), icons.size());
|
|
||||||
{
|
|
||||||
MMCIcon mmc_icon;
|
|
||||||
mmc_icon.m_name = name;
|
|
||||||
mmc_icon.m_key = key;
|
|
||||||
mmc_icon.replace(type, icon, path);
|
|
||||||
icons.push_back(mmc_icon);
|
|
||||||
name_index[key] = icons.size() - 1;
|
|
||||||
}
|
|
||||||
endInsertRows();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
// add a new icon
|
||||||
|
beginInsertRows(QModelIndex(), icons.size(), icons.size());
|
||||||
|
{
|
||||||
|
MMCIcon mmc_icon;
|
||||||
|
mmc_icon.m_name = name;
|
||||||
|
mmc_icon.m_key = key;
|
||||||
|
mmc_icon.replace(type, icon, path);
|
||||||
|
icons.push_back(mmc_icon);
|
||||||
|
name_index[key] = icons.size() - 1;
|
||||||
|
}
|
||||||
|
endInsertRows();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IconList::saveIcon(const QString& key, const QString& path, const char* format) const
|
void IconList::saveIcon(const QString& key, const QString& path, const char* format) const
|
||||||
@ -446,5 +425,3 @@ QString IconList::getDirectory() const
|
|||||||
{
|
{
|
||||||
return m_dir.absolutePath();
|
return m_dir.absolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
//#include "IconList.moc"
|
|
||||||
|
@ -1,18 +1,37 @@
|
|||||||
/* Copyright 2013-2021 MultiMC Contributors
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* you may not use this file except in compliance with the License.
|
* it under the terms of the GNU General Public License as published by
|
||||||
* You may obtain a copy of the License at
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* 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.
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* You should have received a copy of the GNU General Public License
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
*
|
||||||
* See the License for the specific language governing permissions and
|
* This file incorporates work covered by the following copyright and
|
||||||
* limitations under the License.
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
@ -48,7 +67,7 @@ class IconList : public QAbstractListModel {
|
|||||||
virtual Qt::ItemFlags flags(const QModelIndex& index) const override;
|
virtual Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||||
|
|
||||||
bool addThemeIcon(const QString& key);
|
bool addThemeIcon(const QString& key);
|
||||||
bool addIcon(const QString& key, const QString& name, const QString& path, const IconType type);
|
bool addIcon(const QString& key, const QString& name, const QString& path, IconType type);
|
||||||
void saveIcon(const QString& key, const QString& path, const char* format) const;
|
void saveIcon(const QString& key, const QString& path, const char* format) const;
|
||||||
bool deleteIcon(const QString& key);
|
bool deleteIcon(const QString& key);
|
||||||
bool trashIcon(const QString& key);
|
bool trashIcon(const QString& key);
|
||||||
|
@ -1,19 +1,51 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023 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 "IconUtils.h"
|
#include "IconUtils.h"
|
||||||
|
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
std::array<const char*, 6> validIconExtensions = { { "svg", "png", "ico", "gif", "jpg", "jpeg" } };
|
static const QStringList validIconExtensions = { { "svg", "png", "ico", "gif", "jpg", "jpeg" } };
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace IconUtils {
|
namespace IconUtils {
|
||||||
|
|
||||||
QString findBestIconIn(const QString& folder, const QString& iconKey)
|
QString findBestIconIn(const QString& folder, const QString& iconKey)
|
||||||
{
|
{
|
||||||
int best_found = validIconExtensions.size();
|
|
||||||
QString best_filename;
|
QString best_filename;
|
||||||
|
|
||||||
QDirIterator it(folder, QDir::NoDotAndDotDot | QDir::Files, QDirIterator::NoIteratorFlags);
|
QDirIterator it(folder, QDir::NoDotAndDotDot | QDir::Files, QDirIterator::NoIteratorFlags);
|
||||||
@ -21,36 +53,20 @@ QString findBestIconIn(const QString& folder, const QString& iconKey)
|
|||||||
it.next();
|
it.next();
|
||||||
auto fileInfo = it.fileInfo();
|
auto fileInfo = it.fileInfo();
|
||||||
|
|
||||||
if (fileInfo.completeBaseName() != iconKey)
|
if (fileInfo.completeBaseName() == iconKey && isIconSuffix(fileInfo.suffix()))
|
||||||
continue;
|
return fileInfo.absoluteFilePath();
|
||||||
|
|
||||||
auto extension = fileInfo.suffix();
|
|
||||||
|
|
||||||
for (int i = 0; i < best_found; i++) {
|
|
||||||
if (extension == validIconExtensions[i]) {
|
|
||||||
best_found = i;
|
|
||||||
qDebug() << i << " : " << fileInfo.fileName();
|
|
||||||
best_filename = fileInfo.fileName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return FS::PathCombine(folder, best_filename);
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
QString getIconFilter()
|
QString getIconFilter()
|
||||||
{
|
{
|
||||||
QString out;
|
return "(*." + validIconExtensions.join(" *.") + ")";
|
||||||
QTextStream stream(&out);
|
}
|
||||||
stream << '(';
|
|
||||||
for (size_t i = 0; i < validIconExtensions.size() - 1; i++) {
|
bool isIconSuffix(QString suffix)
|
||||||
if (i > 0) {
|
{
|
||||||
stream << " ";
|
return validIconExtensions.contains(suffix);
|
||||||
}
|
|
||||||
stream << "*." << validIconExtensions[i];
|
|
||||||
}
|
|
||||||
stream << " *." << validIconExtensions[validIconExtensions.size() - 1];
|
|
||||||
stream << ')';
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace IconUtils
|
} // namespace IconUtils
|
||||||
|
@ -1,3 +1,38 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023 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
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
@ -10,4 +45,5 @@ QString findBestIconIn(const QString& folder, const QString& iconKey);
|
|||||||
// Get icon file type filter for file browser dialogs
|
// Get icon file type filter for file browser dialogs
|
||||||
QString getIconFilter();
|
QString getIconFilter();
|
||||||
|
|
||||||
|
bool isIconSuffix(QString suffix);
|
||||||
} // namespace IconUtils
|
} // namespace IconUtils
|
||||||
|
@ -2,6 +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>
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -50,8 +51,8 @@ IconType operator--(IconType& t, int)
|
|||||||
case IconType::FileBased:
|
case IconType::FileBased:
|
||||||
t = IconType::Transient;
|
t = IconType::Transient;
|
||||||
break;
|
break;
|
||||||
default: {
|
default:
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,37 @@
|
|||||||
/* Copyright 2013-2021 MultiMC Contributors
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* you may not use this file except in compliance with the License.
|
* it under the terms of the GNU General Public License as published by
|
||||||
* You may obtain a copy of the License at
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* 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.
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* You should have received a copy of the GNU General Public License
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
*
|
||||||
* See the License for the specific language governing permissions and
|
* This file incorporates work covered by the following copyright and
|
||||||
* limitations under the License.
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
|
@ -22,8 +22,8 @@ struct JavaCheckResult {
|
|||||||
enum class Validity { Errored, ReturnedInvalidData, Valid } validity = Validity::Errored;
|
enum class Validity { Errored, ReturnedInvalidData, Valid } validity = Validity::Errored;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef shared_qobject_ptr<QProcess> QProcessPtr;
|
using QProcessPtr = shared_qobject_ptr<QProcess>;
|
||||||
typedef shared_qobject_ptr<JavaChecker> JavaCheckerPtr;
|
using JavaCheckerPtr = shared_qobject_ptr<JavaChecker>;
|
||||||
class JavaChecker : public QObject {
|
class JavaChecker : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
class JavaCheckerJob;
|
class JavaCheckerJob;
|
||||||
typedef shared_qobject_ptr<JavaCheckerJob> JavaCheckerJobPtr;
|
using JavaCheckerJobPtr = shared_qobject_ptr<JavaCheckerJob>;
|
||||||
|
|
||||||
// FIXME: this just seems horribly redundant
|
// FIXME: this just seems horribly redundant
|
||||||
class JavaCheckerJob : public Task {
|
class JavaCheckerJob : public Task {
|
||||||
|
@ -24,11 +24,11 @@
|
|||||||
struct JavaInstall : public BaseVersion {
|
struct JavaInstall : public BaseVersion {
|
||||||
JavaInstall() {}
|
JavaInstall() {}
|
||||||
JavaInstall(QString id, QString arch, QString path) : id(id), arch(arch), path(path) {}
|
JavaInstall(QString id, QString arch, QString path) : id(id), arch(arch), path(path) {}
|
||||||
virtual QString descriptor() { return id.toString(); }
|
virtual QString descriptor() override { return id.toString(); }
|
||||||
|
|
||||||
virtual QString name() { return id.toString(); }
|
virtual QString name() override { return id.toString(); }
|
||||||
|
|
||||||
virtual QString typeString() const { return arch; }
|
virtual QString typeString() const override { return arch; }
|
||||||
|
|
||||||
virtual bool operator<(BaseVersion& a) override;
|
virtual bool operator<(BaseVersion& a) override;
|
||||||
virtual bool operator>(BaseVersion& a) override;
|
virtual bool operator>(BaseVersion& a) override;
|
||||||
@ -42,4 +42,4 @@ struct JavaInstall : public BaseVersion {
|
|||||||
bool recommended = false;
|
bool recommended = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<JavaInstall> JavaInstallPtr;
|
using JavaInstallPtr = std::shared_ptr<JavaInstall>;
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QFileInfo>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
@ -335,6 +336,7 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
candidates.append(getMinecraftJavaBundle());
|
||||||
candidates = addJavasFromEnv(candidates);
|
candidates = addJavasFromEnv(candidates);
|
||||||
candidates.removeDuplicates();
|
candidates.removeDuplicates();
|
||||||
return candidates;
|
return candidates;
|
||||||
@ -360,6 +362,7 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java");
|
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java");
|
||||||
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java");
|
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java");
|
||||||
}
|
}
|
||||||
|
javas.append(getMinecraftJavaBundle());
|
||||||
javas = addJavasFromEnv(javas);
|
javas = addJavasFromEnv(javas);
|
||||||
javas.removeDuplicates();
|
javas.removeDuplicates();
|
||||||
return javas;
|
return javas;
|
||||||
@ -403,6 +406,15 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
scanJavaDirs("/opt/jdks");
|
scanJavaDirs("/opt/jdks");
|
||||||
// flatpak
|
// flatpak
|
||||||
scanJavaDirs("/app/jdk");
|
scanJavaDirs("/app/jdk");
|
||||||
|
|
||||||
|
auto home = qEnvironmentVariable("HOME");
|
||||||
|
|
||||||
|
// javas downloaded by IntelliJ
|
||||||
|
scanJavaDirs(FS::PathCombine(home, ".jdks"));
|
||||||
|
// javas downloaded by sdkman
|
||||||
|
scanJavaDirs(FS::PathCombine(home, ".sdkman/candidates/java"));
|
||||||
|
|
||||||
|
javas.append(getMinecraftJavaBundle());
|
||||||
javas = addJavasFromEnv(javas);
|
javas = addJavasFromEnv(javas);
|
||||||
javas.removeDuplicates();
|
javas.removeDuplicates();
|
||||||
return javas;
|
return javas;
|
||||||
@ -415,6 +427,7 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
QList<QString> javas;
|
QList<QString> javas;
|
||||||
javas.append(this->GetDefaultJava()->path);
|
javas.append(this->GetDefaultJava()->path);
|
||||||
|
|
||||||
|
javas.append(getMinecraftJavaBundle());
|
||||||
return addJavasFromEnv(javas);
|
return addJavasFromEnv(javas);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -423,3 +436,50 @@ QString JavaUtils::getJavaCheckPath()
|
|||||||
{
|
{
|
||||||
return APPLICATION->getJarPath("JavaCheck.jar");
|
return APPLICATION->getJarPath("JavaCheck.jar");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList getMinecraftJavaBundle()
|
||||||
|
{
|
||||||
|
QString partialPath;
|
||||||
|
QString executable = "java";
|
||||||
|
QStringList processpaths;
|
||||||
|
#if defined(Q_OS_OSX)
|
||||||
|
partialPath = FS::PathCombine(QDir::homePath(), "Library/Application Support");
|
||||||
|
#elif defined(Q_OS_WIN32)
|
||||||
|
partialPath = QProcessEnvironment::systemEnvironment().value("LOCALAPPDATA", "");
|
||||||
|
executable += "w.exe";
|
||||||
|
|
||||||
|
// add the microsoft store version of the launcher to the search. the current path is:
|
||||||
|
// C:\Users\USERNAME\AppData\Local\Packages\Microsoft.4297127D64EC6_8wekyb3d8bbwe\LocalCache\Local\runtime
|
||||||
|
auto minecraftMSStorePath =
|
||||||
|
FS::PathCombine(QFileInfo(partialPath).absolutePath(), "Local", "Packages", "Microsoft.4297127D64EC6_8wekyb3d8bbwe");
|
||||||
|
minecraftMSStorePath = FS::PathCombine(minecraftMSStorePath, "LocalCache", "Local", "runtime");
|
||||||
|
processpaths << minecraftMSStorePath;
|
||||||
|
#else
|
||||||
|
partialPath = QDir::homePath();
|
||||||
|
#endif
|
||||||
|
auto minecraftDataPath = FS::PathCombine(partialPath, ".minecraft", "runtime");
|
||||||
|
processpaths << minecraftDataPath;
|
||||||
|
|
||||||
|
QStringList javas;
|
||||||
|
while (!processpaths.isEmpty()) {
|
||||||
|
auto dirPath = processpaths.takeFirst();
|
||||||
|
QDir dir(dirPath);
|
||||||
|
if (!dir.exists())
|
||||||
|
continue;
|
||||||
|
auto entries = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
auto binFound = false;
|
||||||
|
for (auto& entry : entries) {
|
||||||
|
if (entry.baseName() == "bin") {
|
||||||
|
javas.append(FS::PathCombine(entry.canonicalFilePath(), executable));
|
||||||
|
binFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!binFound) {
|
||||||
|
for (auto& entry : entries) {
|
||||||
|
processpaths << entry.canonicalFilePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return javas;
|
||||||
|
}
|
||||||
|
@ -26,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();
|
||||||
|
|
||||||
class JavaUtils : public QObject {
|
class JavaUtils : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -45,10 +45,12 @@ QString JavaVersion::toString() const
|
|||||||
|
|
||||||
bool JavaVersion::requiresPermGen()
|
bool JavaVersion::requiresPermGen()
|
||||||
{
|
{
|
||||||
if (m_parseable) {
|
return !m_parseable || m_major < 8;
|
||||||
return m_major < 8;
|
}
|
||||||
}
|
|
||||||
return true;
|
bool JavaVersion::isModular()
|
||||||
|
{
|
||||||
|
return m_parseable && m_major >= 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JavaVersion::operator<(const JavaVersion& rhs)
|
bool JavaVersion::operator<(const JavaVersion& rhs)
|
||||||
|
@ -14,7 +14,7 @@ class JavaVersion {
|
|||||||
friend class JavaVersionTest;
|
friend class JavaVersionTest;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JavaVersion(){};
|
JavaVersion() {}
|
||||||
JavaVersion(const QString& rhs);
|
JavaVersion(const QString& rhs);
|
||||||
|
|
||||||
JavaVersion& operator=(const QString& rhs);
|
JavaVersion& operator=(const QString& rhs);
|
||||||
@ -25,6 +25,8 @@ class JavaVersion {
|
|||||||
|
|
||||||
bool requiresPermGen();
|
bool requiresPermGen();
|
||||||
|
|
||||||
|
bool isModular();
|
||||||
|
|
||||||
QString toString() const;
|
QString toString() const;
|
||||||
|
|
||||||
int major() { return m_major; }
|
int major() { return m_major; }
|
||||||
|
@ -30,7 +30,7 @@ class LogModel : public QAbstractListModel {
|
|||||||
|
|
||||||
enum Roles { LevelRole = Qt::UserRole };
|
enum Roles { LevelRole = Qt::UserRole };
|
||||||
|
|
||||||
private /* types */:
|
private /* types */:
|
||||||
struct entry {
|
struct entry {
|
||||||
MessageLevel::Enum level;
|
MessageLevel::Enum level;
|
||||||
QString line;
|
QString line;
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
#include "BaseEntity.h"
|
#include "BaseEntity.h"
|
||||||
|
|
||||||
#include "Json.h"
|
#include "Json.h"
|
||||||
#include "net/Download.h"
|
#include "net/ApiDownload.h"
|
||||||
#include "net/HttpMetaCache.h"
|
#include "net/HttpMetaCache.h"
|
||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ class ParsingValidator : public Net::Validator {
|
|||||||
bool init(QNetworkRequest&) override { return true; }
|
bool init(QNetworkRequest&) override { return true; }
|
||||||
bool write(QByteArray& data) override
|
bool write(QByteArray& data) override
|
||||||
{
|
{
|
||||||
this->data.append(data);
|
this->m_data.append(data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool abort() override { return true; }
|
bool abort() override { return true; }
|
||||||
@ -40,7 +40,7 @@ class ParsingValidator : public Net::Validator {
|
|||||||
{
|
{
|
||||||
auto fname = m_entity->localFilename();
|
auto fname = m_entity->localFilename();
|
||||||
try {
|
try {
|
||||||
auto doc = Json::requireDocument(data, fname);
|
auto doc = Json::requireDocument(m_data, fname);
|
||||||
auto obj = Json::requireObject(doc, fname);
|
auto obj = Json::requireObject(doc, fname);
|
||||||
m_entity->parse(obj);
|
m_entity->parse(obj);
|
||||||
return true;
|
return true;
|
||||||
@ -51,7 +51,7 @@ class ParsingValidator : public Net::Validator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private: /* data */
|
private: /* data */
|
||||||
QByteArray data;
|
QByteArray m_data;
|
||||||
Meta::BaseEntity* m_entity;
|
Meta::BaseEntity* m_entity;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ void Meta::BaseEntity::load(Net::Mode loadType)
|
|||||||
auto url = this->url();
|
auto url = this->url();
|
||||||
auto entry = APPLICATION->metacache()->resolveEntry("meta", localFilename());
|
auto entry = APPLICATION->metacache()->resolveEntry("meta", localFilename());
|
||||||
entry->setStale(true);
|
entry->setStale(true);
|
||||||
auto dl = Net::Download::makeCached(url, entry);
|
auto dl = Net::ApiDownload::makeCached(url, entry);
|
||||||
/*
|
/*
|
||||||
* The validator parses the file and loads it into the object.
|
* The validator parses the file and loads it into the object.
|
||||||
* If that fails, the file is not written to storage.
|
* If that fails, the file is not written to storage.
|
||||||
|
@ -55,6 +55,6 @@ class Index : public QAbstractListModel, public BaseEntity {
|
|||||||
QVector<VersionList::Ptr> m_lists;
|
QVector<VersionList::Ptr> m_lists;
|
||||||
QHash<QString, VersionList::Ptr> m_uids;
|
QHash<QString, VersionList::Ptr> m_uids;
|
||||||
|
|
||||||
void connectVersionList(const int row, const VersionList::Ptr& list);
|
void connectVersionList(int row, const VersionList::Ptr& list);
|
||||||
};
|
};
|
||||||
} // namespace Meta
|
} // namespace Meta
|
||||||
|
@ -64,7 +64,7 @@ class Version : public QObject, public BaseVersion, public BaseEntity {
|
|||||||
|
|
||||||
public: // for usage by format parsers only
|
public: // for usage by format parsers only
|
||||||
void setType(const QString& type);
|
void setType(const QString& type);
|
||||||
void setTime(const qint64 time);
|
void setTime(qint64 time);
|
||||||
void setRequires(const Meta::RequireSet& reqs, const Meta::RequireSet& conflicts);
|
void setRequires(const Meta::RequireSet& reqs, const Meta::RequireSet& conflicts);
|
||||||
void setVolatile(bool volatile_);
|
void setVolatile(bool volatile_);
|
||||||
void setRecommended(bool recommended);
|
void setRecommended(bool recommended);
|
||||||
|
@ -79,7 +79,7 @@ class VersionList : public BaseVersionList, public BaseEntity {
|
|||||||
|
|
||||||
Version::Ptr m_recommended;
|
Version::Ptr m_recommended;
|
||||||
|
|
||||||
void setupAddedVersion(const int row, const Version::Ptr& version);
|
void setupAddedVersion(int row, const Version::Ptr& version);
|
||||||
};
|
};
|
||||||
} // namespace Meta
|
} // namespace Meta
|
||||||
Q_DECLARE_METATYPE(Meta::VersionList::Ptr)
|
Q_DECLARE_METATYPE(Meta::VersionList::Ptr)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
class Agent;
|
class Agent;
|
||||||
|
|
||||||
typedef std::shared_ptr<Agent> AgentPtr;
|
using AgentPtr = std::shared_ptr<Agent>;
|
||||||
|
|
||||||
class Agent {
|
class Agent {
|
||||||
public:
|
public:
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include "AssetsUtils.h"
|
#include "AssetsUtils.h"
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
#include "net/ApiDownload.h"
|
||||||
#include "net/ChecksumValidator.h"
|
#include "net/ChecksumValidator.h"
|
||||||
#include "net/Download.h"
|
#include "net/Download.h"
|
||||||
|
|
||||||
@ -279,7 +280,7 @@ NetAction::Ptr AssetObject::getDownloadAction()
|
|||||||
{
|
{
|
||||||
QFileInfo objectFile(getLocalPath());
|
QFileInfo objectFile(getLocalPath());
|
||||||
if ((!objectFile.isFile()) || (objectFile.size() != size)) {
|
if ((!objectFile.isFile()) || (objectFile.size() != size)) {
|
||||||
auto objectDL = Net::Download::makeFile(getUrl(), objectFile.filePath());
|
auto objectDL = Net::ApiDownload::makeFile(getUrl(), objectFile.filePath());
|
||||||
if (hash.size()) {
|
if (hash.size()) {
|
||||||
auto rawHash = QByteArray::fromHex(hash.toLatin1());
|
auto rawHash = QByteArray::fromHex(hash.toLatin1());
|
||||||
objectDL->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawHash));
|
objectDL->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawHash));
|
||||||
|
@ -25,7 +25,8 @@ class Component : public QObject, public ProblemProvider {
|
|||||||
Component(PackProfile* parent, std::shared_ptr<Meta::Version> version);
|
Component(PackProfile* parent, std::shared_ptr<Meta::Version> version);
|
||||||
Component(PackProfile* parent, const QString& uid, std::shared_ptr<VersionFile> file);
|
Component(PackProfile* parent, const QString& uid, std::shared_ptr<VersionFile> file);
|
||||||
|
|
||||||
virtual ~Component(){};
|
virtual ~Component() {}
|
||||||
|
|
||||||
void applyTo(LaunchProfile* profile);
|
void applyTo(LaunchProfile* profile);
|
||||||
|
|
||||||
bool isEnabled();
|
bool isEnabled();
|
||||||
@ -104,4 +105,4 @@ class Component : public QObject, public ProblemProvider {
|
|||||||
bool m_loaded = false;
|
bool m_loaded = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef shared_qobject_ptr<Component> ComponentPtr;
|
using ComponentPtr = shared_qobject_ptr<Component>;
|
||||||
|
@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
#include "Component.h"
|
#include "Component.h"
|
||||||
#include "ComponentUpdateTask_p.h"
|
#include "ComponentUpdateTask_p.h"
|
||||||
#include "OneSixVersionFormat.h"
|
|
||||||
#include "PackProfile.h"
|
#include "PackProfile.h"
|
||||||
#include "PackProfile_p.h"
|
#include "PackProfile_p.h"
|
||||||
#include "Version.h"
|
#include "Version.h"
|
||||||
#include "cassert"
|
#include "cassert"
|
||||||
#include "meta/Index.h"
|
#include "meta/Index.h"
|
||||||
#include "meta/Version.h"
|
#include "meta/Version.h"
|
||||||
#include "meta/VersionList.h"
|
#include "minecraft/OneSixVersionFormat.h"
|
||||||
|
#include "minecraft/ProfileUtils.h"
|
||||||
#include "net/Mode.h"
|
#include "net/Mode.h"
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
class LaunchProfile : public ProblemProvider {
|
class LaunchProfile : public ProblemProvider {
|
||||||
public:
|
public:
|
||||||
virtual ~LaunchProfile(){};
|
virtual ~LaunchProfile() {}
|
||||||
|
|
||||||
public: /* application of profile variables from patches */
|
public: /* application of profile variables from patches */
|
||||||
void applyMinecraftVersion(const QString& id);
|
void applyMinecraftVersion(const QString& id);
|
||||||
|
@ -38,8 +38,8 @@
|
|||||||
|
|
||||||
#include <BuildConfig.h>
|
#include <BuildConfig.h>
|
||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
|
#include <net/ApiDownload.h>
|
||||||
#include <net/ChecksumValidator.h>
|
#include <net/ChecksumValidator.h>
|
||||||
#include <net/Download.h>
|
|
||||||
|
|
||||||
void Library::getApplicableFiles(const RuntimeContext& runtimeContext,
|
void Library::getApplicableFiles(const RuntimeContext& runtimeContext,
|
||||||
QStringList& jar,
|
QStringList& jar,
|
||||||
@ -115,12 +115,12 @@ QList<NetAction::Ptr> Library::getDownloads(const RuntimeContext& runtimeContext
|
|||||||
|
|
||||||
if (sha1.size()) {
|
if (sha1.size()) {
|
||||||
auto rawSha1 = QByteArray::fromHex(sha1.toLatin1());
|
auto rawSha1 = QByteArray::fromHex(sha1.toLatin1());
|
||||||
auto dl = Net::Download::makeCached(url, entry, options);
|
auto dl = Net::ApiDownload::makeCached(url, entry, options);
|
||||||
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1));
|
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1));
|
||||||
qDebug() << "Checksummed Download for:" << rawName().serialize() << "storage:" << storage << "url:" << url;
|
qDebug() << "Checksummed Download for:" << rawName().serialize() << "storage:" << storage << "url:" << url;
|
||||||
out.append(dl);
|
out.append(dl);
|
||||||
} else {
|
} else {
|
||||||
out.append(Net::Download::makeCached(url, entry, options));
|
out.append(Net::ApiDownload::makeCached(url, entry, options));
|
||||||
qDebug() << "Download for:" << rawName().serialize() << "storage:" << storage << "url:" << url;
|
qDebug() << "Download for:" << rawName().serialize() << "storage:" << storage << "url:" << url;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -52,7 +52,7 @@
|
|||||||
class Library;
|
class Library;
|
||||||
class MinecraftInstance;
|
class MinecraftInstance;
|
||||||
|
|
||||||
typedef std::shared_ptr<Library> LibraryPtr;
|
using LibraryPtr = std::shared_ptr<Library>;
|
||||||
|
|
||||||
class Library {
|
class Library {
|
||||||
friend class OneSixVersionFormat;
|
friend class OneSixVersionFormat;
|
||||||
|
@ -3,8 +3,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) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
* Copyright (C) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
|
||||||
* Copyright (c) 2023 seth <getchoo at tuta dot io>
|
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -88,6 +87,10 @@
|
|||||||
#include "minecraft/gameoptions/GameOptions.h"
|
#include "minecraft/gameoptions/GameOptions.h"
|
||||||
#include "minecraft/update/FoldersTask.h"
|
#include "minecraft/update/FoldersTask.h"
|
||||||
|
|
||||||
|
#include "tools/BaseProfiler.h"
|
||||||
|
|
||||||
|
#include <QActionGroup>
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
#include "MangoHud.h"
|
#include "MangoHud.h"
|
||||||
#endif
|
#endif
|
||||||
@ -166,22 +169,28 @@ void MinecraftInstance::loadSpecificSettings()
|
|||||||
// Native library workarounds
|
// Native library workarounds
|
||||||
auto nativeLibraryWorkaroundsOverride = m_settings->registerSetting("OverrideNativeWorkarounds", false);
|
auto nativeLibraryWorkaroundsOverride = m_settings->registerSetting("OverrideNativeWorkarounds", false);
|
||||||
m_settings->registerOverride(global_settings->getSetting("UseNativeOpenAL"), nativeLibraryWorkaroundsOverride);
|
m_settings->registerOverride(global_settings->getSetting("UseNativeOpenAL"), nativeLibraryWorkaroundsOverride);
|
||||||
|
m_settings->registerOverride(global_settings->getSetting("CustomOpenALPath"), nativeLibraryWorkaroundsOverride);
|
||||||
m_settings->registerOverride(global_settings->getSetting("UseNativeGLFW"), nativeLibraryWorkaroundsOverride);
|
m_settings->registerOverride(global_settings->getSetting("UseNativeGLFW"), nativeLibraryWorkaroundsOverride);
|
||||||
|
m_settings->registerOverride(global_settings->getSetting("CustomGLFWPath"), nativeLibraryWorkaroundsOverride);
|
||||||
|
|
||||||
// Peformance related options
|
// Performance related options
|
||||||
auto performanceOverride = m_settings->registerSetting("OverridePerformance", false);
|
auto performanceOverride = m_settings->registerSetting("OverridePerformance", false);
|
||||||
m_settings->registerOverride(global_settings->getSetting("EnableFeralGamemode"), performanceOverride);
|
m_settings->registerOverride(global_settings->getSetting("EnableFeralGamemode"), performanceOverride);
|
||||||
m_settings->registerOverride(global_settings->getSetting("EnableMangoHud"), performanceOverride);
|
m_settings->registerOverride(global_settings->getSetting("EnableMangoHud"), performanceOverride);
|
||||||
m_settings->registerOverride(global_settings->getSetting("UseDiscreteGpu"), performanceOverride);
|
m_settings->registerOverride(global_settings->getSetting("UseDiscreteGpu"), performanceOverride);
|
||||||
|
m_settings->registerOverride(global_settings->getSetting("UseZink"), performanceOverride);
|
||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
auto miscellaneousOverride = m_settings->registerSetting("OverrideMiscellaneous", false);
|
auto miscellaneousOverride = m_settings->registerSetting("OverrideMiscellaneous", false);
|
||||||
m_settings->registerOverride(global_settings->getSetting("CloseAfterLaunch"), miscellaneousOverride);
|
m_settings->registerOverride(global_settings->getSetting("CloseAfterLaunch"), miscellaneousOverride);
|
||||||
m_settings->registerOverride(global_settings->getSetting("QuitAfterGameStop"), miscellaneousOverride);
|
m_settings->registerOverride(global_settings->getSetting("QuitAfterGameStop"), miscellaneousOverride);
|
||||||
|
|
||||||
// Mod loader specific options
|
// Legacy-related options
|
||||||
auto modLoaderSettings = m_settings->registerSetting("OverrideModLoaderSettings", false);
|
auto legacySettings = m_settings->registerSetting("OverrideLegacySettings", false);
|
||||||
m_settings->registerOverride(global_settings->getSetting("DisableQuiltBeacon"), modLoaderSettings);
|
m_settings->registerOverride(global_settings->getSetting("OnlineFixes"), legacySettings);
|
||||||
|
|
||||||
|
auto envSetting = m_settings->registerSetting("OverrideEnv", false);
|
||||||
|
m_settings->registerOverride(global_settings->getSetting("Env"), envSetting);
|
||||||
|
|
||||||
m_settings->set("InstanceType", "OneSix");
|
m_settings->set("InstanceType", "OneSix");
|
||||||
}
|
}
|
||||||
@ -194,6 +203,12 @@ void MinecraftInstance::loadSpecificSettings()
|
|||||||
m_settings->registerSetting("UseAccountForInstance", false);
|
m_settings->registerSetting("UseAccountForInstance", false);
|
||||||
m_settings->registerSetting("InstanceAccountId", "");
|
m_settings->registerSetting("InstanceAccountId", "");
|
||||||
|
|
||||||
|
m_settings->registerSetting("ExportName", "");
|
||||||
|
m_settings->registerSetting("ExportVersion", "1.0.0");
|
||||||
|
m_settings->registerSetting("ExportSummary", "");
|
||||||
|
m_settings->registerSetting("ExportAuthor", "");
|
||||||
|
m_settings->registerSetting("ExportOptionalFiles", true);
|
||||||
|
|
||||||
qDebug() << "Instance-type specific settings were loaded!";
|
qDebug() << "Instance-type specific settings were loaded!";
|
||||||
|
|
||||||
setSpecificSettingsLoaded(true);
|
setSpecificSettingsLoaded(true);
|
||||||
@ -229,15 +244,59 @@ QSet<QString> MinecraftInstance::traits() const
|
|||||||
return profile->getTraits();
|
return profile->getTraits();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: move UI code out of MinecraftInstance
|
||||||
|
void MinecraftInstance::populateLaunchMenu(QMenu* menu)
|
||||||
|
{
|
||||||
|
QAction* normalLaunch = menu->addAction(tr("&Launch"));
|
||||||
|
normalLaunch->setShortcut(QKeySequence::Open);
|
||||||
|
QAction* normalLaunchOffline = menu->addAction(tr("Launch &Offline"));
|
||||||
|
normalLaunchOffline->setShortcut(QKeySequence(tr("Ctrl+Shift+O")));
|
||||||
|
QAction* normalLaunchDemo = menu->addAction(tr("Launch &Demo"));
|
||||||
|
normalLaunchDemo->setShortcut(QKeySequence(tr("Ctrl+Alt+O")));
|
||||||
|
|
||||||
|
normalLaunchDemo->setEnabled(supportsDemo());
|
||||||
|
|
||||||
|
connect(normalLaunch, &QAction::triggered, [this] { APPLICATION->launch(shared_from_this()); });
|
||||||
|
connect(normalLaunchOffline, &QAction::triggered, [this] { APPLICATION->launch(shared_from_this(), false, false); });
|
||||||
|
connect(normalLaunchDemo, &QAction::triggered, [this] { APPLICATION->launch(shared_from_this(), false, true); });
|
||||||
|
|
||||||
|
QString profilersTitle = tr("Profilers");
|
||||||
|
menu->addSeparator()->setText(profilersTitle);
|
||||||
|
|
||||||
|
auto profilers = new QActionGroup(menu);
|
||||||
|
profilers->setExclusive(true);
|
||||||
|
connect(profilers, &QActionGroup::triggered, [this](QAction* action) {
|
||||||
|
settings()->set("Profiler", action->data());
|
||||||
|
emit profilerChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
QAction* noProfilerAction = menu->addAction(tr("&No Profiler"));
|
||||||
|
noProfilerAction->setData("");
|
||||||
|
noProfilerAction->setCheckable(true);
|
||||||
|
noProfilerAction->setChecked(true);
|
||||||
|
profilers->addAction(noProfilerAction);
|
||||||
|
|
||||||
|
for (auto profiler = APPLICATION->profilers().begin(); profiler != APPLICATION->profilers().end(); profiler++) {
|
||||||
|
QAction* profilerAction = menu->addAction(profiler.value()->name());
|
||||||
|
profilers->addAction(profilerAction);
|
||||||
|
profilerAction->setData(profiler.key());
|
||||||
|
profilerAction->setCheckable(true);
|
||||||
|
profilerAction->setChecked(settings()->get("Profiler").toString() == profiler.key());
|
||||||
|
|
||||||
|
QString error;
|
||||||
|
profilerAction->setEnabled(profiler.value()->check(&error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString MinecraftInstance::gameRoot() const
|
QString MinecraftInstance::gameRoot() const
|
||||||
{
|
{
|
||||||
QFileInfo mcDir(FS::PathCombine(instanceRoot(), "minecraft"));
|
QFileInfo mcDir(FS::PathCombine(instanceRoot(), "minecraft"));
|
||||||
QFileInfo dotMCDir(FS::PathCombine(instanceRoot(), ".minecraft"));
|
QFileInfo dotMCDir(FS::PathCombine(instanceRoot(), ".minecraft"));
|
||||||
|
|
||||||
if (mcDir.exists() && !dotMCDir.exists())
|
if (dotMCDir.exists() && !mcDir.exists())
|
||||||
return mcDir.filePath();
|
|
||||||
else
|
|
||||||
return dotMCDir.filePath();
|
return dotMCDir.filePath();
|
||||||
|
else
|
||||||
|
return mcDir.filePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MinecraftInstance::binRoot() const
|
QString MinecraftInstance::binRoot() const
|
||||||
@ -260,7 +319,7 @@ QString MinecraftInstance::getLocalLibraryPath() const
|
|||||||
bool MinecraftInstance::supportsDemo() const
|
bool MinecraftInstance::supportsDemo() const
|
||||||
{
|
{
|
||||||
Version instance_ver{ getPackProfile()->getComponentVersion("net.minecraft") };
|
Version instance_ver{ getPackProfile()->getComponentVersion("net.minecraft") };
|
||||||
// Demo mode was introduced in 1.3.1: https://minecraft.fandom.com/wiki/Demo_mode#History
|
// Demo mode was introduced in 1.3.1: https://minecraft.wiki/w/Demo_mode#History
|
||||||
// FIXME: Due to Version constraints atm, this can't handle well non-release versions
|
// FIXME: Due to Version constraints atm, this can't handle well non-release versions
|
||||||
return instance_ver >= Version("1.3.1");
|
return instance_ver >= Version("1.3.1");
|
||||||
}
|
}
|
||||||
@ -385,10 +444,31 @@ QStringList MinecraftInstance::extraArguments()
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const auto loaders = version->getModLoaders();
|
QString openALPath;
|
||||||
if (loaders.has_value() && loaders.value() & ResourceAPI::Quilt && settings()->get("DisableQuiltBeacon").toBool())
|
QString glfwPath;
|
||||||
list.append("-Dloader.disable_beacon=true");
|
|
||||||
|
if (settings()->get("UseNativeOpenAL").toBool()) {
|
||||||
|
openALPath = APPLICATION->m_detectedOpenALPath;
|
||||||
|
auto customPath = settings()->get("CustomOpenALPath").toString();
|
||||||
|
if (!customPath.isEmpty())
|
||||||
|
openALPath = customPath;
|
||||||
|
}
|
||||||
|
if (settings()->get("UseNativeGLFW").toBool()) {
|
||||||
|
glfwPath = APPLICATION->m_detectedGLFWPath;
|
||||||
|
auto customPath = settings()->get("CustomGLFWPath").toString();
|
||||||
|
if (!customPath.isEmpty())
|
||||||
|
glfwPath = customPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFileInfo openALInfo(openALPath);
|
||||||
|
QFileInfo glfwInfo(glfwPath);
|
||||||
|
|
||||||
|
if (!openALPath.isEmpty() && openALInfo.exists())
|
||||||
|
list.append("-Dorg.lwjgl.openal.libname=" + openALInfo.absoluteFilePath());
|
||||||
|
if (!glfwPath.isEmpty() && glfwInfo.exists())
|
||||||
|
list.append("-Dorg.lwjgl.glfw.libname=" + glfwInfo.absoluteFilePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,20 +521,28 @@ QStringList MinecraftInstance::javaArguments()
|
|||||||
|
|
||||||
args << "-Duser.language=en";
|
args << "-Duser.language=en";
|
||||||
|
|
||||||
|
if (javaVersion.isModular() && shouldApplyOnlineFixes())
|
||||||
|
// allow reflective access to java.net - required by the skin fix
|
||||||
|
args << "--add-opens"
|
||||||
|
<< "java.base/java.net=ALL-UNNAMED";
|
||||||
|
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MinecraftInstance::getLauncher()
|
QString MinecraftInstance::getLauncher()
|
||||||
{
|
{
|
||||||
auto profile = m_components->getProfile();
|
|
||||||
|
|
||||||
// use legacy launcher if the traits are set
|
// use legacy launcher if the traits are set
|
||||||
if (profile->getTraits().contains("legacyLaunch") || profile->getTraits().contains("alphaLaunch"))
|
if (traits().contains("legacyLaunch") || traits().contains("alphaLaunch"))
|
||||||
return "legacy";
|
return "legacy";
|
||||||
|
|
||||||
return "standard";
|
return "standard";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MinecraftInstance::shouldApplyOnlineFixes()
|
||||||
|
{
|
||||||
|
return traits().contains("legacyServices") && settings()->get("OnlineFixes").toBool();
|
||||||
|
}
|
||||||
|
|
||||||
QMap<QString, QString> MinecraftInstance::getVariables()
|
QMap<QString, QString> MinecraftInstance::getVariables()
|
||||||
{
|
{
|
||||||
QMap<QString, QString> out;
|
QMap<QString, QString> out;
|
||||||
@ -464,6 +552,7 @@ QMap<QString, QString> MinecraftInstance::getVariables()
|
|||||||
out.insert("INST_MC_DIR", QDir::toNativeSeparators(QDir(gameRoot()).absolutePath()));
|
out.insert("INST_MC_DIR", QDir::toNativeSeparators(QDir(gameRoot()).absolutePath()));
|
||||||
out.insert("INST_JAVA", settings()->get("JavaPath").toString());
|
out.insert("INST_JAVA", settings()->get("JavaPath").toString());
|
||||||
out.insert("INST_JAVA_ARGS", javaArguments().join(' '));
|
out.insert("INST_JAVA_ARGS", javaArguments().join(' '));
|
||||||
|
out.insert("NO_COLOR", "1");
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,6 +566,22 @@ QProcessEnvironment MinecraftInstance::createEnvironment()
|
|||||||
for (auto it = variables.begin(); it != variables.end(); ++it) {
|
for (auto it = variables.begin(); it != variables.end(); ++it) {
|
||||||
env.insert(it.key(), it.value());
|
env.insert(it.key(), it.value());
|
||||||
}
|
}
|
||||||
|
// custom env
|
||||||
|
|
||||||
|
auto insertEnv = [&env](QMap<QString, QVariant> envMap) {
|
||||||
|
if (envMap.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto iter = envMap.begin(); iter != envMap.end(); iter++)
|
||||||
|
env.insert(iter.key(), iter.value().toString());
|
||||||
|
};
|
||||||
|
|
||||||
|
bool overrideEnv = settings()->get("OverrideEnv").toBool();
|
||||||
|
|
||||||
|
if (!overrideEnv)
|
||||||
|
insertEnv(APPLICATION->settings()->get("Env").toMap());
|
||||||
|
else
|
||||||
|
insertEnv(settings()->get("Env").toMap());
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,20 +592,26 @@ QProcessEnvironment MinecraftInstance::createLaunchEnvironment()
|
|||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
if (settings()->get("EnableMangoHud").toBool() && APPLICATION->capabilities() & Application::SupportsMangoHud) {
|
if (settings()->get("EnableMangoHud").toBool() && APPLICATION->capabilities() & Application::SupportsMangoHud) {
|
||||||
auto preloadList = env.value("LD_PRELOAD").split(QLatin1String(":"));
|
QStringList preloadList;
|
||||||
auto libPaths = env.value("LD_LIBRARY_PATH").split(QLatin1String(":"));
|
if (auto value = env.value("LD_PRELOAD"); !value.isEmpty())
|
||||||
|
preloadList = value.split(QLatin1String(":"));
|
||||||
|
|
||||||
auto mangoHudLibString = MangoHud::getLibraryString();
|
auto mangoHudLibString = MangoHud::getLibraryString();
|
||||||
if (!mangoHudLibString.isEmpty()) {
|
if (!mangoHudLibString.isEmpty()) {
|
||||||
QFileInfo mangoHudLib(mangoHudLibString);
|
QFileInfo mangoHudLib(mangoHudLibString);
|
||||||
|
QString libPath = mangoHudLib.absolutePath();
|
||||||
|
auto appendLib = [libPath, &preloadList](QString fileName) {
|
||||||
|
if (QFileInfo(FS::PathCombine(libPath, fileName)).exists())
|
||||||
|
preloadList << FS::PathCombine(libPath, fileName);
|
||||||
|
};
|
||||||
|
|
||||||
// dlsym variant is only needed for OpenGL and not included in the vulkan layer
|
// dlsym variant is only needed for OpenGL and not included in the vulkan layer
|
||||||
preloadList << "libMangoHud_dlsym.so" << mangoHudLib.fileName();
|
appendLib("libMangoHud_dlsym.so");
|
||||||
libPaths << mangoHudLib.absolutePath();
|
appendLib("libMangoHud_opengl.so");
|
||||||
|
appendLib(mangoHudLib.fileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
env.insert("LD_PRELOAD", preloadList.join(QLatin1String(":")));
|
env.insert("LD_PRELOAD", preloadList.join(QLatin1String(":")));
|
||||||
env.insert("LD_LIBRARY_PATH", libPaths.join(QLatin1String(":")));
|
|
||||||
env.insert("MANGOHUD", "1");
|
env.insert("MANGOHUD", "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,8 +623,14 @@ QProcessEnvironment MinecraftInstance::createLaunchEnvironment()
|
|||||||
env.insert("__VK_LAYER_NV_optimus", "NVIDIA_only");
|
env.insert("__VK_LAYER_NV_optimus", "NVIDIA_only");
|
||||||
env.insert("__GLX_VENDOR_LIBRARY_NAME", "nvidia");
|
env.insert("__GLX_VENDOR_LIBRARY_NAME", "nvidia");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
if (settings()->get("UseZink").toBool()) {
|
||||||
|
// taken from https://wiki.archlinux.org/title/OpenGL#OpenGL_over_Vulkan_(Zink)
|
||||||
|
env.insert("__GLX_VENDOR_LIBRARY_NAME", "mesa");
|
||||||
|
env.insert("MESA_LOADER_DRIVER_OVERRIDE", "zink");
|
||||||
|
env.insert("GALLIUM_DRIVER", "zink");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -630,7 +747,7 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS
|
|||||||
{
|
{
|
||||||
QString windowParams;
|
QString windowParams;
|
||||||
if (settings()->get("LaunchMaximized").toBool())
|
if (settings()->get("LaunchMaximized").toBool())
|
||||||
windowParams = "max";
|
windowParams = "maximized";
|
||||||
else
|
else
|
||||||
windowParams =
|
windowParams =
|
||||||
QString("%1x%2").arg(settings()->get("MinecraftWinWidth").toInt()).arg(settings()->get("MinecraftWinHeight").toInt());
|
QString("%1x%2").arg(settings()->get("MinecraftWinWidth").toInt()).arg(settings()->get("MinecraftWinHeight").toInt());
|
||||||
@ -638,6 +755,19 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS
|
|||||||
launchScript += "windowParams " + windowParams + "\n";
|
launchScript += "windowParams " + windowParams + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// launcher info
|
||||||
|
{
|
||||||
|
launchScript += "launcherBrand " + BuildConfig.LAUNCHER_NAME + "\n";
|
||||||
|
launchScript += "launcherVersion " + BuildConfig.printableVersionString() + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// instance info
|
||||||
|
{
|
||||||
|
launchScript += "instanceName " + name() + "\n";
|
||||||
|
launchScript += "instanceIconKey " + name() + "\n";
|
||||||
|
launchScript += "instanceIconPath icon.png\n"; // we already save a copy here
|
||||||
|
}
|
||||||
|
|
||||||
// legacy auth
|
// legacy auth
|
||||||
if (session) {
|
if (session) {
|
||||||
launchScript += "userName " + session->player_name + "\n";
|
launchScript += "userName " + session->player_name + "\n";
|
||||||
@ -648,6 +778,9 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS
|
|||||||
launchScript += "traits " + trait + "\n";
|
launchScript += "traits " + trait + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shouldApplyOnlineFixes())
|
||||||
|
launchScript += "onlineFixes true\n";
|
||||||
|
|
||||||
launchScript += "launcher " + getLauncher() + "\n";
|
launchScript += "launcher " + getLauncher() + "\n";
|
||||||
|
|
||||||
// qDebug() << "Generated launch script:" << launchScript;
|
// qDebug() << "Generated launch script:" << launchScript;
|
||||||
@ -788,9 +921,6 @@ QMap<QString, QString> MinecraftInstance::createCensorFilterFromSession(AuthSess
|
|||||||
if (sessionRef.access_token != "0") {
|
if (sessionRef.access_token != "0") {
|
||||||
addToFilter(sessionRef.access_token, tr("<ACCESS TOKEN>"));
|
addToFilter(sessionRef.access_token, tr("<ACCESS TOKEN>"));
|
||||||
}
|
}
|
||||||
if (sessionRef.client_token.size()) {
|
|
||||||
addToFilter(sessionRef.client_token, tr("<CLIENT TOKEN>"));
|
|
||||||
}
|
|
||||||
addToFilter(sessionRef.uuid, tr("<PROFILE ID>"));
|
addToFilter(sessionRef.uuid, tr("<PROFILE ID>"));
|
||||||
|
|
||||||
return filter;
|
return filter;
|
||||||
@ -872,13 +1002,16 @@ QString MinecraftInstance::getStatusbarDescription()
|
|||||||
if (m_settings->get("ShowGameTime").toBool()) {
|
if (m_settings->get("ShowGameTime").toBool()) {
|
||||||
if (lastTimePlayed() > 0) {
|
if (lastTimePlayed() > 0) {
|
||||||
QDateTime lastLaunchTime = QDateTime::fromMSecsSinceEpoch(lastLaunch());
|
QDateTime lastLaunchTime = QDateTime::fromMSecsSinceEpoch(lastLaunch());
|
||||||
description.append(tr(", last played on %1 for %2")
|
description.append(
|
||||||
.arg(QLocale().toString(lastLaunchTime, QLocale::ShortFormat))
|
tr(", last played on %1 for %2")
|
||||||
.arg(Time::prettifyDuration(lastTimePlayed())));
|
.arg(QLocale().toString(lastLaunchTime, QLocale::ShortFormat))
|
||||||
|
.arg(Time::prettifyDuration(lastTimePlayed(), APPLICATION->settings()->get("ShowGameTimeWithoutDays").toBool())));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalTimePlayed() > 0) {
|
if (totalTimePlayed() > 0) {
|
||||||
description.append(tr(", total played for %1").arg(Time::prettifyDuration(totalTimePlayed())));
|
description.append(
|
||||||
|
tr(", total played for %1")
|
||||||
|
.arg(Time::prettifyDuration(totalTimePlayed(), APPLICATION->settings()->get("ShowGameTimeWithoutDays").toBool())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasCrashed()) {
|
if (hasCrashed()) {
|
||||||
|
@ -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) 2022 TheKodeToad <TheKodeToad@proton.me>
|
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -70,6 +70,8 @@ class MinecraftInstance : public BaseInstance {
|
|||||||
|
|
||||||
bool canExport() const override { return true; }
|
bool canExport() const override { return true; }
|
||||||
|
|
||||||
|
void populateLaunchMenu(QMenu* menu) override;
|
||||||
|
|
||||||
////// Directories and files //////
|
////// Directories and files //////
|
||||||
QString jarModsDir() const;
|
QString jarModsDir() const;
|
||||||
QString resourcePacksDir() const;
|
QString resourcePacksDir() const;
|
||||||
@ -127,6 +129,7 @@ class MinecraftInstance : public BaseInstance {
|
|||||||
/// get arguments passed to java
|
/// get arguments passed to java
|
||||||
QStringList javaArguments();
|
QStringList javaArguments();
|
||||||
QString getLauncher();
|
QString getLauncher();
|
||||||
|
bool shouldApplyOnlineFixes();
|
||||||
|
|
||||||
/// get variables for launch command variable substitution/environment
|
/// get variables for launch command variable substitution/environment
|
||||||
QMap<QString, QString> getVariables() override;
|
QMap<QString, QString> getVariables() override;
|
||||||
@ -171,4 +174,4 @@ class MinecraftInstance : public BaseInstance {
|
|||||||
mutable std::shared_ptr<GameOptions> m_game_options;
|
mutable std::shared_ptr<GameOptions> m_game_options;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<MinecraftInstance> MinecraftInstancePtr;
|
using MinecraftInstancePtr = std::shared_ptr<MinecraftInstance>;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
struct MojangDownloadInfo {
|
struct MojangDownloadInfo {
|
||||||
// types
|
// types
|
||||||
typedef std::shared_ptr<MojangDownloadInfo> Ptr;
|
using Ptr = std::shared_ptr<MojangDownloadInfo>;
|
||||||
|
|
||||||
// data
|
// data
|
||||||
/// Local filesystem path. WARNING: not used, only here so we can pass through mojang files unmolested!
|
/// Local filesystem path. WARNING: not used, only here so we can pass through mojang files unmolested!
|
||||||
@ -19,11 +19,11 @@ struct MojangDownloadInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct MojangLibraryDownloadInfo {
|
struct MojangLibraryDownloadInfo {
|
||||||
MojangLibraryDownloadInfo(MojangDownloadInfo::Ptr artifact) : artifact(artifact){};
|
MojangLibraryDownloadInfo(MojangDownloadInfo::Ptr artifact_) : artifact(artifact_) {}
|
||||||
MojangLibraryDownloadInfo(){};
|
MojangLibraryDownloadInfo() {}
|
||||||
|
|
||||||
// types
|
// types
|
||||||
typedef std::shared_ptr<MojangLibraryDownloadInfo> Ptr;
|
using Ptr = std::shared_ptr<MojangLibraryDownloadInfo>;
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
MojangDownloadInfo* getDownloadInfo(QString classifier)
|
MojangDownloadInfo* getDownloadInfo(QString classifier)
|
||||||
@ -42,23 +42,23 @@ struct MojangLibraryDownloadInfo {
|
|||||||
|
|
||||||
struct MojangAssetIndexInfo : public MojangDownloadInfo {
|
struct MojangAssetIndexInfo : public MojangDownloadInfo {
|
||||||
// types
|
// types
|
||||||
typedef std::shared_ptr<MojangAssetIndexInfo> Ptr;
|
using Ptr = std::shared_ptr<MojangAssetIndexInfo>;
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
MojangAssetIndexInfo() {}
|
MojangAssetIndexInfo() {}
|
||||||
|
|
||||||
MojangAssetIndexInfo(QString id)
|
MojangAssetIndexInfo(QString id_)
|
||||||
{
|
{
|
||||||
this->id = id;
|
this->id = id_;
|
||||||
// HACK: ignore assets from other version files than Minecraft
|
// HACK: ignore assets from other version files than Minecraft
|
||||||
// workaround for stupid assets issue caused by amazon:
|
// workaround for stupid assets issue caused by amazon:
|
||||||
// https://www.theregister.co.uk/2017/02/28/aws_is_awol_as_s3_goes_haywire/
|
// https://www.theregister.co.uk/2017/02/28/aws_is_awol_as_s3_goes_haywire/
|
||||||
if (id == "legacy") {
|
if (id_ == "legacy") {
|
||||||
url = "https://piston-meta.mojang.com/mc/assets/legacy/c0fd82e8ce9fbc93119e40d96d5a4e62cfa3f729/legacy.json";
|
url = "https://piston-meta.mojang.com/mc/assets/legacy/c0fd82e8ce9fbc93119e40d96d5a4e62cfa3f729/legacy.json";
|
||||||
}
|
}
|
||||||
// HACK
|
// HACK
|
||||||
else {
|
else {
|
||||||
url = "https://s3.amazonaws.com/Minecraft.Download/indexes/" + id + ".json";
|
url = "https://s3.amazonaws.com/Minecraft.Download/indexes/" + id_ + ".json";
|
||||||
}
|
}
|
||||||
known = false;
|
known = false;
|
||||||
}
|
}
|
||||||
|
@ -157,20 +157,6 @@ void MojangVersionFormat::readVersionProperties(const QJsonObject& in, VersionFi
|
|||||||
Bits::readString(in, "id", out->minecraftVersion);
|
Bits::readString(in, "id", out->minecraftVersion);
|
||||||
Bits::readString(in, "mainClass", out->mainClass);
|
Bits::readString(in, "mainClass", out->mainClass);
|
||||||
Bits::readString(in, "minecraftArguments", out->minecraftArguments);
|
Bits::readString(in, "minecraftArguments", out->minecraftArguments);
|
||||||
if (out->minecraftArguments.isEmpty()) {
|
|
||||||
QString processArguments;
|
|
||||||
Bits::readString(in, "processArguments", processArguments);
|
|
||||||
QString toCompare = processArguments.toLower();
|
|
||||||
if (toCompare == "legacy") {
|
|
||||||
out->minecraftArguments = " ${auth_player_name} ${auth_session}";
|
|
||||||
} else if (toCompare == "username_session") {
|
|
||||||
out->minecraftArguments = "--username ${auth_player_name} --session ${auth_session}";
|
|
||||||
} else if (toCompare == "username_session_version") {
|
|
||||||
out->minecraftArguments = "--username ${auth_player_name} --session ${auth_session} --version ${profile_name}";
|
|
||||||
} else if (!toCompare.isEmpty()) {
|
|
||||||
out->addProblem(ProblemSeverity::Error, QObject::tr("processArguments is set to unknown value '%1'").arg(processArguments));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Bits::readString(in, "type", out->type);
|
Bits::readString(in, "type", out->type);
|
||||||
|
|
||||||
Bits::readString(in, "assets", out->assets);
|
Bits::readString(in, "assets", out->assets);
|
||||||
|
@ -350,7 +350,7 @@ QJsonDocument OneSixVersionFormat::versionFileToJson(const VersionFilePtr& patch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LibraryPtr OneSixVersionFormat::plusJarModFromJson(ProblemContainer& problems,
|
LibraryPtr OneSixVersionFormat::plusJarModFromJson([[maybe_unused]] ProblemContainer& problems,
|
||||||
const QJsonObject& libObj,
|
const QJsonObject& libObj,
|
||||||
const QString& filename,
|
const QString& filename,
|
||||||
const QString& originalName)
|
const QString& originalName)
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
class OneSixVersionFormat {
|
class OneSixVersionFormat {
|
||||||
public:
|
public:
|
||||||
// version files / profile patches
|
// version files / profile patches
|
||||||
static VersionFilePtr versionFileFromJson(const QJsonDocument& doc, const QString& filename, const bool requireOrder);
|
static VersionFilePtr versionFileFromJson(const QJsonDocument& doc, const QString& filename, bool requireOrder);
|
||||||
static QJsonDocument versionFileToJson(const VersionFilePtr& patch);
|
static QJsonDocument versionFileToJson(const VersionFilePtr& patch);
|
||||||
|
|
||||||
// libraries
|
// libraries
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user