mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2025-05-04 08:34:30 +02:00
Compare commits
No commits in common. "develop" and "8.0" have entirely different histories.
21
.clang-tidy
21
.clang-tidy
@ -1,23 +1,4 @@
|
|||||||
Checks:
|
Checks:
|
||||||
- modernize-use-using
|
- modernize-use-using
|
||||||
- readability-avoid-const-params-in-decls
|
|
||||||
- misc-unused-parameters,
|
|
||||||
- readability-identifier-naming
|
|
||||||
|
|
||||||
# ^ Without unused-parameters the readability-identifier-naming check doesn't cause any warnings.
|
SystemHeaders: false
|
||||||
|
|
||||||
CheckOptions:
|
|
||||||
- { key: readability-identifier-naming.ClassCase, value: PascalCase }
|
|
||||||
- { key: readability-identifier-naming.EnumCase, value: PascalCase }
|
|
||||||
- { key: readability-identifier-naming.FunctionCase, value: camelCase }
|
|
||||||
- { key: readability-identifier-naming.GlobalVariableCase, value: camelCase }
|
|
||||||
- { key: readability-identifier-naming.GlobalFunctionCase, value: camelCase }
|
|
||||||
- { key: readability-identifier-naming.GlobalConstantCase, value: SCREAMING_SNAKE_CASE }
|
|
||||||
- { key: readability-identifier-naming.MacroDefinitionCase, value: SCREAMING_SNAKE_CASE }
|
|
||||||
- { key: readability-identifier-naming.ClassMemberCase, value: camelCase }
|
|
||||||
- { key: readability-identifier-naming.PrivateMemberPrefix, value: m_ }
|
|
||||||
- { key: readability-identifier-naming.ProtectedMemberPrefix, value: m_ }
|
|
||||||
- { key: readability-identifier-naming.PrivateStaticMemberPrefix, value: s_ }
|
|
||||||
- { key: readability-identifier-naming.ProtectedStaticMemberPrefix, value: s_ }
|
|
||||||
- { key: readability-identifier-naming.PublicStaticConstantCase, value: SCREAMING_SNAKE_CASE }
|
|
||||||
- { key: readability-identifier-naming.EnumConstantCase, value: SCREAMING_SNAKE_CASE }
|
|
||||||
|
@ -2,12 +2,3 @@
|
|||||||
|
|
||||||
# tabs -> spaces
|
# tabs -> spaces
|
||||||
bbb3b3e6f6e3c0f95873f22e6d0a4aaf350f49d9
|
bbb3b3e6f6e3c0f95873f22e6d0a4aaf350f49d9
|
||||||
|
|
||||||
# (nix) alejandra -> nixfmt
|
|
||||||
4c81d8c53d09196426568c4a31a4e752ed05397a
|
|
||||||
|
|
||||||
# reformat codebase
|
|
||||||
1d468ac35ad88d8c77cc83f25e3704d9bd7df01b
|
|
||||||
|
|
||||||
# format a part of codebase
|
|
||||||
5c8481a118c8fefbfe901001d7828eaf6866eac4
|
|
||||||
|
103
.github/actions/get-merge-commit/action.yml
vendored
103
.github/actions/get-merge-commit/action.yml
vendored
@ -1,103 +0,0 @@
|
|||||||
# This file incorporates work covered by the following copyright and
|
|
||||||
# permission notice
|
|
||||||
#
|
|
||||||
# Copyright (c) 2003-2025 Eelco Dolstra and the Nixpkgs/NixOS contributors
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
name: Get merge commit
|
|
||||||
description: Get a merge commit of a given pull request
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
repository:
|
|
||||||
description: Repository containing the pull request
|
|
||||||
required: false
|
|
||||||
pull-request-id:
|
|
||||||
description: ID of a pull request
|
|
||||||
required: true
|
|
||||||
|
|
||||||
outputs:
|
|
||||||
merge-commit-sha:
|
|
||||||
description: Git SHA of a merge commit
|
|
||||||
value: ${{ steps.query.outputs.merge-commit-sha }}
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Wait for GitHub to report merge commit
|
|
||||||
id: query
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
GITHUB_REPO: ${{ inputs.repository || github.repository }}
|
|
||||||
PR_ID: ${{ inputs.pull-request-id }}
|
|
||||||
# https://github.com/NixOS/nixpkgs/blob/8f77f3600f1ee775b85dc2c72fd842768e486ec9/ci/get-merge-commit.sh
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
log() {
|
|
||||||
echo "$@" >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
# Retry the API query this many times
|
|
||||||
retryCount=5
|
|
||||||
# Start with 5 seconds, but double every retry
|
|
||||||
retryInterval=5
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
log "Checking whether the pull request can be merged"
|
|
||||||
prInfo=$(gh api \
|
|
||||||
-H "Accept: application/vnd.github+json" \
|
|
||||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
||||||
"/repos/$GITHUB_REPO/pulls/$PR_ID")
|
|
||||||
|
|
||||||
# Non-open PRs won't have their mergeability computed no matter what
|
|
||||||
state=$(jq -r .state <<<"$prInfo")
|
|
||||||
if [[ "$state" != open ]]; then
|
|
||||||
log "PR is not open anymore"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
mergeable=$(jq -r .mergeable <<<"$prInfo")
|
|
||||||
if [[ "$mergeable" == "null" ]]; then
|
|
||||||
if ((retryCount == 0)); then
|
|
||||||
log "Not retrying anymore. It's likely that GitHub is having internal issues: check https://www.githubstatus.com/"
|
|
||||||
exit 3
|
|
||||||
else
|
|
||||||
((retryCount -= 1)) || true
|
|
||||||
|
|
||||||
# null indicates that GitHub is still computing whether it's mergeable
|
|
||||||
# Wait a couple seconds before trying again
|
|
||||||
log "GitHub is still computing whether this PR can be merged, waiting $retryInterval seconds before trying again ($retryCount retries left)"
|
|
||||||
sleep "$retryInterval"
|
|
||||||
|
|
||||||
((retryInterval *= 2)) || true
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ "$mergeable" == "true" ]]; then
|
|
||||||
echo "merge-commit-sha=$(jq -r .merge_commit_sha <<<"$prInfo")" >> "$GITHUB_OUTPUT"
|
|
||||||
else
|
|
||||||
echo "# 🚨 The PR has a merge conflict!" >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
exit 2
|
|
||||||
fi
|
|
124
.github/actions/package/linux/action.yml
vendored
124
.github/actions/package/linux/action.yml
vendored
@ -1,124 +0,0 @@
|
|||||||
name: Package for Linux
|
|
||||||
description: Create Linux packages for Prism Launcher
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
version:
|
|
||||||
description: Launcher version
|
|
||||||
required: true
|
|
||||||
build-type:
|
|
||||||
description: Type for the build
|
|
||||||
required: true
|
|
||||||
default: Debug
|
|
||||||
artifact-name:
|
|
||||||
description: Name of the uploaded artifact
|
|
||||||
required: true
|
|
||||||
default: Linux
|
|
||||||
cmake-preset:
|
|
||||||
description: Base CMake preset previously used for the build
|
|
||||||
required: true
|
|
||||||
default: linux
|
|
||||||
qt-version:
|
|
||||||
description: Version of Qt to use
|
|
||||||
required: true
|
|
||||||
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
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Package AppImage
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
VERSION: ${{ inputs.version }}
|
|
||||||
BUILD_DIR: build
|
|
||||||
INSTALL_APPIMAGE_DIR: install-appdir
|
|
||||||
|
|
||||||
GPG_PRIVATE_KEY: ${{ inputs.gpg-private-key }}
|
|
||||||
run: |
|
|
||||||
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
|
|
||||||
export "NO_APPSTREAM=1" # we have to skip appstream checking because appstream on ubuntu 20.04 is outdated
|
|
||||||
|
|
||||||
export OUTPUT="PrismLauncher-Linux-x86_64.AppImage"
|
|
||||||
|
|
||||||
chmod +x linuxdeploy-*.AppImage
|
|
||||||
|
|
||||||
mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib
|
|
||||||
mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines
|
|
||||||
|
|
||||||
cp -r ${{ runner.workspace }}/Qt/${{ inputs.qt-version }}/gcc_64/plugins/iconengines/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines
|
|
||||||
|
|
||||||
cp /usr/lib/x86_64-linux-gnu/libcrypto.so.* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
|
|
||||||
cp /usr/lib/x86_64-linux-gnu/libssl.so.* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
|
|
||||||
cp /usr/lib/x86_64-linux-gnu/libOpenGL.so.0* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
|
|
||||||
|
|
||||||
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib"
|
|
||||||
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 [ '${{ inputs.gpg-private-key-id }}' != '' ]; then
|
|
||||||
export SIGN=1
|
|
||||||
export SIGN_KEY=${{ inputs.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
|
|
||||||
|
|
||||||
mv "PrismLauncher-Linux-x86_64.AppImage" "PrismLauncher-Linux-${{ env.VERSION }}-${{ inputs.build-type }}-x86_64.AppImage"
|
|
||||||
|
|
||||||
- name: Package portable tarball
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
BUILD_DIR: build
|
|
||||||
|
|
||||||
CMAKE_PRESET: ${{ inputs.cmake-preset }}
|
|
||||||
|
|
||||||
INSTALL_PORTABLE_DIR: install-portable
|
|
||||||
run: |
|
|
||||||
cmake --preset "$CMAKE_PRESET" -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_PORTABLE_DIR }} -DINSTALL_BUNDLE=full
|
|
||||||
cmake --install ${{ env.BUILD_DIR }}
|
|
||||||
cmake --install ${{ env.BUILD_DIR }} --component portable
|
|
||||||
|
|
||||||
mkdir ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
|
||||||
cp /lib/x86_64-linux-gnu/libbz2.so.1.0 ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
|
||||||
cp /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0 ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
|
||||||
cp /usr/lib/x86_64-linux-gnu/libcrypto.so.* ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
|
||||||
cp /usr/lib/x86_64-linux-gnu/libssl.so.* ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
|
||||||
cp /usr/lib/x86_64-linux-gnu/libffi.so.*.* ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
|
||||||
mv ${{ env.INSTALL_PORTABLE_DIR }}/bin/*.so* ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
|
||||||
|
|
||||||
for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt
|
|
||||||
cd ${{ env.INSTALL_PORTABLE_DIR }}
|
|
||||||
tar -czf ../PrismLauncher-portable.tar.gz *
|
|
||||||
|
|
||||||
- name: Upload binary tarball
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-Qt6-Portable-${{ inputs.version }}-${{ inputs.build-type }}
|
|
||||||
path: PrismLauncher-portable.tar.gz
|
|
||||||
|
|
||||||
- name: Upload AppImage
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}-x86_64.AppImage
|
|
||||||
path: PrismLauncher-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-x86_64.AppImage
|
|
||||||
|
|
||||||
- name: Upload AppImage Zsync
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}-x86_64.AppImage.zsync
|
|
||||||
path: PrismLauncher-Linux-x86_64.AppImage.zsync
|
|
121
.github/actions/package/macos/action.yml
vendored
121
.github/actions/package/macos/action.yml
vendored
@ -1,121 +0,0 @@
|
|||||||
name: Package for macOS
|
|
||||||
description: Create a macOS package for Prism Launcher
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
version:
|
|
||||||
description: Launcher version
|
|
||||||
required: true
|
|
||||||
build-type:
|
|
||||||
description: Type for the build
|
|
||||||
required: true
|
|
||||||
default: Debug
|
|
||||||
artifact-name:
|
|
||||||
description: Name of the uploaded artifact
|
|
||||||
required: true
|
|
||||||
default: macOS
|
|
||||||
apple-codesign-cert:
|
|
||||||
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
|
|
||||||
sparkle-ed25519-key:
|
|
||||||
description: Private key for signing Sparkle updates
|
|
||||||
required: false
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Fetch codesign certificate
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo '${{ inputs.apple-codesign-cert }}' | base64 --decode > codesign.p12
|
|
||||||
if [ -n '${{ inputs.apple-codesign-id }}' ]; then
|
|
||||||
security create-keychain -p '${{ inputs.apple-codesign-password }}' build.keychain
|
|
||||||
security default-keychain -s build.keychain
|
|
||||||
security unlock-keychain -p '${{ inputs.apple-codesign-password }}' build.keychain
|
|
||||||
security import codesign.p12 -k build.keychain -P '${{ inputs.apple-codesign-password }}' -T /usr/bin/codesign
|
|
||||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k '${{ inputs.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
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
BUILD_DIR: build
|
|
||||||
INSTALL_DIR: install
|
|
||||||
run: |
|
|
||||||
cmake --install ${{ env.BUILD_DIR }}
|
|
||||||
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
|
||||||
chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
|
||||||
|
|
||||||
if [ -n '${{ inputs.apple-codesign-id }}' ]; then
|
|
||||||
APPLE_CODESIGN_ID='${{ inputs.apple-codesign-id }}'
|
|
||||||
ENTITLEMENTS_FILE='../program_info/App.entitlements'
|
|
||||||
else
|
|
||||||
APPLE_CODESIGN_ID='-'
|
|
||||||
ENTITLEMENTS_FILE='../program_info/AdhocSignedApp.entitlements'
|
|
||||||
fi
|
|
||||||
|
|
||||||
sudo codesign --sign "$APPLE_CODESIGN_ID" --deep --force --entitlements "$ENTITLEMENTS_FILE" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
|
||||||
mv "PrismLauncher.app" "Prism Launcher.app"
|
|
||||||
|
|
||||||
- name: Notarize
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
INSTALL_DIR: install
|
|
||||||
run: |
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
|
||||||
|
|
||||||
if [ -n '${{ inputs.apple-notarize-password }}' ]; then
|
|
||||||
ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip
|
|
||||||
xcrun notarytool submit ../PrismLauncher.zip \
|
|
||||||
--wait --progress \
|
|
||||||
--apple-id '${{ inputs.apple-notarize-apple-id }}' \
|
|
||||||
--team-id '${{ inputs.apple-notarize-team-id }}' \
|
|
||||||
--password '${{ inputs.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
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
if [ '${{ inputs.sparkle-ed25519-key }}' != '' ]; then
|
|
||||||
echo '${{ inputs.sparkle-ed25519-key }}' > ed25519-priv.pem
|
|
||||||
signature=$(/opt/homebrew/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
|
|
||||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
|
||||||
### Artifact Information :information_source:
|
|
||||||
- :memo: Sparkle Signature (ed25519): \`$signature\`
|
|
||||||
EOF
|
|
||||||
else
|
|
||||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
|
||||||
### Artifact Information :information_source:
|
|
||||||
- :warning: Sparkle Signature (ed25519): No private key available (likely a pull request or fork)
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Upload binary tarball
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}
|
|
||||||
path: PrismLauncher.zip
|
|
143
.github/actions/package/windows/action.yml
vendored
143
.github/actions/package/windows/action.yml
vendored
@ -1,143 +0,0 @@
|
|||||||
name: Package for Windows
|
|
||||||
description: Create a Windows package for Prism Launcher
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
version:
|
|
||||||
description: Launcher version
|
|
||||||
required: true
|
|
||||||
build-type:
|
|
||||||
description: Type for the build
|
|
||||||
required: true
|
|
||||||
default: Debug
|
|
||||||
artifact-name:
|
|
||||||
description: Name of the uploaded artifact
|
|
||||||
required: true
|
|
||||||
msystem:
|
|
||||||
description: MSYS2 subsystem to use
|
|
||||||
required: true
|
|
||||||
default: false
|
|
||||||
windows-codesign-cert:
|
|
||||||
description: Certificate for signing Windows builds
|
|
||||||
required: false
|
|
||||||
windows-codesign-password:
|
|
||||||
description: Password for signing Windows builds
|
|
||||||
required: false
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Package (MinGW)
|
|
||||||
if: ${{ inputs.msystem != '' }}
|
|
||||||
shell: msys2 {0}
|
|
||||||
env:
|
|
||||||
BUILD_DIR: build
|
|
||||||
INSTALL_DIR: install
|
|
||||||
run: |
|
|
||||||
cmake --install ${{ env.BUILD_DIR }}
|
|
||||||
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
|
|
||||||
|
|
||||||
- name: Package (MSVC)
|
|
||||||
if: ${{ inputs.msystem == '' }}
|
|
||||||
shell: pwsh
|
|
||||||
env:
|
|
||||||
BUILD_DIR: build
|
|
||||||
INSTALL_DIR: install
|
|
||||||
run: |
|
|
||||||
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }}
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
- name: Fetch codesign certificate
|
|
||||||
shell: bash # yes, we are not using MSYS2 or PowerShell here
|
|
||||||
run: |
|
|
||||||
echo '${{ inputs.windows-codesign-cert }}' | base64 --decode > codesign.pfx
|
|
||||||
|
|
||||||
- name: Sign executable
|
|
||||||
shell: pwsh
|
|
||||||
env:
|
|
||||||
INSTALL_DIR: install
|
|
||||||
run: |
|
|
||||||
if (Get-Content ./codesign.pfx){
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
|
||||||
# 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 '${{ inputs.windows-codesign-password }}' /tr http://timestamp.digicert.com prismlauncher.exe prismlauncher_updater.exe prismlauncher_filelink.exe
|
|
||||||
} else {
|
|
||||||
":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY
|
|
||||||
}
|
|
||||||
|
|
||||||
- name: Package (MinGW, portable)
|
|
||||||
if: ${{ inputs.msystem != '' }}
|
|
||||||
shell: msys2 {0}
|
|
||||||
env:
|
|
||||||
BUILD_DIR: build
|
|
||||||
INSTALL_DIR: install
|
|
||||||
INSTALL_PORTABLE_DIR: install-portable
|
|
||||||
run: |
|
|
||||||
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
|
|
||||||
for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f); do l=$(cygpath -u $l); l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done >> ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt
|
|
||||||
|
|
||||||
- name: Package (MSVC, portable)
|
|
||||||
if: ${{ inputs.msystem == '' }}
|
|
||||||
shell: pwsh
|
|
||||||
env:
|
|
||||||
BUILD_DIR: build
|
|
||||||
INSTALL_DIR: install
|
|
||||||
INSTALL_PORTABLE_DIR: install-portable
|
|
||||||
run: |
|
|
||||||
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
|
|
||||||
|
|
||||||
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 (installer)
|
|
||||||
shell: pwsh
|
|
||||||
env:
|
|
||||||
BUILD_DIR: build
|
|
||||||
INSTALL_DIR: install
|
|
||||||
|
|
||||||
NSCURL_VERSION: "v24.9.26.122"
|
|
||||||
NSCURL_SHA256: "AEE6C4BE3CB6455858E9C1EE4B3AFE0DB9960FA03FE99CCDEDC28390D57CCBB0"
|
|
||||||
run: |
|
|
||||||
New-Item -Name NSISPlugins -ItemType Directory
|
|
||||||
Invoke-Webrequest https://github.com/negrutiu/nsis-nscurl/releases/download/"${{ env.NSCURL_VERSION }}"/NScurl.zip -OutFile NSISPlugins\NScurl.zip
|
|
||||||
$nscurl_hash = Get-FileHash NSISPlugins\NScurl.zip -Algorithm Sha256 | Select-Object -ExpandProperty Hash
|
|
||||||
if ( $nscurl_hash -ne "${{ env.nscurl_sha256 }}") {
|
|
||||||
echo "::error:: NSCurl.zip sha256 mismatch"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
Expand-Archive -Path NSISPlugins\NScurl.zip -DestinationPath NSISPlugins\NScurl
|
|
||||||
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
|
||||||
makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi"
|
|
||||||
|
|
||||||
- name: Sign installer
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
if (Get-Content ./codesign.pfx){
|
|
||||||
SignTool sign /fd sha256 /td sha256 /f codesign.pfx /p '${{ inputs.windows-codesign-password }}' /tr http://timestamp.digicert.com PrismLauncher-Setup.exe
|
|
||||||
} else {
|
|
||||||
":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY
|
|
||||||
}
|
|
||||||
|
|
||||||
- name: Upload binary zip
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}
|
|
||||||
path: install/**
|
|
||||||
|
|
||||||
- name: Upload portable zip
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-Portable-${{ inputs.version }}-${{ inputs.build-type }}
|
|
||||||
path: install-portable/**
|
|
||||||
|
|
||||||
- name: Upload installer
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-Setup-${{ inputs.version }}-${{ inputs.build-type }}
|
|
||||||
path: PrismLauncher-Setup.exe
|
|
78
.github/actions/setup-dependencies/action.yml
vendored
78
.github/actions/setup-dependencies/action.yml
vendored
@ -1,78 +0,0 @@
|
|||||||
name: Setup Dependencies
|
|
||||||
description: Install and setup dependencies for building Prism Launcher
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
build-type:
|
|
||||||
description: Type for the build
|
|
||||||
required: true
|
|
||||||
default: Debug
|
|
||||||
msystem:
|
|
||||||
description: MSYS2 subsystem to use
|
|
||||||
required: false
|
|
||||||
vcvars-arch:
|
|
||||||
description: Visual Studio architecture to use
|
|
||||||
required: false
|
|
||||||
qt-architecture:
|
|
||||||
description: Qt architecture
|
|
||||||
required: false
|
|
||||||
qt-version:
|
|
||||||
description: Version of Qt to use
|
|
||||||
required: true
|
|
||||||
default: 6.8.1
|
|
||||||
|
|
||||||
outputs:
|
|
||||||
build-type:
|
|
||||||
description: Type of build used
|
|
||||||
value: ${{ inputs.build-type }}
|
|
||||||
qt-version:
|
|
||||||
description: Version of Qt used
|
|
||||||
value: ${{ inputs.qt-version }}
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Setup Linux dependencies
|
|
||||||
if: ${{ runner.os == 'Linux' }}
|
|
||||||
uses: ./.github/actions/setup-dependencies/linux
|
|
||||||
|
|
||||||
- name: Setup macOS dependencies
|
|
||||||
if: ${{ runner.os == 'macOS' }}
|
|
||||||
uses: ./.github/actions/setup-dependencies/macos
|
|
||||||
|
|
||||||
- name: Setup Windows dependencies
|
|
||||||
if: ${{ runner.os == 'Windows' }}
|
|
||||||
uses: ./.github/actions/setup-dependencies/windows
|
|
||||||
with:
|
|
||||||
build-type: ${{ inputs.build-type }}
|
|
||||||
msystem: ${{ inputs.msystem }}
|
|
||||||
vcvars-arch: ${{ inputs.vcvars-arch }}
|
|
||||||
|
|
||||||
# TODO(@getchoo): Get this working on MSYS2!
|
|
||||||
- name: Setup ccache
|
|
||||||
if: ${{ (runner.os != 'Windows' || inputs.msystem == '') && inputs.build-type == 'Debug' }}
|
|
||||||
uses: hendrikmuhs/ccache-action@v1.2.18
|
|
||||||
with:
|
|
||||||
variant: ${{ runner.os == 'Windows' && 'sccache' || 'ccache' }}
|
|
||||||
create-symlink: ${{ runner.os != 'Windows' }}
|
|
||||||
key: ${{ runner.os }}-qt${{ inputs.qt_ver }}-${{ inputs.architecture }}
|
|
||||||
|
|
||||||
- name: Use ccache on debug builds
|
|
||||||
if: ${{ inputs.build-type == 'Debug' }}
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
# Only use sccache on MSVC
|
|
||||||
CCACHE_VARIANT: ${{ (runner.os == 'Windows' && inputs.msystem == '') && 'sccache' || 'ccache' }}
|
|
||||||
run: |
|
|
||||||
echo "CMAKE_C_COMPILER_LAUNCHER=$CCACHE_VARIANT" >> "$GITHUB_ENV"
|
|
||||||
echo "CMAKE_CXX_COMPILER_LAUNCHER=$CCACHE_VARIANT" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Install Qt
|
|
||||||
if: ${{ inputs.msystem == '' }}
|
|
||||||
uses: jurplel/install-qt-action@v4
|
|
||||||
with:
|
|
||||||
aqtversion: "==3.1.*"
|
|
||||||
version: ${{ inputs.qt-version }}
|
|
||||||
arch: ${{ inputs.qt-architecture }}
|
|
||||||
modules: qt5compat qtimageformats qtnetworkauth
|
|
||||||
cache: ${{ inputs.build-type == 'Debug' }}
|
|
@ -1,26 +0,0 @@
|
|||||||
name: Setup Linux dependencies
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Install host dependencies
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
sudo apt-get -y update
|
|
||||||
sudo apt-get -y install ninja-build extra-cmake-modules scdoc appstream libxcb-cursor-dev
|
|
||||||
|
|
||||||
- name: Setup AppImage tooling
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
declare -A appimage_deps
|
|
||||||
appimage_deps["https://github.com/linuxdeploy/linuxdeploy/releases/download/1-alpha-20250213-2/linuxdeploy-x86_64.AppImage"]="4648f278ab3ef31f819e67c30d50f462640e5365a77637d7e6f2ad9fd0b4522a linuxdeploy-x86_64.AppImage"
|
|
||||||
appimage_deps["https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/1-alpha-20250213-1/linuxdeploy-plugin-qt-x86_64.AppImage"]="15106be885c1c48a021198e7e1e9a48ce9d02a86dd0a1848f00bdbf3c1c92724 linuxdeploy-plugin-qt-x86_64.AppImage"
|
|
||||||
appimage_deps["https://github.com/AppImageCommunity/AppImageUpdate/releases/download/2.0.0-alpha-1-20241225/AppImageUpdate-x86_64.AppImage"]="f1747cf60058e99f1bb9099ee9787d16c10241313b7acec81810ea1b1e568c11 AppImageUpdate-x86_64.AppImage"
|
|
||||||
|
|
||||||
for url in "${!appimage_deps[@]}"; do
|
|
||||||
curl -LO "$url"
|
|
||||||
sha256sum -c - <<< "${appimage_deps[$url]}"
|
|
||||||
done
|
|
||||||
|
|
||||||
sudo apt -y install libopengl0
|
|
@ -1,16 +0,0 @@
|
|||||||
name: Setup macOS dependencies
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Install dependencies
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
brew update
|
|
||||||
brew install ninja extra-cmake-modules temurin@17
|
|
||||||
|
|
||||||
- name: Set JAVA_HOME
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "JAVA_HOME=$(/usr/libexec/java_home -v 17)" >> "$GITHUB_ENV"
|
|
@ -1,66 +0,0 @@
|
|||||||
name: Setup Windows Dependencies
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
build-type:
|
|
||||||
description: Type for the build
|
|
||||||
required: true
|
|
||||||
default: Debug
|
|
||||||
msystem:
|
|
||||||
description: MSYS2 subsystem to use
|
|
||||||
required: false
|
|
||||||
vcvars-arch:
|
|
||||||
description: Visual Studio architecture to use
|
|
||||||
required: true
|
|
||||||
default: amd64
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
|
|
||||||
steps:
|
|
||||||
# NOTE: Installed on MinGW as well for SignTool
|
|
||||||
- name: Enter VS Developer shell
|
|
||||||
if: ${{ runner.os == 'Windows' }}
|
|
||||||
uses: ilammy/msvc-dev-cmd@v1
|
|
||||||
with:
|
|
||||||
arch: ${{ inputs.vcvars-arch }}
|
|
||||||
vsversion: 2022
|
|
||||||
|
|
||||||
- name: Setup MSYS2 (MinGW-64)
|
|
||||||
if: ${{ inputs.msystem != '' }}
|
|
||||||
uses: msys2/setup-msys2@v2
|
|
||||||
with:
|
|
||||||
msystem: ${{ inputs.msystem }}
|
|
||||||
update: true
|
|
||||||
install: >-
|
|
||||||
git
|
|
||||||
pacboy: >-
|
|
||||||
toolchain:p
|
|
||||||
ccache:p
|
|
||||||
cmake:p
|
|
||||||
extra-cmake-modules:p
|
|
||||||
ninja:p
|
|
||||||
qt6-base:p
|
|
||||||
qt6-svg:p
|
|
||||||
qt6-imageformats:p
|
|
||||||
qt6-5compat:p
|
|
||||||
qt6-networkauth:p
|
|
||||||
cmark:p
|
|
||||||
quazip-qt6:p
|
|
||||||
|
|
||||||
- name: Retrieve ccache cache (MinGW)
|
|
||||||
if: ${{ inputs.msystem != '' && inputs.build-type == 'Debug' }}
|
|
||||||
uses: actions/cache@v4.2.3
|
|
||||||
with:
|
|
||||||
path: '${{ github.workspace }}\.ccache'
|
|
||||||
key: ${{ runner.os }}-mingw-w64-ccache-${{ github.run_id }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-mingw-w64-ccache
|
|
||||||
|
|
||||||
- name: Setup ccache (MinGW)
|
|
||||||
if: ${{ inputs.msystem != '' && inputs.build-type == 'Debug' }}
|
|
||||||
shell: msys2 {0}
|
|
||||||
run: |
|
|
||||||
ccache --set-config=cache_dir='${{ github.workspace }}\.ccache'
|
|
||||||
ccache --set-config=max_size='500M'
|
|
||||||
ccache --set-config=compression=true
|
|
||||||
ccache -p # Show config
|
|
41
.github/scripts/prepare_JREs.sh
vendored
Executable file
41
.github/scripts/prepare_JREs.sh
vendored
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
URL_JDK8="https://api.adoptium.net/v3/binary/version/jdk8u312-b07/linux/x64/jre/hotspot/normal/eclipse"
|
||||||
|
URL_JDK17="https://api.adoptium.net/v3/binary/latest/17/ga/linux/x64/jre/hotspot/normal/eclipse"
|
||||||
|
|
||||||
|
mkdir -p JREs
|
||||||
|
pushd JREs
|
||||||
|
|
||||||
|
wget --content-disposition "$URL_JDK8"
|
||||||
|
wget --content-disposition "$URL_JDK17"
|
||||||
|
|
||||||
|
for file in *;
|
||||||
|
do
|
||||||
|
mkdir temp
|
||||||
|
|
||||||
|
re='(OpenJDK([[:digit:]]+)U-jre_x64_linux_hotspot_([[:digit:]]+)(.*).tar.gz)'
|
||||||
|
if [[ $file =~ $re ]];
|
||||||
|
then
|
||||||
|
version_major=${BASH_REMATCH[2]}
|
||||||
|
version_trailing=${BASH_REMATCH[4]}
|
||||||
|
|
||||||
|
if [ $version_major = 17 ];
|
||||||
|
then
|
||||||
|
hyphen='-'
|
||||||
|
else
|
||||||
|
hyphen=''
|
||||||
|
fi
|
||||||
|
|
||||||
|
version_edit=$(echo $version_trailing | sed -e 's/_/+/g' | sed -e 's/b/-b/g')
|
||||||
|
dir_name=jdk$hyphen$version_major$version_edit-jre
|
||||||
|
mkdir jre$version_major
|
||||||
|
tar -xzf $file -C temp
|
||||||
|
pushd temp/$dir_name
|
||||||
|
cp -r . ../../jre$version_major
|
||||||
|
popd
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf temp
|
||||||
|
done
|
||||||
|
|
||||||
|
popd
|
3
.github/workflows/backport.yml
vendored
3
.github/workflows/backport.yml
vendored
@ -16,7 +16,6 @@ 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
|
||||||
@ -25,7 +24,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
- name: Create backport PRs
|
- name: Create backport PRs
|
||||||
uses: korthout/backport-action@v3.2.0
|
uses: korthout/backport-action@v2.1.0
|
||||||
with:
|
with:
|
||||||
# Config README: https://github.com/korthout/backport-action#backport-action
|
# Config README: https://github.com/korthout/backport-action#backport-action
|
||||||
pull_description: |-
|
pull_description: |-
|
||||||
|
239
.github/workflows/blocked-prs.yml
vendored
239
.github/workflows/blocked-prs.yml
vendored
@ -1,239 +0,0 @@
|
|||||||
name: Blocked/Stacked Pull Requests Automation
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
types:
|
|
||||||
- opened
|
|
||||||
- reopened
|
|
||||||
- edited
|
|
||||||
- synchronize
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
pr_id:
|
|
||||||
description: Local Pull Request number to work on
|
|
||||||
required: true
|
|
||||||
type: number
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
blocked_status:
|
|
||||||
name: Check Blocked Status
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Generate token
|
|
||||||
id: generate-token
|
|
||||||
uses: actions/create-github-app-token@v2
|
|
||||||
with:
|
|
||||||
app-id: ${{ vars.PULL_REQUEST_APP_ID }}
|
|
||||||
private-key: ${{ secrets.PULL_REQUEST_APP_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Setup From Dispatch Event
|
|
||||||
if: github.event_name == 'workflow_dispatch'
|
|
||||||
id: dispatch_event_setup
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
PR_NUMBER: ${{ inputs.pr_id }}
|
|
||||||
run: |
|
|
||||||
# setup env for the rest of the workflow
|
|
||||||
OWNER=$(dirname "${{ github.repository }}")
|
|
||||||
REPO=$(basename "${{ github.repository }}")
|
|
||||||
PR_JSON=$(
|
|
||||||
gh api \
|
|
||||||
-H "Accept: application/vnd.github.raw+json" \
|
|
||||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
||||||
"/repos/$OWNER/$REPO/pulls/$PR_NUMBER"
|
|
||||||
)
|
|
||||||
echo "PR_JSON=$PR_JSON" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Setup Environment
|
|
||||||
id: env_setup
|
|
||||||
env:
|
|
||||||
EVENT_PR_JSON: ${{ toJSON(github.event.pull_request) }}
|
|
||||||
run: |
|
|
||||||
# setup env for the rest of the workflow
|
|
||||||
PR_JSON=${PR_JSON:-"$EVENT_PR_JSON"}
|
|
||||||
{
|
|
||||||
echo "REPO=$(jq -r '.base.repo.name' <<< "$PR_JSON")"
|
|
||||||
echo "OWNER=$(jq -r '.base.repo.owner.login' <<< "$PR_JSON")"
|
|
||||||
echo "PR_NUMBER=$(jq -r '.number' <<< "$PR_JSON")"
|
|
||||||
echo "JOB_DATA=$(jq -c '
|
|
||||||
{
|
|
||||||
"repo": .base.repo.name,
|
|
||||||
"owner": .base.repo.owner.login,
|
|
||||||
"repoUrl": .base.repo.html_url,
|
|
||||||
"prNumber": .number,
|
|
||||||
"prHeadSha": .head.sha,
|
|
||||||
"prHeadLabel": .head.label,
|
|
||||||
"prBody": .body,
|
|
||||||
"prLabels": (reduce .labels[].name as $l ([]; . + [$l]))
|
|
||||||
}
|
|
||||||
' <<< "$PR_JSON")"
|
|
||||||
} >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
|
|
||||||
- name: Find Blocked/Stacked PRs in body
|
|
||||||
id: pr_ids
|
|
||||||
run: |
|
|
||||||
prs=$(
|
|
||||||
jq -c '
|
|
||||||
.prBody as $body
|
|
||||||
| (
|
|
||||||
$body |
|
|
||||||
reduce (
|
|
||||||
. | scan("blocked (?:by|on):? #([0-9]+)")
|
|
||||||
| map({
|
|
||||||
"type": "Blocked on",
|
|
||||||
"number": ( . | tonumber )
|
|
||||||
})
|
|
||||||
) as $i ([]; . + [$i[]])
|
|
||||||
) as $bprs
|
|
||||||
| (
|
|
||||||
$body |
|
|
||||||
reduce (
|
|
||||||
. | scan("stacked on:? #([0-9]+)")
|
|
||||||
| map({
|
|
||||||
"type": "Stacked on",
|
|
||||||
"number": ( . | tonumber )
|
|
||||||
})
|
|
||||||
) as $i ([]; . + [$i[]])
|
|
||||||
) as $sprs
|
|
||||||
| ($bprs + $sprs) as $prs
|
|
||||||
| {
|
|
||||||
"blocking": $prs,
|
|
||||||
"numBlocking": ( $prs | length),
|
|
||||||
}
|
|
||||||
' <<< "$JOB_DATA"
|
|
||||||
)
|
|
||||||
echo "prs=$prs" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Collect Blocked PR Data
|
|
||||||
id: blocking_data
|
|
||||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
BLOCKING_PRS: ${{ steps.pr_ids.outputs.prs }}
|
|
||||||
run: |
|
|
||||||
blocked_pr_data=$(
|
|
||||||
while read -r pr_data ; do
|
|
||||||
gh api \
|
|
||||||
-H "Accept: application/vnd.github+json" \
|
|
||||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
||||||
"/repos/$OWNER/$REPO/pulls/$(jq -r '.number' <<< "$pr_data")" \
|
|
||||||
| jq -c --arg type "$(jq -r '.type' <<< "$pr_data")" \
|
|
||||||
'
|
|
||||||
. | {
|
|
||||||
"type": $type,
|
|
||||||
"number": .number,
|
|
||||||
"merged": .merged,
|
|
||||||
"labels": (reduce .labels[].name as $l ([]; . + [$l])),
|
|
||||||
"basePrUrl": .html_url,
|
|
||||||
"baseRepoName": .head.repo.name,
|
|
||||||
"baseRepoOwner": .head.repo.owner.login,
|
|
||||||
"baseRepoUrl": .head.repo.html_url,
|
|
||||||
"baseSha": .head.sha,
|
|
||||||
"baseRefName": .head.ref,
|
|
||||||
}
|
|
||||||
'
|
|
||||||
done < <(jq -c '.blocking[]' <<< "$BLOCKING_PRS") | jq -c -s
|
|
||||||
)
|
|
||||||
{
|
|
||||||
echo "data=$blocked_pr_data";
|
|
||||||
echo "all_merged=$(jq -r 'all(.[].merged; .)' <<< "$blocked_pr_data")";
|
|
||||||
echo "current_blocking=$(jq -c 'map( select( .merged | not ) | .number )' <<< "$blocked_pr_data" )";
|
|
||||||
} >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Add 'blocked' Label is Missing
|
|
||||||
id: label_blocked
|
|
||||||
if: (fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0) && !contains(fromJSON(env.JOB_DATA).prLabels, 'blocked') && !fromJSON(steps.blocking_data.outputs.all_merged)
|
|
||||||
continue-on-error: true
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
run: |
|
|
||||||
gh -R ${{ github.repository }} issue edit --add-label 'blocked' "$PR_NUMBER"
|
|
||||||
|
|
||||||
- name: Remove 'blocked' Label if All Dependencies Are Merged
|
|
||||||
id: unlabel_blocked
|
|
||||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0 && fromJSON(steps.blocking_data.outputs.all_merged)
|
|
||||||
continue-on-error: true
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
run: |
|
|
||||||
gh -R ${{ github.repository }} issue edit --remove-label 'blocked' "$PR_NUMBER"
|
|
||||||
|
|
||||||
- name: Apply 'blocking' Label to Unmerged Dependencies
|
|
||||||
id: label_blocking
|
|
||||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
|
|
||||||
continue-on-error: true
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
BLOCKING_ISSUES: ${{ steps.blocking_data.outputs.current_blocking }}
|
|
||||||
run: |
|
|
||||||
while read -r pr ; do
|
|
||||||
gh -R ${{ github.repository }} issue edit --add-label 'blocking' "$pr" || true
|
|
||||||
done < <(jq -c '.[]' <<< "$BLOCKING_ISSUES")
|
|
||||||
|
|
||||||
- name: Apply Blocking PR Status Check
|
|
||||||
id: blocked_check
|
|
||||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
|
|
||||||
continue-on-error: true
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
BLOCKING_DATA: ${{ steps.blocking_data.outputs.data }}
|
|
||||||
run: |
|
|
||||||
pr_head_sha=$(jq -r '.prHeadSha' <<< "$JOB_DATA")
|
|
||||||
# create commit Status, overwrites previous identical context
|
|
||||||
while read -r pr_data ; do
|
|
||||||
DESC=$(
|
|
||||||
jq -r ' "Blocking PR #" + (.number | tostring) + " is " + (if .merged then "" else "not yet " end) + "merged"' <<< "$pr_data"
|
|
||||||
)
|
|
||||||
gh api \
|
|
||||||
--method POST \
|
|
||||||
-H "Accept: application/vnd.github+json" \
|
|
||||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
||||||
"/repos/${OWNER}/${REPO}/statuses/${pr_head_sha}" \
|
|
||||||
-f "state=$(jq -r 'if .merged then "success" else "failure" end' <<< "$pr_data")" \
|
|
||||||
-f "target_url=$(jq -r '.basePrUrl' <<< "$pr_data" )" \
|
|
||||||
-f "description=$DESC" \
|
|
||||||
-f "context=ci/blocking-pr-check:$(jq '.number' <<< "$pr_data")"
|
|
||||||
done < <(jq -c '.[]' <<< "$BLOCKING_DATA")
|
|
||||||
|
|
||||||
- name: Context Comment
|
|
||||||
id: generate-comment
|
|
||||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
|
|
||||||
continue-on-error: true
|
|
||||||
env:
|
|
||||||
BLOCKING_DATA: ${{ steps.blocking_data.outputs.data }}
|
|
||||||
run: |
|
|
||||||
COMMENT_PATH="$(pwd)/temp_comment_file.txt"
|
|
||||||
echo '<h3>PR Dependencies :pushpin:</h3>' > "$COMMENT_PATH"
|
|
||||||
echo >> "$COMMENT_PATH"
|
|
||||||
pr_head_label=$(jq -r '.prHeadLabel' <<< "$JOB_DATA")
|
|
||||||
while read -r pr_data ; do
|
|
||||||
base_pr=$(jq -r '.number' <<< "$pr_data")
|
|
||||||
base_ref_name=$(jq -r '.baseRefName' <<< "$pr_data")
|
|
||||||
base_repo_owner=$(jq -r '.baseRepoOwner' <<< "$pr_data")
|
|
||||||
base_repo_name=$(jq -r '.baseRepoName' <<< "$pr_data")
|
|
||||||
compare_url="https://github.com/$base_repo_owner/$base_repo_name/compare/$base_ref_name...$pr_head_label"
|
|
||||||
status=$(jq -r 'if .merged then ":heavy_check_mark: Merged" else ":x: Not Merged" end' <<< "$pr_data")
|
|
||||||
type=$(jq -r '.type' <<< "$pr_data")
|
|
||||||
echo " - $type #$base_pr $status [(compare)]($compare_url)" >> "$COMMENT_PATH"
|
|
||||||
done < <(jq -c '.[]' <<< "$BLOCKING_DATA")
|
|
||||||
|
|
||||||
{
|
|
||||||
echo 'body<<EOF';
|
|
||||||
cat "${COMMENT_PATH}";
|
|
||||||
echo 'EOF';
|
|
||||||
} >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: 💬 PR Comment
|
|
||||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
|
|
||||||
continue-on-error: true
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
COMMENT_BODY: ${{ steps.generate-comment.outputs.body }}
|
|
||||||
run: |
|
|
||||||
gh -R ${{ github.repository }} issue comment "$PR_NUMBER" \
|
|
||||||
--body "$COMMENT_BODY" \
|
|
||||||
--create-if-none \
|
|
||||||
--edit-last
|
|
||||||
|
|
691
.github/workflows/build.yml
vendored
691
.github/workflows/build.yml
vendored
@ -1,195 +1,610 @@
|
|||||||
name: Build
|
name: Build
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
|
||||||
branches-ignore:
|
|
||||||
- "renovate/**"
|
|
||||||
paths:
|
|
||||||
# File types
|
|
||||||
- "**.cpp"
|
|
||||||
- "**.h"
|
|
||||||
- "**.java"
|
|
||||||
|
|
||||||
# Directories
|
|
||||||
- "buildconfig/"
|
|
||||||
- "cmake/"
|
|
||||||
- "launcher/"
|
|
||||||
- "libraries/"
|
|
||||||
- "program_info/"
|
|
||||||
- "tests/"
|
|
||||||
|
|
||||||
# Files
|
|
||||||
- "CMakeLists.txt"
|
|
||||||
- "COPYING.md"
|
|
||||||
|
|
||||||
# Workflows
|
|
||||||
- ".github/workflows/build.yml"
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
# File types
|
|
||||||
- "**.cpp"
|
|
||||||
- "**.h"
|
|
||||||
|
|
||||||
# Directories
|
|
||||||
- "buildconfig/"
|
|
||||||
- "cmake/"
|
|
||||||
- "launcher/"
|
|
||||||
- "libraries/"
|
|
||||||
- "program_info/"
|
|
||||||
- "tests/"
|
|
||||||
|
|
||||||
# Files
|
|
||||||
- "CMakeLists.txt"
|
|
||||||
- "COPYING.md"
|
|
||||||
|
|
||||||
# Workflows
|
|
||||||
- ".github/workflows/build.yml"
|
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
build-type:
|
build_type:
|
||||||
description: Type of build (Debug or Release)
|
description: Type of build (Debug, Release, RelWithDebInfo, MinSizeRel)
|
||||||
type: string
|
type: string
|
||||||
default: Debug
|
default: Debug
|
||||||
workflow_dispatch:
|
is_qt_cached:
|
||||||
inputs:
|
description: Enable Qt caching or not
|
||||||
build-type:
|
|
||||||
description: Type of build (Debug or Release)
|
|
||||||
type: string
|
type: string
|
||||||
default: Debug
|
default: true
|
||||||
|
secrets:
|
||||||
|
SPARKLE_ED25519_KEY:
|
||||||
|
description: Private key for signing Sparkle updates
|
||||||
|
required: false
|
||||||
|
WINDOWS_CODESIGN_CERT:
|
||||||
|
description: Certificate for signing Windows builds
|
||||||
|
required: false
|
||||||
|
WINDOWS_CODESIGN_PASSWORD:
|
||||||
|
description: Password for signing Windows builds
|
||||||
|
required: false
|
||||||
|
CACHIX_AUTH_TOKEN:
|
||||||
|
description: Private token for authenticating against Cachix cache
|
||||||
|
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
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build (${{ matrix.artifact-name }})
|
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-22.04
|
- os: ubuntu-20.04
|
||||||
artifact-name: Linux
|
qt_ver: 5
|
||||||
base-cmake-preset: linux
|
|
||||||
|
- os: ubuntu-20.04
|
||||||
|
qt_ver: 6
|
||||||
|
qt_host: linux
|
||||||
|
qt_arch: ""
|
||||||
|
qt_version: "6.2.4"
|
||||||
|
qt_modules: "qt5compat qtimageformats"
|
||||||
|
qt_tools: ""
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
artifact-name: Windows-MinGW-w64
|
name: "Windows-MinGW-w64"
|
||||||
base-cmake-preset: windows_mingw
|
msystem: clang64
|
||||||
msystem: CLANG64
|
vcvars_arch: "amd64_x86"
|
||||||
vcvars-arch: amd64_x86
|
|
||||||
|
|
||||||
- os: windows-11-arm
|
|
||||||
artifact-name: Windows-MinGW-arm64
|
|
||||||
base-cmake-preset: windows_mingw
|
|
||||||
msystem: CLANGARM64
|
|
||||||
vcvars-arch: arm64
|
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
artifact-name: Windows-MSVC
|
name: "Windows-MSVC"
|
||||||
base-cmake-preset: windows_msvc
|
msystem: ""
|
||||||
# TODO(@getchoo): This is the default in setup-dependencies/windows. Why isn't it working?!?!
|
architecture: "x64"
|
||||||
vcvars-arch: amd64
|
vcvars_arch: "amd64"
|
||||||
|
qt_ver: 6
|
||||||
|
qt_host: windows
|
||||||
|
qt_arch: ''
|
||||||
|
qt_version: '6.6.0'
|
||||||
|
qt_modules: 'qt5compat qtimageformats'
|
||||||
|
qt_tools: ''
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
artifact-name: Windows-MSVC-arm64
|
name: "Windows-MSVC-arm64"
|
||||||
base-cmake-preset: windows_msvc_arm64_cross
|
msystem: ""
|
||||||
vcvars-arch: amd64_arm64
|
architecture: "arm64"
|
||||||
qt-architecture: win64_msvc2022_arm64_cross_compiled
|
vcvars_arch: "amd64_arm64"
|
||||||
|
qt_ver: 6
|
||||||
|
qt_host: windows
|
||||||
|
qt_arch: 'win64_msvc2019_arm64'
|
||||||
|
qt_version: '6.6.0'
|
||||||
|
qt_modules: 'qt5compat qtimageformats'
|
||||||
|
qt_tools: ''
|
||||||
|
|
||||||
- os: macos-14
|
- os: macos-12
|
||||||
artifact-name: macOS
|
name: macOS
|
||||||
base-cmake-preset: ${{ (inputs.build-type || 'Debug') == 'Debug' && 'macos_universal' || 'macos' }}
|
macosx_deployment_target: 11.0
|
||||||
macosx-deployment-target: 11.0
|
qt_ver: 6
|
||||||
|
qt_host: mac
|
||||||
|
qt_arch: ''
|
||||||
|
qt_version: '6.6.0'
|
||||||
|
qt_modules: 'qt5compat qtimageformats'
|
||||||
|
qt_tools: ''
|
||||||
|
|
||||||
|
- os: macos-12
|
||||||
|
name: macOS-Legacy
|
||||||
|
macosx_deployment_target: 10.13
|
||||||
|
qt_ver: 5
|
||||||
|
qt_host: mac
|
||||||
|
qt_version: "5.15.2"
|
||||||
|
qt_modules: ""
|
||||||
|
qt_tools: ""
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: ${{ matrix.msystem != '' && 'msys2 {0}' || 'bash' }}
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx-deployment-target }}
|
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx_deployment_target }}
|
||||||
|
INSTALL_DIR: "install"
|
||||||
|
INSTALL_PORTABLE_DIR: "install-portable"
|
||||||
|
INSTALL_APPIMAGE_DIR: "install-appdir"
|
||||||
|
BUILD_DIR: "build"
|
||||||
|
CCACHE_VAR: ""
|
||||||
|
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
##
|
##
|
||||||
# SETUP
|
# PREPARE
|
||||||
##
|
##
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: "true"
|
||||||
|
|
||||||
- name: Setup dependencies
|
- name: "Setup MSYS2"
|
||||||
id: setup-dependencies
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
uses: ./.github/actions/setup-dependencies
|
uses: msys2/setup-msys2@v2
|
||||||
with:
|
with:
|
||||||
build-type: ${{ inputs.build-type || 'Debug' }}
|
|
||||||
msystem: ${{ matrix.msystem }}
|
msystem: ${{ matrix.msystem }}
|
||||||
vcvars-arch: ${{ matrix.vcvars-arch }}
|
update: true
|
||||||
qt-architecture: ${{ matrix.qt-architecture }}
|
install: >-
|
||||||
|
git
|
||||||
|
mingw-w64-x86_64-binutils
|
||||||
|
pacboy: >-
|
||||||
|
toolchain:p
|
||||||
|
cmake:p
|
||||||
|
extra-cmake-modules:p
|
||||||
|
ninja:p
|
||||||
|
qt6-base:p
|
||||||
|
qt6-svg:p
|
||||||
|
qt6-imageformats:p
|
||||||
|
quazip-qt6:p
|
||||||
|
ccache:p
|
||||||
|
qt6-5compat:p
|
||||||
|
cmark:p
|
||||||
|
|
||||||
|
- name: Force newer ccache
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem == '' && inputs.build_type == 'Debug'
|
||||||
|
run: |
|
||||||
|
choco install ccache --version 4.7.1
|
||||||
|
|
||||||
|
- name: Setup ccache
|
||||||
|
if: (runner.os != 'Windows' || matrix.msystem == '') && inputs.build_type == 'Debug'
|
||||||
|
uses: hendrikmuhs/ccache-action@v1.2.10
|
||||||
|
with:
|
||||||
|
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}-${{ matrix.architecture }}
|
||||||
|
|
||||||
|
- name: Retrieve ccache cache (Windows MinGW-w64)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug'
|
||||||
|
uses: actions/cache@v3.3.2
|
||||||
|
with:
|
||||||
|
path: '${{ github.workspace }}\.ccache'
|
||||||
|
key: ${{ matrix.os }}-mingw-w64-ccache-${{ github.run_id }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ matrix.os }}-mingw-w64-ccache
|
||||||
|
|
||||||
|
- name: Setup ccache (Windows MinGW-w64)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug'
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
ccache --set-config=cache_dir='${{ github.workspace }}\.ccache'
|
||||||
|
ccache --set-config=max_size='500M'
|
||||||
|
ccache --set-config=compression=true
|
||||||
|
ccache -p # Show config
|
||||||
|
ccache -z # Zero stats
|
||||||
|
|
||||||
|
- name: Use ccache on Debug builds only
|
||||||
|
if: inputs.build_type == 'Debug'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "CCACHE_VAR=ccache" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Set short version
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
ver_short=`git rev-parse --short HEAD`
|
||||||
|
echo "VERSION=$ver_short" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install Dependencies (Linux)
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
sudo apt-get -y update
|
||||||
|
sudo apt-get -y install ninja-build extra-cmake-modules scdoc appstream
|
||||||
|
|
||||||
|
- name: Install Dependencies (macOS)
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
run: |
|
||||||
|
brew update
|
||||||
|
brew install ninja extra-cmake-modules
|
||||||
|
|
||||||
|
- name: Install Qt (Linux)
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
||||||
|
run: |
|
||||||
|
sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5
|
||||||
|
|
||||||
|
- name: Install host Qt (Windows MSVC arm64)
|
||||||
|
if: runner.os == 'Windows' && matrix.architecture == 'arm64'
|
||||||
|
uses: jurplel/install-qt-action@v3
|
||||||
|
with:
|
||||||
|
aqtversion: "==3.1.*"
|
||||||
|
py7zrversion: ">=0.20.2"
|
||||||
|
version: ${{ matrix.qt_version }}
|
||||||
|
host: "windows"
|
||||||
|
target: "desktop"
|
||||||
|
arch: ""
|
||||||
|
modules: ${{ matrix.qt_modules }}
|
||||||
|
tools: ${{ matrix.qt_tools }}
|
||||||
|
cache: ${{ inputs.is_qt_cached }}
|
||||||
|
cache-key-prefix: host-qt-arm64-windows
|
||||||
|
dir: ${{ github.workspace }}\HostQt
|
||||||
|
set-env: false
|
||||||
|
|
||||||
|
- 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 == '')
|
||||||
|
uses: jurplel/install-qt-action@v3
|
||||||
|
with:
|
||||||
|
aqtversion: "==3.1.*"
|
||||||
|
py7zrversion: ">=0.20.2"
|
||||||
|
version: ${{ matrix.qt_version }}
|
||||||
|
host: ${{ matrix.qt_host }}
|
||||||
|
target: "desktop"
|
||||||
|
arch: ${{ matrix.qt_arch }}
|
||||||
|
modules: ${{ matrix.qt_modules }}
|
||||||
|
tools: ${{ matrix.qt_tools }}
|
||||||
|
cache: ${{ inputs.is_qt_cached }}
|
||||||
|
|
||||||
|
- name: Install MSVC (Windows MSVC)
|
||||||
|
if: runner.os == 'Windows' # We want this for MinGW builds as well, as we need SignTool
|
||||||
|
uses: ilammy/msvc-dev-cmd@v1
|
||||||
|
with:
|
||||||
|
vsversion: 2022
|
||||||
|
arch: ${{ matrix.vcvars_arch }}
|
||||||
|
|
||||||
|
- name: Prepare AppImage (Linux)
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
|
run: |
|
||||||
|
wget "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-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/AppImageCommunity/AppImageUpdate/releases/download/continuous/AppImageUpdate-x86_64.AppImage"
|
||||||
|
|
||||||
|
${{ github.workspace }}/.github/scripts/prepare_JREs.sh
|
||||||
|
sudo apt install libopengl0
|
||||||
|
|
||||||
|
- name: Add QT_HOST_PATH var (Windows MSVC arm64)
|
||||||
|
if: runner.os == 'Windows' && matrix.architecture == 'arm64'
|
||||||
|
run: |
|
||||||
|
echo "QT_HOST_PATH=${{ github.workspace }}\HostQt\Qt\${{ matrix.qt_version }}\msvc2019_64" >> $env:GITHUB_ENV
|
||||||
|
|
||||||
|
##
|
||||||
|
# CONFIGURE
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: Configure CMake (macOS)
|
||||||
|
if: runner.os == 'macOS' && matrix.qt_ver == 6
|
||||||
|
run: |
|
||||||
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -G Ninja
|
||||||
|
|
||||||
|
- name: Configure CMake (macOS-Legacy)
|
||||||
|
if: runner.os == 'macOS' && matrix.qt_ver == 5
|
||||||
|
run: |
|
||||||
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DMACOSX_SPARKLE_UPDATE_PUBLIC_KEY="" -DMACOSX_SPARKLE_UPDATE_FEED_URL="" -G Ninja
|
||||||
|
|
||||||
|
- name: Configure CMake (Windows MinGW-w64)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=6 -DCMAKE_OBJDUMP=/mingw64/bin/objdump.exe -DLauncher_BUILD_ARTIFACT=${{ matrix.name }}-Qt${{ matrix.qt_ver }} -G Ninja
|
||||||
|
|
||||||
|
- name: Configure CMake (Windows MSVC)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem == ''
|
||||||
|
run: |
|
||||||
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreadedDLL" -A${{ matrix.architecture}} -DLauncher_FORCE_BUNDLED_LIBS=ON -DLauncher_BUILD_ARTIFACT=${{ matrix.name }}-Qt${{ matrix.qt_ver }}
|
||||||
|
# https://github.com/ccache/ccache/wiki/MS-Visual-Studio (I coudn't figure out the compiler prefix)
|
||||||
|
if ("${{ env.CCACHE_VAR }}")
|
||||||
|
{
|
||||||
|
Copy-Item C:/ProgramData/chocolatey/lib/ccache/tools/ccache-4.7.1-windows-x86_64/ccache.exe -Destination C:/ProgramData/chocolatey/lib/ccache/tools/ccache-4.7.1-windows-x86_64/cl.exe
|
||||||
|
echo "CLToolExe=cl.exe" >> $env:GITHUB_ENV
|
||||||
|
echo "CLToolPath=C:/ProgramData/chocolatey/lib/ccache/tools/ccache-4.7.1-windows-x86_64/" >> $env:GITHUB_ENV
|
||||||
|
echo "TrackFileAccess=false" >> $env:GITHUB_ENV
|
||||||
|
}
|
||||||
|
# Needed for ccache, but also speeds up compile
|
||||||
|
echo "UseMultiToolTask=true" >> $env:GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Configure CMake (Linux)
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DLauncher_BUILD_ARTIFACT=Linux-Qt${{ matrix.qt_ver }} -G Ninja
|
||||||
|
|
||||||
##
|
##
|
||||||
# BUILD
|
# BUILD
|
||||||
##
|
##
|
||||||
|
|
||||||
- name: Get CMake preset
|
- name: Build
|
||||||
id: cmake-preset
|
if: runner.os != 'Windows'
|
||||||
env:
|
|
||||||
BASE_CMAKE_PRESET: ${{ matrix.base-cmake-preset }}
|
|
||||||
PRESET_TYPE: ${{ (inputs.build-type || 'Debug') == 'Debug' && 'debug' || 'ci' }}
|
|
||||||
run: |
|
run: |
|
||||||
echo preset="$BASE_CMAKE_PRESET"_"$PRESET_TYPE" >> "$GITHUB_OUTPUT"
|
cmake --build ${{ env.BUILD_DIR }}
|
||||||
|
|
||||||
- name: Run CMake workflow
|
- name: Build (Windows MinGW-w64)
|
||||||
env:
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
CMAKE_PRESET: ${{ steps.cmake-preset.outputs.preset }}
|
shell: msys2 {0}
|
||||||
run: |
|
run: |
|
||||||
cmake --workflow --preset "$CMAKE_PRESET"
|
cmake --build ${{ env.BUILD_DIR }}
|
||||||
|
|
||||||
|
- name: Build (Windows MSVC)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem == ''
|
||||||
|
run: |
|
||||||
|
cmake --build ${{ env.BUILD_DIR }} --config ${{ inputs.build_type }}
|
||||||
|
|
||||||
##
|
##
|
||||||
# PACKAGE
|
# TEST
|
||||||
##
|
##
|
||||||
|
|
||||||
- name: Get short version
|
- name: Test
|
||||||
id: short-version
|
if: runner.os != 'Windows'
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
echo "version=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
|
ctest -E "^example64|example$" --test-dir build --output-on-failure
|
||||||
|
|
||||||
- name: Package (Linux)
|
- name: Test (Windows MinGW-w64)
|
||||||
if: ${{ runner.os == 'Linux' }}
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
uses: ./.github/actions/package/linux
|
shell: msys2 {0}
|
||||||
with:
|
run: |
|
||||||
version: ${{ steps.short-version.outputs.version }}
|
ctest -E "^example64|example$" --test-dir build --output-on-failure
|
||||||
build-type: ${{ steps.setup-dependencies.outputs.build-type }}
|
|
||||||
cmake-preset: ${{ steps.cmake-preset.outputs.preset }}
|
|
||||||
qt-version: ${{ steps.setup-dependencies.outputs.qt-version }}
|
|
||||||
|
|
||||||
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
|
- name: Test (Windows MSVC)
|
||||||
gpg-private-key-id: ${{ secrets.GPG_PRIVATE_KEY_ID }}
|
if: runner.os == 'Windows' && matrix.msystem == '' && matrix.architecture != 'arm64'
|
||||||
|
run: |
|
||||||
|
ctest -E "^example64|example$" --test-dir build --output-on-failure -C ${{ inputs.build_type }}
|
||||||
|
|
||||||
|
##
|
||||||
|
# PACKAGE BUILDS
|
||||||
|
##
|
||||||
|
|
||||||
- name: Package (macOS)
|
- name: Package (macOS)
|
||||||
if: ${{ runner.os == 'macOS' }}
|
if: runner.os == 'macOS'
|
||||||
uses: ./.github/actions/package/macos
|
run: |
|
||||||
|
cmake --install ${{ env.BUILD_DIR }}
|
||||||
|
|
||||||
|
cd ${{ env.INSTALL_DIR }}
|
||||||
|
chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
||||||
|
sudo codesign --sign - --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
||||||
|
mv "PrismLauncher.app" "Prism Launcher.app"
|
||||||
|
tar -czf ../PrismLauncher.tar.gz *
|
||||||
|
|
||||||
|
- name: Make Sparkle signature (macOS)
|
||||||
|
if: matrix.name == 'macOS'
|
||||||
|
run: |
|
||||||
|
if [ '${{ secrets.SPARKLE_ED25519_KEY }}' != '' ]; then
|
||||||
|
brew install openssl@3
|
||||||
|
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)
|
||||||
|
rm ed25519-priv.pem
|
||||||
|
cat >> $GITHUB_STEP_SUMMARY << EOF
|
||||||
|
### Artifact Information :information_source:
|
||||||
|
- :memo: Sparkle Signature (ed25519): \`$signature\`
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
cat >> $GITHUB_STEP_SUMMARY << EOF
|
||||||
|
### Artifact Information :information_source:
|
||||||
|
- :warning: Sparkle Signature (ed25519): No private key available (likely a pull request or fork)
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Package (Windows MinGW-w64)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
cmake --install ${{ env.BUILD_DIR }}
|
||||||
|
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
|
||||||
|
|
||||||
|
- name: Package (Windows MSVC)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem == ''
|
||||||
|
run: |
|
||||||
|
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build_type }}
|
||||||
|
|
||||||
|
cd ${{ env.INSTALL_DIR }}
|
||||||
|
if ("${{ matrix.qt_ver }}" -eq "5")
|
||||||
|
{
|
||||||
|
Copy-Item ${{ runner.workspace }}/Qt/Tools/OpenSSL/Win_x86/bin/libcrypto-1_1.dll -Destination libcrypto-1_1.dll
|
||||||
|
Copy-Item ${{ runner.workspace }}/Qt/Tools/OpenSSL/Win_x86/bin/libssl-1_1.dll -Destination libssl-1_1.dll
|
||||||
|
}
|
||||||
|
cd ${{ github.workspace }}
|
||||||
|
|
||||||
|
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)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
shell: bash # yes, we are not using MSYS2 or PowerShell here
|
||||||
|
run: |
|
||||||
|
echo '${{ secrets.WINDOWS_CODESIGN_CERT }}' | base64 --decode > codesign.pfx
|
||||||
|
|
||||||
|
- name: Sign executable (Windows)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
run: |
|
||||||
|
if (Get-Content ./codesign.pfx){
|
||||||
|
cd ${{ env.INSTALL_DIR }}
|
||||||
|
# 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_updater.exe prismlauncher_filelink.exe
|
||||||
|
} else {
|
||||||
|
":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Package (Windows MinGW-w64, portable)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
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
|
||||||
|
for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f); do l=$(cygpath -u $l); l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done >> ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt
|
||||||
|
|
||||||
|
- name: Package (Windows MSVC, portable)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem == ''
|
||||||
|
run: |
|
||||||
|
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
|
||||||
|
|
||||||
|
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)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
run: |
|
||||||
|
cd ${{ env.INSTALL_DIR }}
|
||||||
|
makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi"
|
||||||
|
|
||||||
|
- name: Sign installer (Windows)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
run: |
|
||||||
|
if (Get-Content ./codesign.pfx){
|
||||||
|
SignTool sign /fd sha256 /td sha256 /f codesign.pfx /p '${{ secrets.WINDOWS_CODESIGN_PASSWORD }}' /tr http://timestamp.digicert.com PrismLauncher-Setup.exe
|
||||||
|
} else {
|
||||||
|
":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Package (Linux)
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_DIR }}
|
||||||
|
for l in $(find ${{ env.INSTALL_DIR }} -type f); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_DIR }}/manifest.txt
|
||||||
|
|
||||||
|
cd ${{ env.INSTALL_DIR }}
|
||||||
|
tar --owner root --group root -czf ../PrismLauncher.tar.gz *
|
||||||
|
|
||||||
|
- name: Package (Linux, portable)
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }}
|
||||||
|
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
||||||
|
for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt
|
||||||
|
|
||||||
|
|
||||||
|
cd ${{ env.INSTALL_PORTABLE_DIR }}
|
||||||
|
tar -czf ../PrismLauncher-portable.tar.gz *
|
||||||
|
|
||||||
|
- name: Package AppImage (Linux)
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
|
run: |
|
||||||
|
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
|
||||||
|
export "NO_APPSTREAM=1" # we have to skip appstream checking because appstream on ubuntu 20.04 is outdated
|
||||||
|
|
||||||
|
export OUTPUT="PrismLauncher-Linux-x86_64.AppImage"
|
||||||
|
|
||||||
|
chmod +x linuxdeploy-*.AppImage
|
||||||
|
|
||||||
|
mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-{8,17}-openjdk
|
||||||
|
mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines
|
||||||
|
|
||||||
|
cp -r ${{ github.workspace }}/JREs/jre8/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-8-openjdk
|
||||||
|
|
||||||
|
cp -r ${{ github.workspace }}/JREs/jre17/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk
|
||||||
|
|
||||||
|
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/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/
|
||||||
|
|
||||||
|
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib"
|
||||||
|
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-8-openjdk/lib/amd64/server"
|
||||||
|
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-8-openjdk/lib/amd64"
|
||||||
|
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk/lib/server"
|
||||||
|
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk/lib"
|
||||||
|
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
|
||||||
|
|
||||||
|
mv "PrismLauncher-Linux-x86_64.AppImage" "PrismLauncher-Linux-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage"
|
||||||
|
|
||||||
|
##
|
||||||
|
# UPLOAD BUILDS
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: Upload binary tarball (macOS)
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
version: ${{ steps.short-version.outputs.version }}
|
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
build-type: ${{ steps.setup-dependencies.outputs.build-type }}
|
path: PrismLauncher.tar.gz
|
||||||
artifact-name: ${{ matrix.artifact-name }}
|
|
||||||
|
|
||||||
apple-codesign-cert: ${{ secrets.APPLE-CODESIGN-CERT }}
|
- name: Upload binary zip (Windows)
|
||||||
apple-codesign-password: ${{ secrets.APPLE-CODESIGN_PASSWORD }}
|
if: runner.os == 'Windows'
|
||||||
apple-codesign-id: ${{ secrets.APPLE-CODESIGN_ID }}
|
uses: actions/upload-artifact@v3
|
||||||
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 }}
|
|
||||||
sparkle-ed25519-key: ${{ secrets.SPARKLE-ED25519_KEY }}
|
|
||||||
|
|
||||||
- name: Package (Windows)
|
|
||||||
if: ${{ runner.os == 'Windows' }}
|
|
||||||
uses: ./.github/actions/package/windows
|
|
||||||
with:
|
with:
|
||||||
version: ${{ steps.short-version.outputs.version }}
|
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
build-type: ${{ steps.setup-dependencies.outputs.build-type }}
|
path: ${{ env.INSTALL_DIR }}/**
|
||||||
artifact-name: ${{ matrix.artifact-name }}
|
|
||||||
msystem: ${{ matrix.msystem }}
|
|
||||||
|
|
||||||
windows-codesign-cert: ${{ secrets.WINDOWS_CODESIGN_CERT }}
|
- name: Upload binary zip (Windows, portable)
|
||||||
windows-codesign-password: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
|
if: runner.os == 'Windows'
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: PrismLauncher-${{ matrix.name }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
|
path: ${{ env.INSTALL_PORTABLE_DIR }}/**
|
||||||
|
|
||||||
|
- name: Upload installer (Windows)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: PrismLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
|
path: PrismLauncher-Setup.exe
|
||||||
|
|
||||||
|
- name: Upload binary tarball (Linux, Qt 5)
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: PrismLauncher-${{ runner.os }}-Qt5-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
|
path: PrismLauncher.tar.gz
|
||||||
|
|
||||||
|
- name: Upload binary tarball (Linux, portable, Qt 5)
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: PrismLauncher-${{ runner.os }}-Qt5-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
|
path: PrismLauncher-portable.tar.gz
|
||||||
|
|
||||||
|
- name: Upload binary tarball (Linux, Qt 6)
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver !=5
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: PrismLauncher-${{ runner.os }}-Qt6-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
|
path: PrismLauncher.tar.gz
|
||||||
|
|
||||||
|
- name: Upload binary tarball (Linux, portable, Qt 6)
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: PrismLauncher-${{ runner.os }}-Qt6-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
|
path: PrismLauncher-portable.tar.gz
|
||||||
|
|
||||||
|
- name: Upload AppImage (Linux)
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: 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@v3
|
||||||
|
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)
|
||||||
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
ccache -s
|
||||||
|
|
||||||
|
flatpak:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: bilelmoussaoui/flatpak-github-actions:kde-5.15-22.08
|
||||||
|
options: --privileged
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
if: inputs.build_type == 'Debug'
|
||||||
|
with:
|
||||||
|
submodules: "true"
|
||||||
|
- name: Build Flatpak (Linux)
|
||||||
|
if: inputs.build_type == 'Debug'
|
||||||
|
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
||||||
|
with:
|
||||||
|
bundle: "Prism Launcher.flatpak"
|
||||||
|
manifest-path: flatpak/org.prismlauncher.PrismLauncher.yml
|
||||||
|
68
.github/workflows/codeql.yml
vendored
68
.github/workflows/codeql.yml
vendored
@ -1,77 +1,35 @@
|
|||||||
name: "CodeQL Code Scanning"
|
name: "CodeQL Code Scanning"
|
||||||
|
|
||||||
on:
|
on: [ push, pull_request, workflow_dispatch ]
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
# File types
|
|
||||||
- "**.cpp"
|
|
||||||
- "**.h"
|
|
||||||
- "**.java"
|
|
||||||
|
|
||||||
# Directories
|
|
||||||
- "buildconfig/"
|
|
||||||
- "cmake/"
|
|
||||||
- "launcher/"
|
|
||||||
- "libraries/"
|
|
||||||
- "program_info/"
|
|
||||||
- "tests/"
|
|
||||||
|
|
||||||
# Files
|
|
||||||
- "CMakeLists.txt"
|
|
||||||
- "COPYING.md"
|
|
||||||
|
|
||||||
# Workflows
|
|
||||||
- ".github/codeql"
|
|
||||||
- ".github/workflows/codeql.yml"
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
# File types
|
|
||||||
- "**.cpp"
|
|
||||||
- "**.h"
|
|
||||||
|
|
||||||
# Directories
|
|
||||||
- "buildconfig/"
|
|
||||||
- "cmake/"
|
|
||||||
- "launcher/"
|
|
||||||
- "libraries/"
|
|
||||||
- "program_info/"
|
|
||||||
- "tests/"
|
|
||||||
|
|
||||||
# Files
|
|
||||||
- "CMakeLists.txt"
|
|
||||||
- "COPYING.md"
|
|
||||||
|
|
||||||
# Workflows
|
|
||||||
- ".github/codeql"
|
|
||||||
- ".github/workflows/codeql.yml"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
CodeQL:
|
CodeQL:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: "true"
|
submodules: 'true'
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v3
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
config-file: ./.github/codeql/codeql-config.yml
|
config-file: ./.github/codeql/codeql-config.yml
|
||||||
queries: security-and-quality
|
queries: security-and-quality
|
||||||
languages: cpp, java
|
languages: cpp, java
|
||||||
|
|
||||||
- name: Setup dependencies
|
- name: Install Dependencies
|
||||||
uses: ./.github/actions/setup-dependencies
|
run:
|
||||||
with:
|
sudo apt-get -y update
|
||||||
build-type: Debug
|
|
||||||
|
sudo apt-get -y install ninja-build extra-cmake-modules scdoc qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5
|
||||||
|
|
||||||
- name: Configure and Build
|
- name: Configure and Build
|
||||||
run: |
|
run: |
|
||||||
cmake --preset linux_debug
|
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr -DLauncher_QT_VERSION_MAJOR=5 -G Ninja
|
||||||
cmake --build --preset linux_debug
|
|
||||||
|
cmake --build build
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v3
|
uses: github/codeql-action/analyze@v2
|
||||||
|
95
.github/workflows/flatpak.yml
vendored
95
.github/workflows/flatpak.yml
vendored
@ -1,95 +0,0 @@
|
|||||||
name: Flatpak
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
# We don't do anything with these artifacts on releases. They go to Flathub
|
|
||||||
tags-ignore:
|
|
||||||
- "*"
|
|
||||||
paths:
|
|
||||||
# File types
|
|
||||||
- "**.cpp"
|
|
||||||
- "**.h"
|
|
||||||
- "**.java"
|
|
||||||
|
|
||||||
# Build files
|
|
||||||
- "flatpak/"
|
|
||||||
|
|
||||||
# Directories
|
|
||||||
- "buildconfig/"
|
|
||||||
- "cmake/"
|
|
||||||
- "launcher/"
|
|
||||||
- "libraries/"
|
|
||||||
- "program_info/"
|
|
||||||
- "tests/"
|
|
||||||
|
|
||||||
# Files
|
|
||||||
- "CMakeLists.txt"
|
|
||||||
- "COPYING.md"
|
|
||||||
|
|
||||||
# Workflows
|
|
||||||
- ".github/workflows/flatpak.yml"
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
# File types
|
|
||||||
- "**.cpp"
|
|
||||||
- "**.h"
|
|
||||||
|
|
||||||
# Build files
|
|
||||||
- "flatpak/"
|
|
||||||
|
|
||||||
# Directories
|
|
||||||
- "buildconfig/"
|
|
||||||
- "cmake/"
|
|
||||||
- "launcher/"
|
|
||||||
- "libraries/"
|
|
||||||
- "program_info/"
|
|
||||||
- "tests/"
|
|
||||||
|
|
||||||
# Files
|
|
||||||
- "CMakeLists.txt"
|
|
||||||
- "COPYING.md"
|
|
||||||
|
|
||||||
# Workflows
|
|
||||||
- ".github/workflows/flatpak.yml"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build (${{ matrix.arch }})
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: ubuntu-22.04
|
|
||||||
arch: x86_64
|
|
||||||
|
|
||||||
- os: ubuntu-22.04-arm
|
|
||||||
arch: aarch64
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
|
|
||||||
container:
|
|
||||||
image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.8
|
|
||||||
options: --privileged
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
|
|
||||||
- name: Set short version
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "VERSION=${GITHUB_SHA::7}" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Build Flatpak
|
|
||||||
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
|
||||||
with:
|
|
||||||
bundle: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-Flatpak.flatpak
|
|
||||||
manifest-path: flatpak/org.prismlauncher.PrismLauncher.yml
|
|
||||||
arch: ${{ matrix.arch }}
|
|
62
.github/workflows/merge-blocking-pr.yml
vendored
62
.github/workflows/merge-blocking-pr.yml
vendored
@ -1,62 +0,0 @@
|
|||||||
name: Merged Blocking Pull Request Automation
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
types:
|
|
||||||
- closed
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
pr_id:
|
|
||||||
description: Local Pull Request number to work on
|
|
||||||
required: true
|
|
||||||
type: number
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
update-blocked-status:
|
|
||||||
name: Update Blocked Status
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
# a pr that was a `blocking:<id>` label was merged.
|
|
||||||
# find the open pr's it was blocked by and trigger a refresh of their state
|
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'blocking') }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Generate token
|
|
||||||
id: generate-token
|
|
||||||
uses: actions/create-github-app-token@v2
|
|
||||||
with:
|
|
||||||
app-id: ${{ vars.PULL_REQUEST_APP_ID }}
|
|
||||||
private-key: ${{ secrets.PULL_REQUEST_APP_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Gather Dependent PRs
|
|
||||||
id: gather_deps
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
PR_NUMBER: ${{ inputs.pr_id || github.event.pull_request.number }}
|
|
||||||
run: |
|
|
||||||
blocked_prs=$(
|
|
||||||
gh -R ${{ github.repository }} pr list --label 'blocked' --json 'number,body' \
|
|
||||||
| jq -c --argjson pr "$PR_NUMBER" '
|
|
||||||
reduce ( .[] | select(
|
|
||||||
.body |
|
|
||||||
scan("(?:blocked (?:by|on)|stacked on):? #([0-9]+)") |
|
|
||||||
map(tonumber) |
|
|
||||||
any(.[]; . == $pr)
|
|
||||||
)) as $i ([]; . + [$i])
|
|
||||||
'
|
|
||||||
)
|
|
||||||
{
|
|
||||||
echo "deps=$blocked_prs"
|
|
||||||
echo "numdeps=$(jq -r '. | length' <<< "$blocked_prs")"
|
|
||||||
} >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Trigger Blocked PR Workflows for Dependants
|
|
||||||
if: fromJSON(steps.gather_deps.outputs.numdeps) > 0
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
DEPS: ${{ steps.gather_deps.outputs.deps }}
|
|
||||||
run: |
|
|
||||||
while read -r pr ; do
|
|
||||||
gh -R ${{ github.repository }} workflow run 'blocked-prs.yml' -r "${{ github.ref_name }}" -f pr_id="$pr"
|
|
||||||
done < <(jq -c '.[].number' <<< "$DEPS")
|
|
||||||
|
|
143
.github/workflows/nix.yml
vendored
143
.github/workflows/nix.yml
vendored
@ -1,143 +0,0 @@
|
|||||||
name: Nix
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "*"
|
|
||||||
paths:
|
|
||||||
# File types
|
|
||||||
- "**.cpp"
|
|
||||||
- "**.h"
|
|
||||||
- "**.java"
|
|
||||||
|
|
||||||
# Build files
|
|
||||||
- "**.nix"
|
|
||||||
- "nix/"
|
|
||||||
- "flake.lock"
|
|
||||||
|
|
||||||
# Directories
|
|
||||||
- "buildconfig/"
|
|
||||||
- "cmake/"
|
|
||||||
- "launcher/"
|
|
||||||
- "libraries/"
|
|
||||||
- "program_info/"
|
|
||||||
- "tests/"
|
|
||||||
|
|
||||||
# Files
|
|
||||||
- "CMakeLists.txt"
|
|
||||||
- "COPYING.md"
|
|
||||||
|
|
||||||
# Workflows
|
|
||||||
- ".github/workflows/nix.yml"
|
|
||||||
pull_request_target:
|
|
||||||
paths:
|
|
||||||
# File types
|
|
||||||
- "**.cpp"
|
|
||||||
- "**.h"
|
|
||||||
|
|
||||||
# Build files
|
|
||||||
- "**.nix"
|
|
||||||
- "nix/"
|
|
||||||
- "flake.lock"
|
|
||||||
|
|
||||||
# Directories
|
|
||||||
- "buildconfig/"
|
|
||||||
- "cmake/"
|
|
||||||
- "launcher/"
|
|
||||||
- "libraries/"
|
|
||||||
- "program_info/"
|
|
||||||
- "tests/"
|
|
||||||
|
|
||||||
# Files
|
|
||||||
- "CMakeLists.txt"
|
|
||||||
- "COPYING.md"
|
|
||||||
|
|
||||||
# Workflows
|
|
||||||
- ".github/workflows/nix.yml"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
env:
|
|
||||||
DEBUG: ${{ github.ref_type != 'tag' }}
|
|
||||||
USE_DETERMINATE: ${{ github.event_name == 'pull_request' }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build (${{ matrix.system }})
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: ubuntu-22.04
|
|
||||||
system: x86_64-linux
|
|
||||||
|
|
||||||
- os: ubuntu-22.04-arm
|
|
||||||
system: aarch64-linux
|
|
||||||
|
|
||||||
- os: macos-13
|
|
||||||
system: x86_64-darwin
|
|
||||||
|
|
||||||
- os: macos-14
|
|
||||||
system: aarch64-darwin
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
id-token: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Get merge commit
|
|
||||||
if: ${{ github.event_name == 'pull_request_target' }}
|
|
||||||
id: merge-commit
|
|
||||||
uses: PrismLauncher/PrismLauncher/.github/actions/get-merge-commit@develop
|
|
||||||
with:
|
|
||||||
pull-request-id: ${{ github.event.number }}
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: ${{ steps.merge-commit.outputs.merge-commit-sha || github.sha }}
|
|
||||||
|
|
||||||
- name: Install Nix
|
|
||||||
uses: DeterminateSystems/nix-installer-action@v17
|
|
||||||
with:
|
|
||||||
determinate: ${{ env.USE_DETERMINATE }}
|
|
||||||
|
|
||||||
# For PRs
|
|
||||||
- name: Setup Nix Magic Cache
|
|
||||||
if: ${{ env.USE_DETERMINATE == 'true' }}
|
|
||||||
uses: DeterminateSystems/flakehub-cache-action@v1
|
|
||||||
|
|
||||||
# For in-tree builds
|
|
||||||
- name: Setup Cachix
|
|
||||||
if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
|
|
||||||
uses: cachix/cachix-action@v16
|
|
||||||
with:
|
|
||||||
name: prismlauncher
|
|
||||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
|
||||||
|
|
||||||
- name: Run Flake checks
|
|
||||||
run: |
|
|
||||||
nix flake check --print-build-logs --show-trace
|
|
||||||
|
|
||||||
- name: Build debug package
|
|
||||||
if: ${{ env.DEBUG == 'true' }}
|
|
||||||
run: |
|
|
||||||
nix build \
|
|
||||||
--no-link --print-build-logs --print-out-paths \
|
|
||||||
.#prismlauncher-debug >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
|
|
||||||
- name: Build release package
|
|
||||||
if: ${{ env.DEBUG == 'false' }}
|
|
||||||
env:
|
|
||||||
TAG: ${{ github.ref_name }}
|
|
||||||
SYSTEM: ${{ matrix.system }}
|
|
||||||
run: |
|
|
||||||
nix build --no-link --print-out-paths .#prismlauncher \
|
|
||||||
| tee -a "$GITHUB_STEP_SUMMARY" \
|
|
||||||
| xargs cachix pin prismlauncher "$TAG"-"$SYSTEM"
|
|
29
.github/workflows/stale.yml
vendored
29
.github/workflows/stale.yml
vendored
@ -1,29 +0,0 @@
|
|||||||
name: Stale
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
# run weekly on sunday
|
|
||||||
- cron: "0 0 * * 0"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
label:
|
|
||||||
name: Label issues and PRs
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/stale@v9
|
|
||||||
with:
|
|
||||||
days-before-stale: 60
|
|
||||||
days-before-close: -1 # Don't close anything
|
|
||||||
exempt-issue-labels: rfc,nostale,help wanted
|
|
||||||
exempt-all-milestones: true
|
|
||||||
exempt-all-assignees: true
|
|
||||||
operations-per-run: 1000
|
|
||||||
stale-issue-label: inactive
|
|
||||||
stale-pr-label: inactive
|
|
37
.github/workflows/trigger_builds.yml
vendored
Normal file
37
.github/workflows/trigger_builds.yml
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
name: Build Application
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches-ignore:
|
||||||
|
- "renovate/**"
|
||||||
|
paths-ignore:
|
||||||
|
- "**.md"
|
||||||
|
- "**/LICENSE"
|
||||||
|
- "flake.lock"
|
||||||
|
- "packages/**"
|
||||||
|
- ".github/ISSUE_TEMPLATE/**"
|
||||||
|
- ".markdownlint**"
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- "**.md"
|
||||||
|
- "**/LICENSE"
|
||||||
|
- "flake.lock"
|
||||||
|
- "packages/**"
|
||||||
|
- ".github/ISSUE_TEMPLATE/**"
|
||||||
|
- ".markdownlint**"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_debug:
|
||||||
|
name: Build Debug
|
||||||
|
uses: ./.github/workflows/build.yml
|
||||||
|
with:
|
||||||
|
build_type: Debug
|
||||||
|
is_qt_cached: true
|
||||||
|
secrets:
|
||||||
|
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
||||||
|
WINDOWS_CODESIGN_CERT: ${{ secrets.WINDOWS_CODESIGN_CERT }}
|
||||||
|
WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
|
||||||
|
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||||
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
|
GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }}
|
@ -10,8 +10,15 @@ jobs:
|
|||||||
name: Build Release
|
name: Build Release
|
||||||
uses: ./.github/workflows/build.yml
|
uses: ./.github/workflows/build.yml
|
||||||
with:
|
with:
|
||||||
build-type: Release
|
build_type: Release
|
||||||
secrets: inherit
|
is_qt_cached: false
|
||||||
|
secrets:
|
||||||
|
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
||||||
|
WINDOWS_CODESIGN_CERT: ${{ secrets.WINDOWS_CODESIGN_CERT }}
|
||||||
|
WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
|
||||||
|
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||||
|
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
|
||||||
@ -25,7 +32,7 @@ jobs:
|
|||||||
submodules: "true"
|
submodules: "true"
|
||||||
path: "PrismLauncher-source"
|
path: "PrismLauncher-source"
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v3
|
||||||
- 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 "[^/]+$")
|
||||||
@ -34,9 +41,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-Qt5-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz
|
||||||
|
mv PrismLauncher-Linux-Qt5*/PrismLauncher.tar.gz PrismLauncher-Linux-Qt5-${{ env.VERSION }}.tar.gz
|
||||||
mv PrismLauncher-*.AppImage/PrismLauncher-*.AppImage PrismLauncher-Linux-x86_64.AppImage
|
mv PrismLauncher-*.AppImage/PrismLauncher-*.AppImage PrismLauncher-Linux-x86_64.AppImage
|
||||||
mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*.AppImage.zsync PrismLauncher-Linux-x86_64.AppImage.zsync
|
mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*.AppImage.zsync PrismLauncher-Linux-x86_64.AppImage.zsync
|
||||||
mv PrismLauncher-macOS*/PrismLauncher.zip PrismLauncher-macOS-${{ env.VERSION }}.zip
|
mv PrismLauncher-macOS-Legacy*/PrismLauncher.tar.gz PrismLauncher-macOS-Legacy-${{ env.VERSION }}.tar.gz
|
||||||
|
mv PrismLauncher-macOS*/PrismLauncher.tar.gz PrismLauncher-macOS-${{ env.VERSION }}.tar.gz
|
||||||
|
|
||||||
tar --exclude='.git' -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
|
tar --exclude='.git' -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
|
||||||
|
|
||||||
@ -68,7 +79,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Create release
|
- name: Create release
|
||||||
id: create_release
|
id: create_release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v1
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
tag_name: ${{ github.ref }}
|
tag_name: ${{ github.ref }}
|
||||||
@ -76,20 +87,21 @@ jobs:
|
|||||||
draft: true
|
draft: true
|
||||||
prerelease: false
|
prerelease: false
|
||||||
files: |
|
files: |
|
||||||
|
PrismLauncher-Linux-Qt5-${{ env.VERSION }}.tar.gz
|
||||||
|
PrismLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-Linux-x86_64.AppImage
|
PrismLauncher-Linux-x86_64.AppImage
|
||||||
PrismLauncher-Linux-x86_64.AppImage.zsync
|
PrismLauncher-Linux-x86_64.AppImage.zsync
|
||||||
|
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-MinGW-arm64-${{ env.VERSION }}.zip
|
|
||||||
PrismLauncher-Windows-MinGW-arm64-Portable-${{ env.VERSION }}.zip
|
|
||||||
PrismLauncher-Windows-MinGW-arm64-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 }}.zip
|
PrismLauncher-macOS-${{ env.VERSION }}.tar.gz
|
||||||
|
PrismLauncher-macOS-Legacy-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-${{ env.VERSION }}.tar.gz
|
PrismLauncher-${{ env.VERSION }}.tar.gz
|
4
.github/workflows/update-flake.yml
vendored
4
.github/workflows/update-flake.yml
vendored
@ -17,9 +17,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: cachix/install-nix-action@526118121621777ccd86f79b04685a9319637641 # v31
|
- uses: cachix/install-nix-action@6a9a9e84a173d90b3ffb42c5ddaf9ea033fad011 # v23
|
||||||
|
|
||||||
- uses: DeterminateSystems/update-flake-lock@v24
|
- 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"
|
||||||
|
@ -1,21 +1,13 @@
|
|||||||
name: Publish
|
name: Publish to WinGet
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [ released ]
|
types: [released]
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
winget:
|
publish:
|
||||||
name: Winget
|
|
||||||
|
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Publish on Winget
|
- uses: vedantmgoyal2009/winget-releaser@v2
|
||||||
uses: vedantmgoyal2009/winget-releaser@v2
|
|
||||||
with:
|
with:
|
||||||
identifier: PrismLauncher.PrismLauncher
|
identifier: PrismLauncher.PrismLauncher
|
||||||
version: ${{ github.event.release.tag_name }}
|
version: ${{ github.event.release.tag_name }}
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -14,7 +14,6 @@ CMakeLists.txt.user.*
|
|||||||
CMakeSettings.json
|
CMakeSettings.json
|
||||||
/CMakeFiles
|
/CMakeFiles
|
||||||
CMakeCache.txt
|
CMakeCache.txt
|
||||||
CMakeUserPresets.json
|
|
||||||
/.project
|
/.project
|
||||||
/.settings
|
/.settings
|
||||||
/.idea
|
/.idea
|
||||||
@ -22,7 +21,6 @@ CMakeUserPresets.json
|
|||||||
/.vs
|
/.vs
|
||||||
cmake-build-*/
|
cmake-build-*/
|
||||||
Debug
|
Debug
|
||||||
compile_commands.json
|
|
||||||
|
|
||||||
# Build dirs
|
# Build dirs
|
||||||
build
|
build
|
||||||
@ -49,12 +47,8 @@ run/
|
|||||||
|
|
||||||
# Nix/NixOS
|
# Nix/NixOS
|
||||||
.direnv/
|
.direnv/
|
||||||
## Used when manually invoking stdenv phases
|
.pre-commit-config.yaml
|
||||||
outputs/
|
|
||||||
## Regular artifacts
|
|
||||||
result
|
result
|
||||||
result-*
|
|
||||||
repl-result-*
|
|
||||||
|
|
||||||
# Flatpak
|
# Flatpak
|
||||||
.flatpak-builder
|
.flatpak-builder
|
||||||
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -4,6 +4,9 @@
|
|||||||
[submodule "libraries/tomlplusplus"]
|
[submodule "libraries/tomlplusplus"]
|
||||||
path = libraries/tomlplusplus
|
path = libraries/tomlplusplus
|
||||||
url = https://github.com/marzer/tomlplusplus.git
|
url = https://github.com/marzer/tomlplusplus.git
|
||||||
|
[submodule "libraries/filesystem"]
|
||||||
|
path = libraries/filesystem
|
||||||
|
url = https://github.com/gulrak/filesystem
|
||||||
[submodule "libraries/libnbtplusplus"]
|
[submodule "libraries/libnbtplusplus"]
|
||||||
path = libraries/libnbtplusplus
|
path = libraries/libnbtplusplus
|
||||||
url = https://github.com/PrismLauncher/libnbtplusplus.git
|
url = https://github.com/PrismLauncher/libnbtplusplus.git
|
||||||
@ -19,6 +22,3 @@
|
|||||||
[submodule "flatpak/shared-modules"]
|
[submodule "flatpak/shared-modules"]
|
||||||
path = flatpak/shared-modules
|
path = flatpak/shared-modules
|
||||||
url = https://github.com/flathub/shared-modules.git
|
url = https://github.com/flathub/shared-modules.git
|
||||||
[submodule "libraries/qt-qrcodegenerator/QR-Code-generator"]
|
|
||||||
path = libraries/qt-qrcodegenerator/QR-Code-generator
|
|
||||||
url = https://github.com/nayuki/QR-Code-generator
|
|
||||||
|
3
BUILD.md
Normal file
3
BUILD.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Build Instructions
|
||||||
|
|
||||||
|
Full build instructions are available on [the website](https://prismlauncher.org/wiki/development/build-instructions/).
|
130
CMakeLists.txt
130
CMakeLists.txt
@ -78,18 +78,13 @@ else()
|
|||||||
# ATL's pack list needs more than the default 1 Mib stack on windows
|
# ATL's pack list needs more than the default 1 Mib stack on windows
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--stack,8388608 ${CMAKE_EXE_LINKER_FLAGS}")
|
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--stack,8388608 ${CMAKE_EXE_LINKER_FLAGS}")
|
||||||
|
|
||||||
# -ffunction-sections and -fdata-sections help reduce binary size
|
|
||||||
# -mguard=cf enables Control Flow Guard
|
|
||||||
# TODO: Look into -gc-sections to further reduce binary size
|
|
||||||
foreach(lang C CXX)
|
|
||||||
set("CMAKE_${lang}_FLAGS_RELEASE" "-ffunction-sections -fdata-sections -mguard=cf")
|
|
||||||
endforeach()
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_WARN_DEPRECATED_UP_TO=0x060200")
|
# Fix build with Qt 5.13
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_DISABLE_DEPRECATED_UP_TO=0x060000")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_DISABLE_DEPRECATED_BEFORE=0x050C00")
|
||||||
|
|
||||||
# Fix aarch64 build for toml++
|
# Fix aarch64 build for toml++
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTOML_ENABLE_FLOAT16=0")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTOML_ENABLE_FLOAT16=0")
|
||||||
@ -97,12 +92,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTOML_ENABLE_FLOAT16=0")
|
|||||||
# set CXXFLAGS for build targets
|
# set CXXFLAGS for build targets
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS_RELEASE}")
|
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||||
|
|
||||||
# Export compile commands for debug builds if we can (useful in LSPs like clangd)
|
|
||||||
# https://cmake.org/cmake/help/v3.31/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html
|
|
||||||
if(CMAKE_GENERATOR STREQUAL "Unix Makefiles" OR CMAKE_GENERATOR STREQUAL "Ninja" AND CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
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
|
||||||
@ -110,21 +99,21 @@ if ((CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebI
|
|||||||
message(STATUS "Address Sanitizer enabled for Debug builds, Turn it off with -DDEBUG_ADDRESS_SANITIZER=off")
|
message(STATUS "Address Sanitizer enabled for Debug builds, Turn it off with -DDEBUG_ADDRESS_SANITIZER=off")
|
||||||
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||||
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||||
# using clang with clang-cl front end
|
# using clang with clang-cl front end
|
||||||
message(STATUS "Address Sanitizer available on Clang MSVC frontend")
|
message(STATUS "Address Sanitizer available on Clang MSVC frontend")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /Oy-")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /Oy-")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /Oy-")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /Oy-")
|
||||||
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 -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover=null")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover=null")
|
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 -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover")
|
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")
|
||||||
@ -187,17 +176,14 @@ endif()
|
|||||||
set(Launcher_NEWS_RSS_URL "https://prismlauncher.org/feed/feed.xml" CACHE STRING "URL to fetch Prism Launcher's news RSS feed from.")
|
set(Launcher_NEWS_RSS_URL "https://prismlauncher.org/feed/feed.xml" CACHE STRING "URL to fetch Prism Launcher's news RSS feed from.")
|
||||||
set(Launcher_NEWS_OPEN_URL "https://prismlauncher.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
|
set(Launcher_NEWS_OPEN_URL "https://prismlauncher.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
|
||||||
set(Launcher_HELP_URL "https://prismlauncher.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help")
|
set(Launcher_HELP_URL "https://prismlauncher.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help")
|
||||||
set(Launcher_LOGIN_CALLBACK_URL "https://prismlauncher.org/successful-login" CACHE STRING "URL that gets opened when the user successfully logins.")
|
|
||||||
set(Launcher_FMLLIBS_BASE_URL "https://files.prismlauncher.org/fmllibs/" CACHE STRING "URL for FML Libraries.")
|
|
||||||
|
|
||||||
######## Set version numbers ########
|
######## Set version numbers ########
|
||||||
set(Launcher_VERSION_MAJOR 10)
|
set(Launcher_VERSION_MAJOR 8)
|
||||||
set(Launcher_VERSION_MINOR 0)
|
set(Launcher_VERSION_MINOR 0)
|
||||||
set(Launcher_VERSION_PATCH 0)
|
|
||||||
|
|
||||||
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_PATCH}")
|
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}")
|
||||||
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_PATCH}.0")
|
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.0.0")
|
||||||
set(Launcher_VERSION_NAME4_COMMA "${Launcher_VERSION_MAJOR},${Launcher_VERSION_MINOR},${Launcher_VERSION_PATCH},0")
|
set(Launcher_VERSION_NAME4_COMMA "${Launcher_VERSION_MAJOR},${Launcher_VERSION_MINOR},0,0")
|
||||||
|
|
||||||
# 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.")
|
||||||
@ -219,7 +205,6 @@ set(Launcher_BUG_TRACKER_URL "https://github.com/PrismLauncher/PrismLauncher/iss
|
|||||||
|
|
||||||
# Translations Platform URL
|
# Translations Platform URL
|
||||||
set(Launcher_TRANSLATIONS_URL "https://hosted.weblate.org/projects/prismlauncher/launcher/" CACHE STRING "URL for the translations platform.")
|
set(Launcher_TRANSLATIONS_URL "https://hosted.weblate.org/projects/prismlauncher/launcher/" CACHE STRING "URL for the translations platform.")
|
||||||
set(Launcher_TRANSLATION_FILES_URL "https://i18n.prismlauncher.org/" CACHE STRING "URL for the translations files.")
|
|
||||||
|
|
||||||
# Matrix Space
|
# Matrix Space
|
||||||
set(Launcher_MATRIX_URL "https://prismlauncher.org/matrix" CACHE STRING "URL to the Matrix Space")
|
set(Launcher_MATRIX_URL "https://prismlauncher.org/matrix" CACHE STRING "URL to the Matrix Space")
|
||||||
@ -234,19 +219,6 @@ 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")
|
||||||
|
|
||||||
# Java downloader
|
|
||||||
set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT ON)
|
|
||||||
|
|
||||||
# Although we recommend enabling this, we cannot guarantee binary compatibility on
|
|
||||||
# differing Linux/BSD/etc distributions. Downstream packagers should be explicitly opt-ing into this
|
|
||||||
# feature if they know it will work with their distribution.
|
|
||||||
if(UNIX AND NOT APPLE)
|
|
||||||
set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT OFF)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Java downloader
|
|
||||||
option(Launcher_ENABLE_JAVA_DOWNLOADER "Build the java downloader feature" ${Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT})
|
|
||||||
|
|
||||||
# Native libraries
|
# Native libraries
|
||||||
if(UNIX AND APPLE)
|
if(UNIX AND APPLE)
|
||||||
set(Launcher_GLFW_LIBRARY_NAME "libglfw.dylib" CACHE STRING "Name of native glfw library")
|
set(Launcher_GLFW_LIBRARY_NAME "libglfw.dylib" CACHE STRING "Name of native glfw library")
|
||||||
@ -308,11 +280,23 @@ endif()
|
|||||||
|
|
||||||
# Find the required Qt parts
|
# Find the required Qt parts
|
||||||
include(QtVersionlessBackport)
|
include(QtVersionlessBackport)
|
||||||
if(Launcher_QT_VERSION_MAJOR EQUAL 6)
|
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
|
||||||
|
set(QT_VERSION_MAJOR 5)
|
||||||
|
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml)
|
||||||
|
|
||||||
|
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
||||||
|
find_package(QuaZip-Qt5 1.3 QUIET)
|
||||||
|
endif()
|
||||||
|
if (NOT QuaZip-Qt5_FOUND)
|
||||||
|
set(QUAZIP_QT_MAJOR_VERSION ${QT_VERSION_MAJOR} CACHE STRING "Qt version to use (4, 5 or 6), defaults to ${QT_VERSION_MAJOR}" FORCE)
|
||||||
|
set(FORCE_BUNDLED_QUAZIP 1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Qt 6 sets these by default. Notably causes Windows APIs to use UNICODE strings.
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNICODE -D_UNICODE")
|
||||||
|
elseif(Launcher_QT_VERSION_MAJOR EQUAL 6)
|
||||||
set(QT_VERSION_MAJOR 6)
|
set(QT_VERSION_MAJOR 6)
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml Core5Compat NetworkAuth OpenGL)
|
find_package(Qt6 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml Core5Compat)
|
||||||
find_package(Qt6 COMPONENTS DBus)
|
|
||||||
list(APPEND Launcher_QT_DBUS Qt6::DBus)
|
|
||||||
list(APPEND Launcher_QT_LIBS Qt6::Core5Compat)
|
list(APPEND Launcher_QT_LIBS Qt6::Core5Compat)
|
||||||
|
|
||||||
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
||||||
@ -326,16 +310,29 @@ else()
|
|||||||
message(FATAL_ERROR "Qt version ${Launcher_QT_VERSION_MAJOR} is not supported")
|
message(FATAL_ERROR "Qt version ${Launcher_QT_VERSION_MAJOR} is not supported")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(Launcher_QT_VERSION_MAJOR EQUAL 6)
|
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
|
||||||
|
include(ECMQueryQt)
|
||||||
|
ecm_query_qt(QT_PLUGINS_DIR QT_INSTALL_PLUGINS)
|
||||||
|
ecm_query_qt(QT_LIBS_DIR QT_INSTALL_LIBS)
|
||||||
|
ecm_query_qt(QT_LIBEXECS_DIR QT_INSTALL_LIBEXECS)
|
||||||
|
else()
|
||||||
set(QT_PLUGINS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_PLUGINS})
|
set(QT_PLUGINS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_PLUGINS})
|
||||||
set(QT_LIBS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBS})
|
set(QT_LIBS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBS})
|
||||||
set(QT_LIBEXECS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBEXECS})
|
set(QT_LIBEXECS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBEXECS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# NOTE: Qt 6 already sets this by default
|
||||||
|
if (Qt5_POSITION_INDEPENDENT_CODE)
|
||||||
|
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
||||||
# Find toml++
|
# Find toml++
|
||||||
find_package(tomlplusplus 3.2.0 QUIET)
|
find_package(tomlplusplus 3.2.0 QUIET)
|
||||||
|
|
||||||
|
# Find ghc_filesystem
|
||||||
|
find_package(ghc_filesystem QUIET)
|
||||||
|
|
||||||
# Find cmark
|
# Find cmark
|
||||||
find_package(cmark QUIET)
|
find_package(cmark QUIET)
|
||||||
endif()
|
endif()
|
||||||
@ -353,7 +350,7 @@ set(Launcher_ENABLE_UPDATER NO)
|
|||||||
set(Launcher_BUILD_UPDATER NO)
|
set(Launcher_BUILD_UPDATER NO)
|
||||||
|
|
||||||
if (NOT APPLE AND (NOT Launcher_UPDATER_GITHUB_REPO STREQUAL "" AND NOT Launcher_BUILD_ARTIFACT STREQUAL ""))
|
if (NOT APPLE AND (NOT Launcher_UPDATER_GITHUB_REPO STREQUAL "" AND NOT Launcher_BUILD_ARTIFACT STREQUAL ""))
|
||||||
set(Launcher_BUILD_UPDATER YES)
|
set(Launcher_BUILD_UPDATER YES)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT (UNIX AND APPLE))
|
if(NOT (UNIX AND APPLE))
|
||||||
@ -380,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 "${Launcher_Copyright_Mac}")
|
set(MACOSX_BUNDLE_COPYRIGHT "© 2022-2023 ${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.6.4/Sparkle-2.6.4.tar.xz" CACHE STRING "URL to Sparkle release archive")
|
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_SHA256 "50612a06038abc931f16011d7903b8326a362c1074dabccb718404ce8e585f0b" CACHE STRING "SHA256 checksum for Sparkle release archive")
|
set(MACOSX_SPARKLE_SHA256 "bf6ac1caa9f8d321d5784859c88da874f28412f37fb327bc21b7b14c5d61ef94" 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
|
||||||
@ -420,19 +417,7 @@ elseif(UNIX)
|
|||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_mrpack_MIMEInfo} DESTINATION ${KDE_INSTALL_MIMEDIR})
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_mrpack_MIMEInfo} DESTINATION ${KDE_INSTALL_MIMEDIR})
|
||||||
|
|
||||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/launcher/qtlogging.ini" DESTINATION "share/${Launcher_Name}")
|
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/launcher/qtlogging.ini" DESTINATION "share/${Launcher_Name}")
|
||||||
|
|
||||||
if (INSTALL_BUNDLE STREQUAL full)
|
|
||||||
set(PLUGIN_DEST_DIR "plugins")
|
|
||||||
set(BUNDLE_DEST_DIR ".")
|
|
||||||
set(RESOURCES_DEST_DIR ".")
|
|
||||||
|
|
||||||
# Apps to bundle
|
|
||||||
set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${Launcher_APP_BINARY_NAME}")
|
|
||||||
|
|
||||||
# directories to look for dependencies
|
|
||||||
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(Launcher_ManPage)
|
if(Launcher_ManPage)
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION "${KDE_INSTALL_MANDIR}/man6")
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION "${KDE_INSTALL_MANDIR}/man6")
|
||||||
endif()
|
endif()
|
||||||
@ -475,7 +460,6 @@ add_subdirectory(libraries/libnbtplusplus)
|
|||||||
add_subdirectory(libraries/systeminfo) # system information library
|
add_subdirectory(libraries/systeminfo) # system information library
|
||||||
add_subdirectory(libraries/launcher) # java based launcher part for Minecraft
|
add_subdirectory(libraries/launcher) # java based launcher part for Minecraft
|
||||||
add_subdirectory(libraries/javacheck) # java compatibility checker
|
add_subdirectory(libraries/javacheck) # java compatibility checker
|
||||||
add_subdirectory(libraries/qt-qrcodegenerator) # qr code generator
|
|
||||||
if(FORCE_BUNDLED_ZLIB)
|
if(FORCE_BUNDLED_ZLIB)
|
||||||
message(STATUS "Using bundled zlib")
|
message(STATUS "Using bundled zlib")
|
||||||
|
|
||||||
@ -483,7 +467,7 @@ if(FORCE_BUNDLED_ZLIB)
|
|||||||
set(SKIP_INSTALL_ALL ON)
|
set(SKIP_INSTALL_ALL ON)
|
||||||
add_subdirectory(libraries/zlib EXCLUDE_FROM_ALL)
|
add_subdirectory(libraries/zlib EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
# On OS where unistd.h exists, zlib's generated header defines `Z_HAVE_UNISTD_H`, while the included header does not.
|
# On OS where unistd.h exists, zlib's generated header defines `Z_HAVE_UNISTD_H`, while the included header does not.
|
||||||
# We cannot safely undo the rename on those systems, and they generally have packages for zlib anyway.
|
# We cannot safely undo the rename on those systems, and they generally have packages for zlib anyway.
|
||||||
check_include_file(unistd.h NEED_GENERATED_ZCONF)
|
check_include_file(unistd.h NEED_GENERATED_ZCONF)
|
||||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib/zconf.h.included" AND NOT NEED_GENERATED_ZCONF)
|
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib/zconf.h.included" AND NOT NEED_GENERATED_ZCONF)
|
||||||
@ -520,17 +504,23 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
if(NOT cmark_FOUND)
|
if(NOT cmark_FOUND)
|
||||||
message(STATUS "Using bundled cmark")
|
message(STATUS "Using bundled cmark")
|
||||||
set(ORIGINAL_BUILD_TESTING ${BUILD_TESTING})
|
set(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)
|
add_library(cmark::cmark ALIAS cmark_static)
|
||||||
set(BUILD_TESTING ${ORIGINAL_BUILD_TESTING})
|
|
||||||
else()
|
else()
|
||||||
message(STATUS "Using system cmark")
|
message(STATUS "Using system cmark")
|
||||||
endif()
|
endif()
|
||||||
|
add_subdirectory(libraries/katabasis) # An OAuth2 library that tried to do too much
|
||||||
add_subdirectory(libraries/gamemode)
|
add_subdirectory(libraries/gamemode)
|
||||||
add_subdirectory(libraries/murmur2) # Hash for usage with the CurseForge API
|
add_subdirectory(libraries/murmur2) # Hash for usage with the CurseForge API
|
||||||
|
if (NOT ghc_filesystem_FOUND)
|
||||||
|
message(STATUS "Using bundled ghc_filesystem")
|
||||||
|
add_subdirectory(libraries/filesystem) # Implementation of std::filesystem for old C++, for usage in old macOS
|
||||||
|
else()
|
||||||
|
message(STATUS "Using system ghc_filesystem")
|
||||||
|
endif()
|
||||||
add_subdirectory(libraries/qdcss) # css parser
|
add_subdirectory(libraries/qdcss) # css parser
|
||||||
|
|
||||||
############################### Built Artifacts ###############################
|
############################### Built Artifacts ###############################
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json",
|
|
||||||
"version": 8,
|
|
||||||
"cmakeMinimumRequired": {
|
|
||||||
"major": 3,
|
|
||||||
"minor": 28
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"cmake/linuxPreset.json",
|
|
||||||
"cmake/macosPreset.json",
|
|
||||||
"cmake/windowsMinGWPreset.json",
|
|
||||||
"cmake/windowsMSVCPreset.json"
|
|
||||||
]
|
|
||||||
}
|
|
@ -2,59 +2,16 @@
|
|||||||
|
|
||||||
## Code formatting
|
## Code formatting
|
||||||
|
|
||||||
All files are formatted with `clang-format` using the configuration in `.clang-format`. Ensure it is run on changed files before committing!
|
Try to follow the existing formatting.
|
||||||
|
If there is no existing formatting, you may use `clang-format` with our included `.clang-format` configuration.
|
||||||
|
|
||||||
Please also follow the project's conventions for C++:
|
In general, in order of importance:
|
||||||
|
|
||||||
- Class and type names should be formatted as `PascalCase`: `MyClass`.
|
- Make sure your IDE is not messing up line endings or whitespace and avoid using linters.
|
||||||
- Private or protected class data members should be formatted as `camelCase` prefixed with `m_`: `m_myCounter`.
|
- Prefer readability over dogma.
|
||||||
- Private or protected `static` class data members should be formatted as `camelCase` prefixed with `s_`: `s_instance`.
|
- Keep to the existing formatting.
|
||||||
- Public class data members should be formatted as `camelCase` without the prefix: `dateOfBirth`.
|
- Indent with 4 space unless it's in a submodule.
|
||||||
- Public, private or protected `static const` class data members should be formatted as `SCREAMING_SNAKE_CASE`: `MAX_VALUE`.
|
- Keep lists (of arguments, parameters, initializers...) as lists, not paragraphs. It should either read from top to bottom, or left to right. Not both.
|
||||||
- Class function members should be formatted as `camelCase` without a prefix: `incrementCounter`.
|
|
||||||
- Global functions and non-`const` global variables should be formatted as `camelCase` without a prefix: `globalData`.
|
|
||||||
- `const` global variables, macros, and enum constants should be formatted as `SCREAMING_SNAKE_CASE`: `LIGHT_GRAY`.
|
|
||||||
- Avoid inventing acronyms or abbreviations especially for a name of multiple words - like `tp` for `texturePack`.
|
|
||||||
|
|
||||||
Most of these rules are included in the `.clang-tidy` file, so you can run `clang-tidy` to check for any violations.
|
|
||||||
|
|
||||||
Here is what these conventions with the formatting configuration look like:
|
|
||||||
|
|
||||||
```c++
|
|
||||||
#define AWESOMENESS 10
|
|
||||||
|
|
||||||
constexpr double PI = 3.14159;
|
|
||||||
|
|
||||||
enum class PizzaToppings { HAM_AND_PINEAPPLE, OREO_AND_KETCHUP };
|
|
||||||
|
|
||||||
struct Person {
|
|
||||||
QString name;
|
|
||||||
QDateTime dateOfBirth;
|
|
||||||
|
|
||||||
long daysOld() const { return dateOfBirth.daysTo(QDateTime::currentDateTime()); }
|
|
||||||
};
|
|
||||||
|
|
||||||
class ImportantClass {
|
|
||||||
public:
|
|
||||||
void incrementCounter()
|
|
||||||
{
|
|
||||||
if (m_counter + 1 > MAX_COUNTER_VALUE)
|
|
||||||
throw std::runtime_error("Counter has reached limit!");
|
|
||||||
|
|
||||||
++m_counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
int counter() const { return m_counter; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
static constexpr int MAX_COUNTER_VALUE = 100;
|
|
||||||
int m_counter;
|
|
||||||
};
|
|
||||||
|
|
||||||
ImportantClass importantClassInstance;
|
|
||||||
```
|
|
||||||
|
|
||||||
If you see any names which do not follow these conventions, it is preferred that you leave them be - renames increase the number of changes therefore make reviewing harder and make your PR more prone to conflicts. However, if you're refactoring a whole class anyway, it's fine.
|
|
||||||
|
|
||||||
## Signing your work
|
## Signing your work
|
||||||
|
|
||||||
|
63
COPYING.md
63
COPYING.md
@ -1,7 +1,7 @@
|
|||||||
## Prism Launcher
|
## Prism Launcher
|
||||||
|
|
||||||
Prism Launcher - Minecraft Launcher
|
Prism Launcher - Minecraft Launcher
|
||||||
Copyright (C) 2022-2025 Prism Launcher Contributors
|
Copyright (C) 2022-2023 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
|
||||||
@ -108,7 +108,7 @@
|
|||||||
|
|
||||||
Information on third party licenses used in MinGW-w64 can be found in its COPYING.MinGW-w64-runtime.txt.
|
Information on third party licenses used in MinGW-w64 can be found in its COPYING.MinGW-w64-runtime.txt.
|
||||||
|
|
||||||
## Qt 6
|
## Qt 5/6
|
||||||
|
|
||||||
Copyright (C) 2022 The Qt Company Ltd and other contributors.
|
Copyright (C) 2022 The Qt Company Ltd and other contributors.
|
||||||
Contact: https://www.qt.io/licensing
|
Contact: https://www.qt.io/licensing
|
||||||
@ -333,6 +333,32 @@
|
|||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
## O2 (Katabasis fork)
|
||||||
|
|
||||||
|
Copyright (c) 2012, Akos Polster
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
## Gamemode
|
## Gamemode
|
||||||
|
|
||||||
Copyright (c) 2017-2022, Feral Interactive
|
Copyright (c) 2017-2022, Feral Interactive
|
||||||
@ -362,6 +388,28 @@
|
|||||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
## gulrak/filesystem
|
||||||
|
|
||||||
|
Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
## Breeze icons
|
## Breeze icons
|
||||||
|
|
||||||
Copyright (C) 2014 Uri Herrera <uri_herrera@nitrux.in> and others
|
Copyright (C) 2014 Uri Herrera <uri_herrera@nitrux.in> and others
|
||||||
@ -388,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
|
||||||
@ -403,12 +451,3 @@
|
|||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
## qt-qrcodegenerator (`libraries/qt-qrcodegenerator`)
|
|
||||||
|
|
||||||
Copyright © 2024 Project Nayuki. (MIT License)
|
|
||||||
https://www.nayuki.io/page/qr-code-generator-library
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
@ -61,12 +61,7 @@ The translation effort for Prism Launcher is hosted on [Weblate](https://hosted.
|
|||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
If you want to build Prism Launcher yourself, check the build instructions:
|
If you want to build Prism Launcher yourself, check the [Build Instructions](https://prismlauncher.org/wiki/development/build-instructions/).
|
||||||
|
|
||||||
- [Windows](https://prismlauncher.org/wiki/development/build-instructions/windows/)
|
|
||||||
- [Linux](https://prismlauncher.org/wiki/development/build-instructions/linux/)
|
|
||||||
- [MacOS](https://prismlauncher.org/wiki/development/build-instructions/macos/)
|
|
||||||
- [OpenBSD](https://prismlauncher.org/wiki/development/build-instructions/openbsd/)
|
|
||||||
|
|
||||||
## Sponsors & Partners
|
## Sponsors & Partners
|
||||||
|
|
||||||
|
@ -34,8 +34,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <qstringliteral.h>
|
#include <qstringliteral.h>
|
||||||
#include <QObject>
|
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
const Config BuildConfig;
|
const Config BuildConfig;
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ Config::Config()
|
|||||||
LAUNCHER_DOMAIN = "@Launcher_Domain@";
|
LAUNCHER_DOMAIN = "@Launcher_Domain@";
|
||||||
LAUNCHER_CONFIGFILE = "@Launcher_ConfigFile@";
|
LAUNCHER_CONFIGFILE = "@Launcher_ConfigFile@";
|
||||||
LAUNCHER_GIT = "@Launcher_Git@";
|
LAUNCHER_GIT = "@Launcher_Git@";
|
||||||
LAUNCHER_APPID = "@Launcher_AppID@";
|
LAUNCHER_DESKTOPFILENAME = "@Launcher_DesktopFileName@";
|
||||||
LAUNCHER_SVGFILENAME = "@Launcher_SVGFileName@";
|
LAUNCHER_SVGFILENAME = "@Launcher_SVGFileName@";
|
||||||
|
|
||||||
USER_AGENT = "@Launcher_UserAgent@";
|
USER_AGENT = "@Launcher_UserAgent@";
|
||||||
@ -58,7 +58,6 @@ Config::Config()
|
|||||||
// Version information
|
// Version information
|
||||||
VERSION_MAJOR = @Launcher_VERSION_MAJOR@;
|
VERSION_MAJOR = @Launcher_VERSION_MAJOR@;
|
||||||
VERSION_MINOR = @Launcher_VERSION_MINOR@;
|
VERSION_MINOR = @Launcher_VERSION_MINOR@;
|
||||||
VERSION_PATCH = @Launcher_VERSION_PATCH@;
|
|
||||||
|
|
||||||
BUILD_PLATFORM = "@Launcher_BUILD_PLATFORM@";
|
BUILD_PLATFORM = "@Launcher_BUILD_PLATFORM@";
|
||||||
BUILD_ARTIFACT = "@Launcher_BUILD_ARTIFACT@";
|
BUILD_ARTIFACT = "@Launcher_BUILD_ARTIFACT@";
|
||||||
@ -75,52 +74,55 @@ Config::Config()
|
|||||||
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@";
|
||||||
|
|
||||||
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()) {
|
} else if(!UPDATER_GITHUB_REPO.isEmpty() && !BUILD_ARTIFACT.isEmpty()) {
|
||||||
UPDATER_ENABLED = true;
|
UPDATER_ENABLED = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#cmakedefine01 Launcher_ENABLE_JAVA_DOWNLOADER
|
|
||||||
JAVA_DOWNLOADER_ENABLED = Launcher_ENABLE_JAVA_DOWNLOADER;
|
|
||||||
|
|
||||||
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
|
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
|
||||||
GIT_TAG = "@Launcher_GIT_TAG@";
|
GIT_TAG = "@Launcher_GIT_TAG@";
|
||||||
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
|
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
|
||||||
|
|
||||||
// Assume that builds outside of Git repos are "stable"
|
// Assume that builds outside of Git repos are "stable"
|
||||||
if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND") || GIT_TAG == QStringLiteral("GITDIR-NOTFOUND") ||
|
if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND")
|
||||||
GIT_REFSPEC == QStringLiteral("") || GIT_TAG == QStringLiteral("GIT-NOTFOUND")) {
|
|| GIT_TAG == QStringLiteral("GITDIR-NOTFOUND")
|
||||||
|
|| GIT_REFSPEC == QStringLiteral("")
|
||||||
|
|| GIT_TAG == QStringLiteral("GIT-NOTFOUND"))
|
||||||
|
{
|
||||||
GIT_REFSPEC = "refs/heads/stable";
|
GIT_REFSPEC = "refs/heads/stable";
|
||||||
GIT_TAG = versionString();
|
GIT_TAG = versionString();
|
||||||
GIT_COMMIT = "";
|
GIT_COMMIT = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
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/");
|
||||||
} else if (!GIT_COMMIT.isEmpty()) {
|
}
|
||||||
|
else if (!GIT_COMMIT.isEmpty())
|
||||||
|
{
|
||||||
VERSION_CHANNEL = GIT_COMMIT.mid(0, 8);
|
VERSION_CHANNEL = GIT_COMMIT.mid(0, 8);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
VERSION_CHANNEL = "unknown";
|
VERSION_CHANNEL = "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
NEWS_RSS_URL = "@Launcher_NEWS_RSS_URL@";
|
NEWS_RSS_URL = "@Launcher_NEWS_RSS_URL@";
|
||||||
NEWS_OPEN_URL = "@Launcher_NEWS_OPEN_URL@";
|
NEWS_OPEN_URL = "@Launcher_NEWS_OPEN_URL@";
|
||||||
HELP_URL = "@Launcher_HELP_URL@";
|
HELP_URL = "@Launcher_HELP_URL@";
|
||||||
LOGIN_CALLBACK_URL = "@Launcher_LOGIN_CALLBACK_URL@";
|
|
||||||
IMGUR_CLIENT_ID = "@Launcher_IMGUR_CLIENT_ID@";
|
IMGUR_CLIENT_ID = "@Launcher_IMGUR_CLIENT_ID@";
|
||||||
MSA_CLIENT_ID = "@Launcher_MSA_CLIENT_ID@";
|
MSA_CLIENT_ID = "@Launcher_MSA_CLIENT_ID@";
|
||||||
FLAME_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
|
FLAME_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
|
||||||
META_URL = "@Launcher_META_URL@";
|
META_URL = "@Launcher_META_URL@";
|
||||||
FMLLIBS_BASE_URL = "@Launcher_FMLLIBS_BASE_URL@";
|
|
||||||
|
|
||||||
GLFW_LIBRARY_NAME = "@Launcher_GLFW_LIBRARY_NAME@";
|
GLFW_LIBRARY_NAME = "@Launcher_GLFW_LIBRARY_NAME@";
|
||||||
OPENAL_LIBRARY_NAME = "@Launcher_OPENAL_LIBRARY_NAME@";
|
OPENAL_LIBRARY_NAME = "@Launcher_OPENAL_LIBRARY_NAME@";
|
||||||
|
|
||||||
BUG_TRACKER_URL = "@Launcher_BUG_TRACKER_URL@";
|
BUG_TRACKER_URL = "@Launcher_BUG_TRACKER_URL@";
|
||||||
TRANSLATIONS_URL = "@Launcher_TRANSLATIONS_URL@";
|
TRANSLATIONS_URL = "@Launcher_TRANSLATIONS_URL@";
|
||||||
TRANSLATION_FILES_URL = "@Launcher_TRANSLATION_FILES_URL@";
|
|
||||||
MATRIX_URL = "@Launcher_MATRIX_URL@";
|
MATRIX_URL = "@Launcher_MATRIX_URL@";
|
||||||
DISCORD_URL = "@Launcher_DISCORD_URL@";
|
DISCORD_URL = "@Launcher_DISCORD_URL@";
|
||||||
SUBREDDIT_URL = "@Launcher_SUBREDDIT_URL@";
|
SUBREDDIT_URL = "@Launcher_SUBREDDIT_URL@";
|
||||||
@ -128,7 +130,7 @@ Config::Config()
|
|||||||
|
|
||||||
QString Config::versionString() const
|
QString Config::versionString() const
|
||||||
{
|
{
|
||||||
return QString("%1.%2.%3").arg(VERSION_MAJOR).arg(VERSION_MINOR).arg(VERSION_PATCH);
|
return QString("%1.%2").arg(VERSION_MAJOR).arg(VERSION_MINOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Config::printableVersionString() const
|
QString Config::printableVersionString() const
|
||||||
@ -136,7 +138,8 @@ QString Config::printableVersionString() const
|
|||||||
QString vstr = versionString();
|
QString vstr = versionString();
|
||||||
|
|
||||||
// If the build is not a main release, append the channel
|
// If the build is not a main release, append the channel
|
||||||
if (VERSION_CHANNEL != "stable" && GIT_TAG != vstr) {
|
if(VERSION_CHANNEL != "stable" && GIT_TAG != vstr)
|
||||||
|
{
|
||||||
vstr += "-" + VERSION_CHANNEL;
|
vstr += "-" + VERSION_CHANNEL;
|
||||||
}
|
}
|
||||||
return vstr;
|
return vstr;
|
||||||
@ -153,3 +156,4 @@ QString Config::systemID() const
|
|||||||
{
|
{
|
||||||
return QStringLiteral("%1 %2 %3").arg(COMPILER_TARGET_SYSTEM, COMPILER_TARGET_SYSTEM_VERSION, COMPILER_TARGET_SYSTEM_PROCESSOR);
|
return QStringLiteral("%1 %2 %3").arg(COMPILER_TARGET_SYSTEM, COMPILER_TARGET_SYSTEM_VERSION, COMPILER_TARGET_SYSTEM_PROCESSOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,15 +52,13 @@ class Config {
|
|||||||
QString LAUNCHER_DOMAIN;
|
QString LAUNCHER_DOMAIN;
|
||||||
QString LAUNCHER_CONFIGFILE;
|
QString LAUNCHER_CONFIGFILE;
|
||||||
QString LAUNCHER_GIT;
|
QString LAUNCHER_GIT;
|
||||||
QString LAUNCHER_APPID;
|
QString LAUNCHER_DESKTOPFILENAME;
|
||||||
QString LAUNCHER_SVGFILENAME;
|
QString LAUNCHER_SVGFILENAME;
|
||||||
|
|
||||||
/// The major version number.
|
/// The major version number.
|
||||||
int VERSION_MAJOR;
|
int VERSION_MAJOR;
|
||||||
/// The minor version number.
|
/// The minor version number.
|
||||||
int VERSION_MINOR;
|
int VERSION_MINOR;
|
||||||
/// The patch version number.
|
|
||||||
int VERSION_PATCH;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The version channel
|
* The version channel
|
||||||
@ -69,7 +67,6 @@ class Config {
|
|||||||
QString VERSION_CHANNEL;
|
QString VERSION_CHANNEL;
|
||||||
|
|
||||||
bool UPDATER_ENABLED = false;
|
bool UPDATER_ENABLED = false;
|
||||||
bool JAVA_DOWNLOADER_ENABLED = false;
|
|
||||||
|
|
||||||
/// A short string identifying this build's platform or distribution.
|
/// A short string identifying this build's platform or distribution.
|
||||||
QString BUILD_PLATFORM;
|
QString BUILD_PLATFORM;
|
||||||
@ -135,11 +132,6 @@ class Config {
|
|||||||
*/
|
*/
|
||||||
QString HELP_URL;
|
QString HELP_URL;
|
||||||
|
|
||||||
/**
|
|
||||||
* URL that gets opened when the user succesfully logins.
|
|
||||||
*/
|
|
||||||
QString LOGIN_CALLBACK_URL;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client ID you can get from Imgur when you register an application
|
* Client ID you can get from Imgur when you register an application
|
||||||
*/
|
*/
|
||||||
@ -171,9 +163,10 @@ class Config {
|
|||||||
|
|
||||||
QString RESOURCE_BASE = "https://resources.download.minecraft.net/";
|
QString RESOURCE_BASE = "https://resources.download.minecraft.net/";
|
||||||
QString LIBRARY_BASE = "https://libraries.minecraft.net/";
|
QString LIBRARY_BASE = "https://libraries.minecraft.net/";
|
||||||
|
QString AUTH_BASE = "https://authserver.mojang.com/";
|
||||||
QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
|
QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
|
||||||
QString FMLLIBS_BASE_URL;
|
QString FMLLIBS_BASE_URL = "https://files.prismlauncher.org/fmllibs/"; // FIXME: move into CMakeLists
|
||||||
QString TRANSLATION_FILES_URL;
|
QString TRANSLATIONS_BASE_URL = "https://i18n.prismlauncher.org/"; // FIXME: move into CMakeLists
|
||||||
|
|
||||||
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";
|
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";
|
||||||
|
|
||||||
|
@ -68,8 +68,6 @@ function(
|
|||||||
/w14906 # string literal cast to 'LPWSTR'
|
/w14906 # string literal cast to 'LPWSTR'
|
||||||
/w14928 # illegal copy-initialization; more than one user-defined conversion has been implicitly applied
|
/w14928 # illegal copy-initialization; more than one user-defined conversion has been implicitly applied
|
||||||
/permissive- # standards conformance mode for MSVC compiler.
|
/permissive- # standards conformance mode for MSVC compiler.
|
||||||
|
|
||||||
/we4062 # forbid omitting a possible value of an enum in a switch statement
|
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -95,8 +93,6 @@ function(
|
|||||||
# in a lot of noise. This warning is only notifying us that clang is emulating the GCC behaviour
|
# 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
|
# instead of the exact standard wording so we can safely ignore it
|
||||||
-Wno-gnu-zero-variadic-macro-arguments
|
-Wno-gnu-zero-variadic-macro-arguments
|
||||||
|
|
||||||
-Werror=switch # forbid omitting a possible value of an enum in a switch statement
|
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -108,8 +104,6 @@ function(
|
|||||||
-Wduplicated-branches # warn if if / else branches have duplicated code
|
-Wduplicated-branches # warn if if / else branches have duplicated code
|
||||||
-Wlogical-op # warn about logical operations being used where bitwise were probably wanted
|
-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
|
-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()
|
endif()
|
||||||
|
|
||||||
@ -134,8 +128,6 @@ function(
|
|||||||
-Woverloaded-virtual
|
-Woverloaded-virtual
|
||||||
-Wuseless-cast
|
-Wuseless-cast
|
||||||
-Wextra-semi
|
-Wextra-semi
|
||||||
|
|
||||||
-Werror=switch # forbid omitting a possible value of an enum in a switch statement
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_options(
|
target_compile_options(
|
||||||
|
@ -6,10 +6,6 @@
|
|||||||
<string>A Minecraft mod wants to access your camera.</string>
|
<string>A Minecraft mod wants to access your camera.</string>
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
<string>A Minecraft mod wants to access your microphone.</string>
|
<string>A Minecraft mod wants to access your microphone.</string>
|
||||||
<key>NSDownloadsFolderUsageDescription</key>
|
|
||||||
<string>Prism uses access to your Downloads folder to help you more quickly add mods that can't be automatically downloaded to your instance. You can change where Prism scans for downloaded mods in Settings or the prompt that appears.</string>
|
|
||||||
<key>NSLocalNetworkUsageDescription</key>
|
|
||||||
<string>Minecraft uses the local network to find and connect to LAN servers.</string>
|
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
<string>NSApplication</string>
|
<string>NSApplication</string>
|
||||||
<key>NSHighResolutionCapable</key>
|
<key>NSHighResolutionCapable</key>
|
||||||
@ -81,14 +77,6 @@
|
|||||||
<string>curseforge</string>
|
<string>curseforge</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
<dict>
|
|
||||||
<key>CFBundleURLName</key>
|
|
||||||
<string>Prismlauncher</string>
|
|
||||||
<key>CFBundleURLSchemes</key>
|
|
||||||
<array>
|
|
||||||
<string>prismlauncher</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json",
|
|
||||||
"version": 8,
|
|
||||||
"configurePresets": [
|
|
||||||
{
|
|
||||||
"name": "base",
|
|
||||||
"hidden": true,
|
|
||||||
"binaryDir": "build",
|
|
||||||
"installDir": "install",
|
|
||||||
"cacheVariables": {
|
|
||||||
"Launcher_BUILD_PLATFORM": "custom"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "base_debug",
|
|
||||||
"hidden": true,
|
|
||||||
"inherits": [
|
|
||||||
"base"
|
|
||||||
],
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_BUILD_TYPE": "Debug"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "base_release",
|
|
||||||
"hidden": true,
|
|
||||||
"inherits": [
|
|
||||||
"base"
|
|
||||||
],
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_BUILD_TYPE": "Release",
|
|
||||||
"ENABLE_LTO": "ON"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "base_ci",
|
|
||||||
"hidden": true,
|
|
||||||
"inherits": [
|
|
||||||
"base_release"
|
|
||||||
],
|
|
||||||
"cacheVariables": {
|
|
||||||
"Launcher_BUILD_PLATFORM": "official",
|
|
||||||
"Launcher_FORCE_BUNDLED_LIBS": "ON"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"testPresets": [
|
|
||||||
{
|
|
||||||
"name": "base",
|
|
||||||
"hidden": true,
|
|
||||||
"output": {
|
|
||||||
"outputOnFailure": true
|
|
||||||
},
|
|
||||||
"execution": {
|
|
||||||
"noTestsAction": "error"
|
|
||||||
},
|
|
||||||
"filter": {
|
|
||||||
"exclude": {
|
|
||||||
"name": "^example64|example$"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "base_debug",
|
|
||||||
"hidden": true,
|
|
||||||
"inherits": [
|
|
||||||
"base"
|
|
||||||
],
|
|
||||||
"output": {
|
|
||||||
"debug": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "base_release",
|
|
||||||
"hidden": true,
|
|
||||||
"inherits": [
|
|
||||||
"base"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,180 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json",
|
|
||||||
"version": 8,
|
|
||||||
"include": [
|
|
||||||
"commonPresets.json"
|
|
||||||
],
|
|
||||||
"configurePresets": [
|
|
||||||
{
|
|
||||||
"name": "linux_base",
|
|
||||||
"hidden": true,
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Linux"
|
|
||||||
},
|
|
||||||
"generator": "Ninja",
|
|
||||||
"cacheVariables": {
|
|
||||||
"Launcher_BUILD_ARTIFACT": "Linux-Qt6",
|
|
||||||
"Launcher_ENABLE_JAVA_DOWNLOADER": "ON"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "linux_debug",
|
|
||||||
"inherits": [
|
|
||||||
"base_debug",
|
|
||||||
"linux_base"
|
|
||||||
],
|
|
||||||
"displayName": "Linux (Debug)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "linux_release",
|
|
||||||
"inherits": [
|
|
||||||
"base_release",
|
|
||||||
"linux_base"
|
|
||||||
],
|
|
||||||
"displayName": "Linux (Release)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "linux_ci",
|
|
||||||
"inherits": [
|
|
||||||
"base_ci",
|
|
||||||
"linux_base"
|
|
||||||
],
|
|
||||||
"displayName": "Linux (CI)",
|
|
||||||
"cacheVariables": {
|
|
||||||
"Launcher_BUILD_ARTIFACT": "Linux-Qt6"
|
|
||||||
},
|
|
||||||
"installDir": "/usr"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"buildPresets": [
|
|
||||||
{
|
|
||||||
"name": "linux_base",
|
|
||||||
"hidden": true,
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Linux"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "linux_debug",
|
|
||||||
"inherits": [
|
|
||||||
"linux_base"
|
|
||||||
],
|
|
||||||
"displayName": "Linux (Debug)",
|
|
||||||
"configurePreset": "linux_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "linux_release",
|
|
||||||
"inherits": [
|
|
||||||
"linux_base"
|
|
||||||
],
|
|
||||||
"displayName": "Linux (Release)",
|
|
||||||
"configurePreset": "linux_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "linux_ci",
|
|
||||||
"inherits": [
|
|
||||||
"linux_base"
|
|
||||||
],
|
|
||||||
"displayName": "Linux (CI)",
|
|
||||||
"configurePreset": "linux_ci"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"testPresets": [
|
|
||||||
{
|
|
||||||
"name": "linux_base",
|
|
||||||
"hidden": true,
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Linux"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "linux_debug",
|
|
||||||
"inherits": [
|
|
||||||
"base_debug",
|
|
||||||
"linux_base"
|
|
||||||
],
|
|
||||||
"displayName": "Linux (Debug)",
|
|
||||||
"configurePreset": "linux_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "linux_release",
|
|
||||||
"inherits": [
|
|
||||||
"base_release",
|
|
||||||
"linux_base"
|
|
||||||
],
|
|
||||||
"displayName": "Linux (Release)",
|
|
||||||
"configurePreset": "linux_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "linux_ci",
|
|
||||||
"inherits": [
|
|
||||||
"base_release",
|
|
||||||
"linux_base"
|
|
||||||
],
|
|
||||||
"displayName": "Linux (CI)",
|
|
||||||
"configurePreset": "linux_ci"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"workflowPresets": [
|
|
||||||
{
|
|
||||||
"name": "linux_debug",
|
|
||||||
"displayName": "Linux (Debug)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "linux_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "linux_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "test",
|
|
||||||
"name": "linux_debug"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "linux",
|
|
||||||
"displayName": "Linux (Release)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "linux_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "linux_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "test",
|
|
||||||
"name": "linux_release"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "linux_ci",
|
|
||||||
"displayName": "Linux (CI)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "linux_ci"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "linux_ci"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "test",
|
|
||||||
"name": "linux_ci"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,272 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json",
|
|
||||||
"version": 8,
|
|
||||||
"include": [
|
|
||||||
"commonPresets.json"
|
|
||||||
],
|
|
||||||
"configurePresets": [
|
|
||||||
{
|
|
||||||
"name": "macos_base",
|
|
||||||
"hidden": true,
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Darwin"
|
|
||||||
},
|
|
||||||
"generator": "Ninja"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_universal_base",
|
|
||||||
"hidden": true,
|
|
||||||
"inherits": [
|
|
||||||
"macos_base"
|
|
||||||
],
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_OSX_ARCHITECTURES": "x86_64;arm64",
|
|
||||||
"Launcher_BUILD_ARTIFACT": "macOS-Qt6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_debug",
|
|
||||||
"inherits": [
|
|
||||||
"base_debug",
|
|
||||||
"macos_base"
|
|
||||||
],
|
|
||||||
"displayName": "macOS (Debug)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_release",
|
|
||||||
"inherits": [
|
|
||||||
"base_release",
|
|
||||||
"macos_base"
|
|
||||||
],
|
|
||||||
"displayName": "macOS (Release)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_universal_debug",
|
|
||||||
"inherits": [
|
|
||||||
"base_debug",
|
|
||||||
"macos_universal_base"
|
|
||||||
],
|
|
||||||
"displayName": "macOS (Universal Binary, Debug)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_universal_release",
|
|
||||||
"inherits": [
|
|
||||||
"base_release",
|
|
||||||
"macos_universal_base"
|
|
||||||
],
|
|
||||||
"displayName": "macOS (Universal Binary, Release)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_ci",
|
|
||||||
"inherits": [
|
|
||||||
"base_ci",
|
|
||||||
"macos_universal_base"
|
|
||||||
],
|
|
||||||
"displayName": "macOS (CI)",
|
|
||||||
"cacheVariables": {
|
|
||||||
"Launcher_BUILD_ARTIFACT": "macOS-Qt6"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"buildPresets": [
|
|
||||||
{
|
|
||||||
"name": "macos_base",
|
|
||||||
"hidden": true,
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Darwin"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_debug",
|
|
||||||
"inherits": [
|
|
||||||
"macos_base"
|
|
||||||
],
|
|
||||||
"displayName": "macOS (Debug)",
|
|
||||||
"configurePreset": "macos_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_release",
|
|
||||||
"inherits": [
|
|
||||||
"macos_base"
|
|
||||||
],
|
|
||||||
"displayName": "macOS (Release)",
|
|
||||||
"configurePreset": "macos_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_universal_debug",
|
|
||||||
"inherits": [
|
|
||||||
"macos_base"
|
|
||||||
],
|
|
||||||
"displayName": "macOS (Universal Binary, Debug)",
|
|
||||||
"configurePreset": "macos_universal_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_universal_release",
|
|
||||||
"inherits": [
|
|
||||||
"macos_base"
|
|
||||||
],
|
|
||||||
"displayName": "macOS (Universal Binary, Release)",
|
|
||||||
"configurePreset": "macos_universal_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_ci",
|
|
||||||
"inherits": [
|
|
||||||
"macos_base"
|
|
||||||
],
|
|
||||||
"displayName": "macOS (CI)",
|
|
||||||
"configurePreset": "macos_ci"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"testPresets": [
|
|
||||||
{
|
|
||||||
"name": "macos_base",
|
|
||||||
"hidden": true,
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Darwin"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_debug",
|
|
||||||
"inherits": [
|
|
||||||
"base_debug",
|
|
||||||
"macos_base"
|
|
||||||
],
|
|
||||||
"displayName": "MacOS (Debug)",
|
|
||||||
"configurePreset": "macos_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_release",
|
|
||||||
"inherits": [
|
|
||||||
"base_release",
|
|
||||||
"macos_base"
|
|
||||||
],
|
|
||||||
"displayName": "macOS (Release)",
|
|
||||||
"configurePreset": "macos_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_universal_debug",
|
|
||||||
"inherits": [
|
|
||||||
"base_debug",
|
|
||||||
"macos_base"
|
|
||||||
],
|
|
||||||
"displayName": "MacOS (Universal Binary, Debug)",
|
|
||||||
"configurePreset": "macos_universal_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_universal_release",
|
|
||||||
"inherits": [
|
|
||||||
"base_release",
|
|
||||||
"macos_base"
|
|
||||||
],
|
|
||||||
"displayName": "macOS (Universal Binary, Release)",
|
|
||||||
"configurePreset": "macos_universal_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_ci",
|
|
||||||
"inherits": [
|
|
||||||
"base_release",
|
|
||||||
"macos_base"
|
|
||||||
],
|
|
||||||
"displayName": "macOS (CI)",
|
|
||||||
"configurePreset": "macos_ci"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"workflowPresets": [
|
|
||||||
{
|
|
||||||
"name": "macos_debug",
|
|
||||||
"displayName": "macOS (Debug)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "macos_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "macos_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "test",
|
|
||||||
"name": "macos_debug"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos",
|
|
||||||
"displayName": "macOS (Release)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "macos_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "macos_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "test",
|
|
||||||
"name": "macos_release"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_universal_debug",
|
|
||||||
"displayName": "macOS (Universal Binary, Debug)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "macos_universal_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "macos_universal_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "test",
|
|
||||||
"name": "macos_universal_debug"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_universal",
|
|
||||||
"displayName": "macOS (Universal Binary, Release)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "macos_universal_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "macos_universal_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "test",
|
|
||||||
"name": "macos_universal_release"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macos_ci",
|
|
||||||
"displayName": "macOS (CI)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "macos_ci"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "macos_ci"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "test",
|
|
||||||
"name": "macos_ci"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,311 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json",
|
|
||||||
"version": 8,
|
|
||||||
"include": [
|
|
||||||
"commonPresets.json"
|
|
||||||
],
|
|
||||||
"configurePresets": [
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_base",
|
|
||||||
"hidden": true,
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Windows"
|
|
||||||
},
|
|
||||||
"cacheVariables": {
|
|
||||||
"Launcher_BUILD_ARTIFACT": "Windows-MSVC-Qt6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_arm64_cross_base",
|
|
||||||
"hidden": true,
|
|
||||||
"inherits": [
|
|
||||||
"windows_msvc_base"
|
|
||||||
],
|
|
||||||
"architecture": "arm64",
|
|
||||||
"cacheVariables": {
|
|
||||||
"Launcher_BUILD_ARTIFACT": "Windows-MSVC-arm64-Qt6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_debug",
|
|
||||||
"inherits": [
|
|
||||||
"base_debug",
|
|
||||||
"windows_msvc_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MSVC (Debug)",
|
|
||||||
"generator": "Ninja"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_release",
|
|
||||||
"inherits": [
|
|
||||||
"base_release",
|
|
||||||
"windows_msvc_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MSVC (Release)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_arm64_cross_debug",
|
|
||||||
"inherits": [
|
|
||||||
"base_debug",
|
|
||||||
"windows_msvc_arm64_cross_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MSVC (ARM64 cross, Debug)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_arm64_cross_release",
|
|
||||||
"inherits": [
|
|
||||||
"base_release",
|
|
||||||
"windows_msvc_arm64_cross_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MSVC (ARM64 cross, Release)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_ci",
|
|
||||||
"inherits": [
|
|
||||||
"base_ci",
|
|
||||||
"windows_msvc_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MSVC (CI)",
|
|
||||||
"cacheVariables": {
|
|
||||||
"Launcher_BUILD_ARTIFACT": "Windows-MSVC-Qt6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_arm64_cross_ci",
|
|
||||||
"inherits": [
|
|
||||||
"base_ci",
|
|
||||||
"windows_msvc_arm64_cross_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MSVC (ARM64 cross, CI)",
|
|
||||||
"cacheVariables": {
|
|
||||||
"Launcher_BUILD_ARTIFACT": "Windows-MSVC-arm64-Qt6"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"buildPresets": [
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_base",
|
|
||||||
"hidden": true,
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Windows"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_debug",
|
|
||||||
"inherits": [
|
|
||||||
"windows_msvc_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MSVC (Debug)",
|
|
||||||
"configurePreset": "windows_msvc_debug",
|
|
||||||
"configuration": "Debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_release",
|
|
||||||
"inherits": [
|
|
||||||
"windows_msvc_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MSVC (Release)",
|
|
||||||
"configurePreset": "windows_msvc_release",
|
|
||||||
"configuration": "Release",
|
|
||||||
"nativeToolOptions": [
|
|
||||||
"/p:UseMultiToolTask=true",
|
|
||||||
"/p:EnforceProcessCountAcrossBuilds=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_arm64_cross_debug",
|
|
||||||
"inherits": [
|
|
||||||
"windows_msvc_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MSVC (ARM64 cross, Debug)",
|
|
||||||
"configurePreset": "windows_msvc_arm64_cross_debug",
|
|
||||||
"configuration": "Debug",
|
|
||||||
"nativeToolOptions": [
|
|
||||||
"/p:UseMultiToolTask=true",
|
|
||||||
"/p:EnforceProcessCountAcrossBuilds=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_arm64_cross_release",
|
|
||||||
"inherits": [
|
|
||||||
"windows_msvc_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MSVC (ARM64 cross, Release)",
|
|
||||||
"configurePreset": "windows_msvc_arm64_cross_release",
|
|
||||||
"configuration": "Release",
|
|
||||||
"nativeToolOptions": [
|
|
||||||
"/p:UseMultiToolTask=true",
|
|
||||||
"/p:EnforceProcessCountAcrossBuilds=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_ci",
|
|
||||||
"inherits": [
|
|
||||||
"windows_msvc_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MSVC (CI)",
|
|
||||||
"configurePreset": "windows_msvc_ci",
|
|
||||||
"configuration": "Release",
|
|
||||||
"nativeToolOptions": [
|
|
||||||
"/p:UseMultiToolTask=true",
|
|
||||||
"/p:EnforceProcessCountAcrossBuilds=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_arm64_cross_ci",
|
|
||||||
"inherits": [
|
|
||||||
"windows_msvc_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MSVC (ARM64 cross, CI)",
|
|
||||||
"configurePreset": "windows_msvc_arm64_cross_ci",
|
|
||||||
"configuration": "Release",
|
|
||||||
"nativeToolOptions": [
|
|
||||||
"/p:UseMultiToolTask=true",
|
|
||||||
"/p:EnforceProcessCountAcrossBuilds=true"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"testPresets": [
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_base",
|
|
||||||
"hidden": true,
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Windows"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_debug",
|
|
||||||
"inherits": [
|
|
||||||
"base_debug",
|
|
||||||
"windows_msvc_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MSVC (Debug)",
|
|
||||||
"configurePreset": "windows_msvc_debug",
|
|
||||||
"configuration": "Debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_release",
|
|
||||||
"inherits": [
|
|
||||||
"base_release",
|
|
||||||
"windows_msvc_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MSVC (Release)",
|
|
||||||
"configurePreset": "windows_msvc_release",
|
|
||||||
"configuration": "Release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_ci",
|
|
||||||
"inherits": [
|
|
||||||
"base_release",
|
|
||||||
"windows_msvc_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MSVC (CI)",
|
|
||||||
"configurePreset": "windows_msvc_ci",
|
|
||||||
"configuration": "Release"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"workflowPresets": [
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_debug",
|
|
||||||
"displayName": "Windows MSVC (Debug)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "windows_msvc_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "windows_msvc_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "test",
|
|
||||||
"name": "windows_msvc_debug"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc",
|
|
||||||
"displayName": "Windows MSVC (Release)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "windows_msvc_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "windows_msvc_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "test",
|
|
||||||
"name": "windows_msvc_release"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_arm64_cross_debug",
|
|
||||||
"displayName": "Windows MSVC (ARM64 cross, Debug)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "windows_msvc_arm64_cross_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "windows_msvc_arm64_cross_debug"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_arm64_cross",
|
|
||||||
"displayName": "Windows MSVC (ARM64 cross, Release)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "windows_msvc_arm64_cross_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "windows_msvc_arm64_cross_release"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_ci",
|
|
||||||
"displayName": "Windows MSVC (CI)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "windows_msvc_ci"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "windows_msvc_ci"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "test",
|
|
||||||
"name": "windows_msvc_ci"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_msvc_arm64_cross_ci",
|
|
||||||
"displayName": "Windows MSVC (ARM64 cross, CI)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "windows_msvc_arm64_cross_ci"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "windows_msvc_arm64_cross_ci"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,183 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json",
|
|
||||||
"version": 8,
|
|
||||||
"include": [
|
|
||||||
"commonPresets.json"
|
|
||||||
],
|
|
||||||
"configurePresets": [
|
|
||||||
{
|
|
||||||
"name": "windows_mingw_base",
|
|
||||||
"hidden": true,
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Windows"
|
|
||||||
},
|
|
||||||
"generator": "Ninja",
|
|
||||||
"cacheVariables": {
|
|
||||||
"Launcher_BUILD_ARTIFACT": "Windows-MinGW-w64-Qt6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_mingw_debug",
|
|
||||||
"inherits": [
|
|
||||||
"base_debug",
|
|
||||||
"windows_mingw_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MinGW (Debug)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_mingw_release",
|
|
||||||
"inherits": [
|
|
||||||
"base_release",
|
|
||||||
"windows_mingw_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MinGW (Release)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_mingw_ci",
|
|
||||||
"inherits": [
|
|
||||||
"base_ci",
|
|
||||||
"windows_mingw_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MinGW (CI)",
|
|
||||||
"cacheVariables": {
|
|
||||||
"Launcher_BUILD_ARTIFACT": "Windows-MinGW-w64-Qt6"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"buildPresets": [
|
|
||||||
{
|
|
||||||
"name": "windows_mingw_base",
|
|
||||||
"hidden": true,
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Windows"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_mingw_debug",
|
|
||||||
"inherits": [
|
|
||||||
"windows_mingw_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MinGW (Debug)",
|
|
||||||
"configurePreset": "windows_mingw_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_mingw_release",
|
|
||||||
"inherits": [
|
|
||||||
"windows_mingw_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MinGW (Release)",
|
|
||||||
"configurePreset": "windows_mingw_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_mingw_ci",
|
|
||||||
"inherits": [
|
|
||||||
"windows_mingw_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MinGW (CI)",
|
|
||||||
"configurePreset": "windows_mingw_ci"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"testPresets": [
|
|
||||||
{
|
|
||||||
"name": "windows_mingw_base",
|
|
||||||
"hidden": true,
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Windows"
|
|
||||||
},
|
|
||||||
"filter": {
|
|
||||||
"exclude": {
|
|
||||||
"name": "^example64|example$"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_mingw_debug",
|
|
||||||
"inherits": [
|
|
||||||
"base_debug",
|
|
||||||
"windows_mingw_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MinGW (Debug)",
|
|
||||||
"configurePreset": "windows_mingw_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_mingw_release",
|
|
||||||
"inherits": [
|
|
||||||
"base_release",
|
|
||||||
"windows_mingw_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MinGW (Release)",
|
|
||||||
"configurePreset": "windows_mingw_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_mingw_ci",
|
|
||||||
"inherits": [
|
|
||||||
"base_release",
|
|
||||||
"windows_mingw_base"
|
|
||||||
],
|
|
||||||
"displayName": "Windows MinGW (CI)",
|
|
||||||
"configurePreset": "windows_mingw_ci"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"workflowPresets": [
|
|
||||||
{
|
|
||||||
"name": "windows_mingw_debug",
|
|
||||||
"displayName": "Windows MinGW (Debug)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "windows_mingw_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "windows_mingw_debug"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "test",
|
|
||||||
"name": "windows_mingw_debug"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_mingw",
|
|
||||||
"displayName": "Windows MinGW (Release)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "windows_mingw_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "windows_mingw_release"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "test",
|
|
||||||
"name": "windows_mingw_release"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows_mingw_ci",
|
|
||||||
"displayName": "Windows MinGW (CI)",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"type": "configure",
|
|
||||||
"name": "windows_mingw_ci"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "build",
|
|
||||||
"name": "windows_mingw_ci"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "test",
|
|
||||||
"name": "windows_mingw_ci"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
18
default.nix
18
default.nix
@ -1,4 +1,14 @@
|
|||||||
(import (fetchTarball {
|
(
|
||||||
url = "https://github.com/edolstra/flake-compat/archive/ff81ac966bb2cae68946d5ed5fc4994f96d0ffec.tar.gz";
|
import
|
||||||
sha256 = "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=";
|
(
|
||||||
}) { src = ./.; }).defaultNix
|
let
|
||||||
|
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
|
||||||
|
in
|
||||||
|
fetchTarball {
|
||||||
|
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
|
||||||
|
sha256 = lock.nodes.flake-compat.locked.narHash;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
{src = ./.;}
|
||||||
|
)
|
||||||
|
.defaultNix
|
||||||
|
174
flake.lock
generated
174
flake.lock
generated
@ -1,13 +1,86 @@
|
|||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1696426674,
|
||||||
|
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-parts": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1698882062,
|
||||||
|
"narHash": "sha256-HkhafUayIqxXyHH1X8d9RDl1M2CkFgZLjKD3MzabiEo=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"rev": "8c9fa2545007b49a5db5f650ae91f227672c3877",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1685518550,
|
||||||
|
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gitignore": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"pre-commit-hooks",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1660459072,
|
||||||
|
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"libnbtplusplus": {
|
"libnbtplusplus": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1744811532,
|
"lastModified": 1690036783,
|
||||||
"narHash": "sha256-qhmjaRkt+O7A+gu6HjUkl7QzOEb4r8y8vWZMG2R/C6o=",
|
"narHash": "sha256-A5kTgICnx+Qdq3Fir/bKTfdTt/T1NQP2SC+nhN1ENug=",
|
||||||
"owner": "PrismLauncher",
|
"owner": "PrismLauncher",
|
||||||
"repo": "libnbtplusplus",
|
"repo": "libnbtplusplus",
|
||||||
"rev": "531449ba1c930c98e0bcf5d332b237a8566f9d78",
|
"rev": "a5e8fd52b8bf4ab5d5bcc042b2a247867589985f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -16,43 +89,106 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nix-filter": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1745526057,
|
"lastModified": 1694857738,
|
||||||
"narHash": "sha256-ITSpPDwvLBZBnPRS2bUcHY3gZSwis/uTe255QgMtTLA=",
|
"narHash": "sha256-bxxNyLHjhu0N8T3REINXQ2ZkJco0ABFPn6PIe2QUfqo=",
|
||||||
"owner": "NixOS",
|
"owner": "numtide",
|
||||||
"repo": "nixpkgs",
|
"repo": "nix-filter",
|
||||||
"rev": "f771eb401a46846c1aebd20552521b233dd7e18b",
|
"rev": "41fd48e00c22b4ced525af521ead8792402de0ea",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "nix-filter",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1699094435,
|
||||||
|
"narHash": "sha256-YLZ5/KKZ1PyLrm2MO8UxRe4H3M0/oaYqNhSlq6FDeeA=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "9d5d25bbfe8c0297ebe85324addcb5020ed1a454",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-lib": {
|
||||||
|
"locked": {
|
||||||
|
"dir": "lib",
|
||||||
|
"lastModified": 1698611440,
|
||||||
|
"narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "0cbe9f69c234a7700596e943bfae7ef27a31b735",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"dir": "lib",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-unstable",
|
"ref": "nixos-unstable",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"qt-qrcodegenerator": {
|
"pre-commit-hooks": {
|
||||||
"flake": false,
|
"inputs": {
|
||||||
|
"flake-compat": [
|
||||||
|
"flake-compat"
|
||||||
|
],
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"gitignore": "gitignore",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"nixpkgs-stable": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1737616857,
|
"lastModified": 1698852633,
|
||||||
"narHash": "sha256-6SugPt0lp1Gz7nV23FLmsmpfzgFItkSw7jpGftsDPWc=",
|
"narHash": "sha256-Hsc/cCHud8ZXLvmm8pxrXpuaPEeNaaUttaCvtdX/Wug=",
|
||||||
"owner": "nayuki",
|
"owner": "cachix",
|
||||||
"repo": "QR-Code-generator",
|
"repo": "pre-commit-hooks.nix",
|
||||||
"rev": "2c9044de6b049ca25cb3cd1649ed7e27aa055138",
|
"rev": "dec10399e5b56aa95fcd530e0338be72ad6462a0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nayuki",
|
"owner": "cachix",
|
||||||
"repo": "QR-Code-generator",
|
"repo": "pre-commit-hooks.nix",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"flake-parts": "flake-parts",
|
||||||
"libnbtplusplus": "libnbtplusplus",
|
"libnbtplusplus": "libnbtplusplus",
|
||||||
|
"nix-filter": "nix-filter",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"qt-qrcodegenerator": "qt-qrcodegenerator"
|
"pre-commit-hooks": "pre-commit-hooks"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
243
flake.nix
243
flake.nix
@ -1,227 +1,44 @@
|
|||||||
{
|
{
|
||||||
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://prismlauncher.cachix.org" ];
|
|
||||||
extra-trusted-public-keys = [
|
|
||||||
"prismlauncher.cachix.org-1:9/n/FGyABA2jLUVfY+DEp4hKds/rwO+SCOtbOkDzd+c="
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
||||||
|
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||||
|
nix-filter.url = "github:numtide/nix-filter";
|
||||||
|
pre-commit-hooks = {
|
||||||
|
url = "github:cachix/pre-commit-hooks.nix";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
inputs.nixpkgs-stable.follows = "nixpkgs";
|
||||||
|
inputs.flake-compat.follows = "flake-compat";
|
||||||
|
};
|
||||||
|
flake-compat = {
|
||||||
|
url = "github:edolstra/flake-compat";
|
||||||
|
flake = false;
|
||||||
|
};
|
||||||
libnbtplusplus = {
|
libnbtplusplus = {
|
||||||
url = "github:PrismLauncher/libnbtplusplus";
|
url = "github:PrismLauncher/libnbtplusplus";
|
||||||
flake = false;
|
flake = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
qt-qrcodegenerator = {
|
|
||||||
url = "github:nayuki/QR-Code-generator";
|
|
||||||
flake = false;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs =
|
outputs = {
|
||||||
{
|
flake-parts,
|
||||||
self,
|
pre-commit-hooks,
|
||||||
nixpkgs,
|
...
|
||||||
libnbtplusplus,
|
} @ inputs:
|
||||||
qt-qrcodegenerator,
|
flake-parts.lib.mkFlake {inherit inputs;} {
|
||||||
}:
|
imports = [
|
||||||
|
pre-commit-hooks.flakeModule
|
||||||
|
|
||||||
let
|
./nix/dev.nix
|
||||||
inherit (nixpkgs) lib;
|
./nix/distribution.nix
|
||||||
|
];
|
||||||
|
|
||||||
# While we only officially support aarch and x86_64 on Linux and MacOS,
|
systems = [
|
||||||
# we expose a reasonable amount of other systems for users who want to
|
"x86_64-linux"
|
||||||
# build for most exotic platforms
|
"aarch64-linux"
|
||||||
systems = lib.systems.flakeExposed;
|
"x86_64-darwin"
|
||||||
|
"aarch64-darwin"
|
||||||
forAllSystems = lib.genAttrs systems;
|
];
|
||||||
nixpkgsFor = forAllSystems (system: nixpkgs.legacyPackages.${system});
|
|
||||||
in
|
|
||||||
|
|
||||||
{
|
|
||||||
checks = forAllSystems (
|
|
||||||
system:
|
|
||||||
|
|
||||||
let
|
|
||||||
pkgs = nixpkgsFor.${system};
|
|
||||||
llvm = pkgs.llvmPackages_19;
|
|
||||||
in
|
|
||||||
|
|
||||||
{
|
|
||||||
formatting =
|
|
||||||
pkgs.runCommand "check-formatting"
|
|
||||||
{
|
|
||||||
nativeBuildInputs = with pkgs; [
|
|
||||||
deadnix
|
|
||||||
llvm.clang-tools
|
|
||||||
markdownlint-cli
|
|
||||||
nixfmt-rfc-style
|
|
||||||
statix
|
|
||||||
];
|
|
||||||
}
|
|
||||||
''
|
|
||||||
cd ${self}
|
|
||||||
|
|
||||||
echo "Running clang-format...."
|
|
||||||
clang-format --dry-run --style='file' --Werror */**.{c,cc,cpp,h,hh,hpp}
|
|
||||||
|
|
||||||
echo "Running deadnix..."
|
|
||||||
deadnix --fail
|
|
||||||
|
|
||||||
echo "Running markdownlint..."
|
|
||||||
markdownlint --dot .
|
|
||||||
|
|
||||||
echo "Running nixfmt..."
|
|
||||||
find -type f -name '*.nix' -exec nixfmt --check {} +
|
|
||||||
|
|
||||||
echo "Running statix"
|
|
||||||
statix check .
|
|
||||||
|
|
||||||
touch $out
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
devShells = forAllSystems (
|
|
||||||
system:
|
|
||||||
|
|
||||||
let
|
|
||||||
pkgs = nixpkgsFor.${system};
|
|
||||||
llvm = pkgs.llvmPackages_19;
|
|
||||||
|
|
||||||
packages' = self.packages.${system};
|
|
||||||
|
|
||||||
welcomeMessage = ''
|
|
||||||
Welcome to the Prism Launcher repository! 🌈
|
|
||||||
|
|
||||||
We just set some things up for you. To get building, you can run:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cd "$cmakeBuildDir"
|
|
||||||
$ ninjaBuildPhase
|
|
||||||
$ ninjaInstallPhase
|
|
||||||
```
|
|
||||||
|
|
||||||
Feel free to ask any questions in our Discord server or Matrix space:
|
|
||||||
- https://prismlauncher.org/discord
|
|
||||||
- https://matrix.to/#/#prismlauncher:matrix.org
|
|
||||||
|
|
||||||
And thanks for helping out :)
|
|
||||||
'';
|
|
||||||
|
|
||||||
# Re-use our package wrapper to wrap our development environment
|
|
||||||
qt-wrapper-env = packages'.prismlauncher.overrideAttrs (old: {
|
|
||||||
name = "qt-wrapper-env";
|
|
||||||
|
|
||||||
# Required to use script-based makeWrapper below
|
|
||||||
strictDeps = true;
|
|
||||||
|
|
||||||
# We don't need/want the unwrapped Prism package
|
|
||||||
paths = [ ];
|
|
||||||
|
|
||||||
nativeBuildInputs = old.nativeBuildInputs or [ ] ++ [
|
|
||||||
# Ensure the wrapper is script based so it can be sourced
|
|
||||||
pkgs.makeWrapper
|
|
||||||
];
|
|
||||||
|
|
||||||
# Inspired by https://discourse.nixos.org/t/python-qt-woes/11808/10
|
|
||||||
buildCommand = ''
|
|
||||||
makeQtWrapper ${lib.getExe pkgs.runtimeShellPackage} "$out"
|
|
||||||
sed -i '/^exec/d' "$out"
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
in
|
|
||||||
|
|
||||||
{
|
|
||||||
default = pkgs.mkShell {
|
|
||||||
name = "prism-launcher";
|
|
||||||
|
|
||||||
inputsFrom = [ packages'.prismlauncher-unwrapped ];
|
|
||||||
|
|
||||||
packages = with pkgs; [
|
|
||||||
ccache
|
|
||||||
llvm.clang-tools
|
|
||||||
];
|
|
||||||
|
|
||||||
cmakeBuildType = "Debug";
|
|
||||||
cmakeFlags = [ "-GNinja" ] ++ packages'.prismlauncher.cmakeFlags;
|
|
||||||
dontFixCmake = true;
|
|
||||||
|
|
||||||
shellHook = ''
|
|
||||||
echo "Sourcing ${qt-wrapper-env}"
|
|
||||||
source ${qt-wrapper-env}
|
|
||||||
|
|
||||||
git submodule update --init --force
|
|
||||||
|
|
||||||
if [ ! -f compile_commands.json ]; then
|
|
||||||
cmakeConfigurePhase
|
|
||||||
cd ..
|
|
||||||
ln -s "$cmakeBuildDir"/compile_commands.json compile_commands.json
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ${lib.escapeShellArg welcomeMessage}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
formatter = forAllSystems (system: nixpkgsFor.${system}.nixfmt-rfc-style);
|
|
||||||
|
|
||||||
overlays.default = final: prev: {
|
|
||||||
prismlauncher-unwrapped = prev.callPackage ./nix/unwrapped.nix {
|
|
||||||
inherit
|
|
||||||
libnbtplusplus
|
|
||||||
qt-qrcodegenerator
|
|
||||||
self
|
|
||||||
;
|
|
||||||
};
|
|
||||||
|
|
||||||
prismlauncher = final.callPackage ./nix/wrapper.nix { };
|
|
||||||
};
|
|
||||||
|
|
||||||
packages = forAllSystems (
|
|
||||||
system:
|
|
||||||
|
|
||||||
let
|
|
||||||
pkgs = nixpkgsFor.${system};
|
|
||||||
|
|
||||||
# Build a scope from our overlay
|
|
||||||
prismPackages = lib.makeScope pkgs.newScope (final: self.overlays.default final pkgs);
|
|
||||||
|
|
||||||
# Grab our packages from it and set the default
|
|
||||||
packages = {
|
|
||||||
inherit (prismPackages) prismlauncher-unwrapped prismlauncher;
|
|
||||||
default = prismPackages.prismlauncher;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
|
|
||||||
# Only output them if they're available on the current system
|
|
||||||
lib.filterAttrs (_: lib.meta.availableOn pkgs.stdenv.hostPlatform) packages
|
|
||||||
);
|
|
||||||
|
|
||||||
# We put these under legacyPackages as they are meant for CI, not end user consumption
|
|
||||||
legacyPackages = forAllSystems (
|
|
||||||
system:
|
|
||||||
|
|
||||||
let
|
|
||||||
packages' = self.packages.${system};
|
|
||||||
legacyPackages' = self.legacyPackages.${system};
|
|
||||||
in
|
|
||||||
|
|
||||||
{
|
|
||||||
prismlauncher-debug = packages'.prismlauncher.override {
|
|
||||||
prismlauncher-unwrapped = legacyPackages'.prismlauncher-unwrapped-debug;
|
|
||||||
};
|
|
||||||
|
|
||||||
prismlauncher-unwrapped-debug = packages'.prismlauncher-unwrapped.overrideAttrs {
|
|
||||||
cmakeBuildType = "Debug";
|
|
||||||
dontStrip = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "flite",
|
|
||||||
"config-opts": [
|
|
||||||
"--enable-shared",
|
|
||||||
"--with-audio=pulseaudio"
|
|
||||||
],
|
|
||||||
"no-parallel-make": true,
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/festvox/flite.git",
|
|
||||||
"tag": "v2.2",
|
|
||||||
"commit": "e9e2e37c329dbe98bfeb27a1828ef9a71fa84f88",
|
|
||||||
"x-checker-data": {
|
|
||||||
"type": "git",
|
|
||||||
"tag-pattern": "^v([\\d.]+)$"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,18 +1,22 @@
|
|||||||
{
|
{
|
||||||
"name": "libdecor",
|
"name": "libdecor",
|
||||||
"buildsystem": "meson",
|
"buildsystem": "meson",
|
||||||
"config-opts": [
|
"config-opts": [
|
||||||
"-Ddemo=false"
|
"-Ddemo=false"
|
||||||
],
|
],
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://gitlab.freedesktop.org/libdecor/libdecor.git",
|
"url": "https://gitlab.freedesktop.org/libdecor/libdecor.git",
|
||||||
"commit": "c2bd8ad6fa42c0cb17553ce77ad8a87d1f543b1f"
|
"commit": "73260393a97291c887e1074ab7f318e031be0ac6"
|
||||||
}
|
},
|
||||||
],
|
{
|
||||||
"cleanup": [
|
"type": "patch",
|
||||||
"/include",
|
"path": "patches/weird_libdecor.patch"
|
||||||
"/lib/pkgconfig"
|
}
|
||||||
]
|
],
|
||||||
|
"cleanup": [
|
||||||
|
"/include",
|
||||||
|
"/lib/pkgconfig"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
id: org.prismlauncher.PrismLauncher
|
id: org.prismlauncher.PrismLauncher
|
||||||
runtime: org.kde.Platform
|
runtime: org.kde.Platform
|
||||||
runtime-version: '6.8'
|
runtime-version: "5.15-22.08"
|
||||||
sdk: org.kde.Sdk
|
sdk: org.kde.Sdk
|
||||||
sdk-extensions:
|
sdk-extensions:
|
||||||
- org.freedesktop.Sdk.Extension.openjdk17
|
- org.freedesktop.Sdk.Extension.openjdk17
|
||||||
|
- org.freedesktop.Sdk.Extension.openjdk8
|
||||||
|
|
||||||
command: prismlauncher
|
command: prismlauncher
|
||||||
finish-args:
|
finish-args:
|
||||||
@ -19,12 +20,9 @@ finish-args:
|
|||||||
- --filesystem=xdg-download:ro
|
- --filesystem=xdg-download:ro
|
||||||
# FTBApp import
|
# FTBApp import
|
||||||
- --filesystem=~/.ftba:ro
|
- --filesystem=~/.ftba:ro
|
||||||
# Userspace visibility for manual hugepages configuration
|
|
||||||
# Required for -XX:+UseLargePages
|
cleanup:
|
||||||
- --filesystem=/sys/kernel/mm/hugepages:ro
|
- /lib/libGLU*
|
||||||
# Userspace visibility for transparent hugepages configuration
|
|
||||||
# Required for -XX:+UseTransparentHugePages
|
|
||||||
- --filesystem=/sys/kernel/mm/transparent_hugepage:ro
|
|
||||||
|
|
||||||
modules:
|
modules:
|
||||||
# Might be needed by some Controller mods (see https://github.com/isXander/Controlify/issues/31)
|
# Might be needed by some Controller mods (see https://github.com/isXander/Controlify/issues/31)
|
||||||
@ -33,39 +31,48 @@ modules:
|
|||||||
# Needed for proper Wayland support
|
# Needed for proper Wayland support
|
||||||
- libdecor.json
|
- libdecor.json
|
||||||
|
|
||||||
# Text to Speech in the game
|
|
||||||
- flite.json
|
|
||||||
|
|
||||||
- name: prismlauncher
|
- name: prismlauncher
|
||||||
buildsystem: cmake-ninja
|
buildsystem: cmake-ninja
|
||||||
builddir: true
|
builddir: true
|
||||||
config-opts:
|
config-opts:
|
||||||
- -DLauncher_BUILD_PLATFORM=flatpak
|
- -DLauncher_BUILD_PLATFORM=flatpak
|
||||||
# This allows us to manage and update Java independently of this Flatpak
|
|
||||||
- -DLauncher_ENABLE_JAVA_DOWNLOADER=ON
|
|
||||||
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||||
|
- -DLauncher_QT_VERSION_MAJOR=5
|
||||||
build-options:
|
build-options:
|
||||||
env:
|
env:
|
||||||
JAVA_HOME: /usr/lib/sdk/openjdk17/jvm/openjdk-17
|
JAVA_HOME: /usr/lib/sdk/openjdk17/jvm/openjdk-17
|
||||||
JAVA_COMPILER: /usr/lib/sdk/openjdk17/jvm/openjdk-17/bin/javac
|
JAVA_COMPILER: /usr/lib/sdk/openjdk17/jvm/openjdk-17/bin/javac
|
||||||
run-tests: true
|
|
||||||
sources:
|
sources:
|
||||||
- type: dir
|
- type: dir
|
||||||
path: ../
|
path: ../
|
||||||
|
|
||||||
|
- name: openjdk
|
||||||
|
buildsystem: simple
|
||||||
|
build-commands:
|
||||||
|
- mkdir -p /app/jdk/
|
||||||
|
- /usr/lib/sdk/openjdk17/install.sh
|
||||||
|
- mv /app/jre /app/jdk/17
|
||||||
|
- /usr/lib/sdk/openjdk8/install.sh
|
||||||
|
- mv /app/jre /app/jdk/8
|
||||||
|
cleanup:
|
||||||
|
- /jre
|
||||||
|
|
||||||
- name: glfw
|
- name: glfw
|
||||||
buildsystem: cmake-ninja
|
buildsystem: cmake-ninja
|
||||||
config-opts:
|
config-opts:
|
||||||
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||||
- -DBUILD_SHARED_LIBS:BOOL=ON
|
- -DBUILD_SHARED_LIBS:BOOL=ON
|
||||||
- -DGLFW_BUILD_WAYLAND:BOOL=ON
|
- -DGLFW_USE_WAYLAND=ON
|
||||||
- -DGLFW_BUILD_DOCS:BOOL=OFF
|
|
||||||
sources:
|
sources:
|
||||||
- type: git
|
- type: git
|
||||||
url: https://github.com/glfw/glfw.git
|
url: https://github.com/glfw/glfw.git
|
||||||
commit: 7b6aead9fb88b3623e3b3725ebb42670cbe4c579 # 3.4
|
commit: 3fa2360720eeba1964df3c0ecf4b5df8648a8e52
|
||||||
- type: patch
|
- type: patch
|
||||||
path: patches/0009-Defer-setting-cursor-position-until-the-cursor-is-lo.patch
|
path: patches/0003-Don-t-crash-on-calls-to-focus-or-icon.patch
|
||||||
|
- type: patch
|
||||||
|
path: patches/0005-Add-warning-about-being-an-unofficial-patch.patch
|
||||||
|
- type: patch
|
||||||
|
path: patches/0007-Platform-Prefer-Wayland-over-X11.patch
|
||||||
cleanup:
|
cleanup:
|
||||||
- /include
|
- /include
|
||||||
- /lib/cmake
|
- /lib/cmake
|
||||||
@ -75,8 +82,8 @@ modules:
|
|||||||
buildsystem: autotools
|
buildsystem: autotools
|
||||||
sources:
|
sources:
|
||||||
- type: archive
|
- type: archive
|
||||||
url: https://xorg.freedesktop.org/archive/individual/app/xrandr-1.5.3.tar.xz
|
url: https://xorg.freedesktop.org/archive/individual/app/xrandr-1.5.2.tar.xz
|
||||||
sha256: f8dd7566adb74147fab9964680b6bbadee87cf406a7fcff51718a5e6949b841c
|
sha256: c8bee4790d9058bacc4b6246456c58021db58a87ddda1a9d0139bf5f18f1f240
|
||||||
x-checker-data:
|
x-checker-data:
|
||||||
type: anitya
|
type: anitya
|
||||||
project-id: 14957
|
project-id: 14957
|
||||||
@ -97,9 +104,9 @@ modules:
|
|||||||
- install -Dm755 ../data/gamemoderun -t /app/bin
|
- install -Dm755 ../data/gamemoderun -t /app/bin
|
||||||
sources:
|
sources:
|
||||||
- type: archive
|
- type: archive
|
||||||
dest-filename: gamemode.tar.gz
|
archive-type: tar-gzip
|
||||||
url: https://api.github.com/repos/FeralInteractive/gamemode/tarball/1.8.2
|
url: https://api.github.com/repos/FeralInteractive/gamemode/tarball/1.7
|
||||||
sha256: 2886d4ce543c78bd2a364316d5e7fd59ef06b71de63f896b37c6d3dc97658f60
|
sha256: 57ce73ba605d1cf12f8d13725006a895182308d93eba0f69f285648449641803
|
||||||
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
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
diff --git a/src/wl_window.c b/src/wl_window.c
|
||||||
|
index 52d3b9eb..4ac4eb5d 100644
|
||||||
|
--- a/src/wl_window.c
|
||||||
|
+++ b/src/wl_window.c
|
||||||
|
@@ -2117,8 +2117,7 @@ void _glfwSetWindowTitleWayland(_GLFWwindow* window, const char* title)
|
||||||
|
void _glfwSetWindowIconWayland(_GLFWwindow* window,
|
||||||
|
int count, const GLFWimage* images)
|
||||||
|
{
|
||||||
|
- _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||||
|
- "Wayland: The platform does not support setting the window icon");
|
||||||
|
+ fprintf(stderr, "!!! Ignoring Error: Wayland: The platform does not support setting the window icon\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwGetWindowPosWayland(_GLFWwindow* window, int* xpos, int* ypos)
|
||||||
|
@@ -2361,8 +2360,7 @@ void _glfwRequestWindowAttentionWayland(_GLFWwindow* window)
|
||||||
|
|
||||||
|
void _glfwFocusWindowWayland(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
- _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||||
|
- "Wayland: The platform does not support setting the input focus");
|
||||||
|
+ fprintf(stderr, "!!! Ignoring Error: Wayland: The platform does not support setting the input focus\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwSetWindowMonitorWayland(_GLFWwindow* window,
|
@ -0,0 +1,17 @@
|
|||||||
|
diff --git a/src/init.c b/src/init.c
|
||||||
|
index 06dbb3f2..a7c6da86 100644
|
||||||
|
--- a/src/init.c
|
||||||
|
+++ b/src/init.c
|
||||||
|
@@ -449,6 +449,12 @@ GLFWAPI int glfwInit(void)
|
||||||
|
_glfw.initialized = GLFW_TRUE;
|
||||||
|
|
||||||
|
glfwDefaultWindowHints();
|
||||||
|
+
|
||||||
|
+ fprintf(stderr, "!!! Patched GLFW from https://github.com/Admicos/minecraft-wayland\n"
|
||||||
|
+ "!!! If any issues with the window, or some issues with rendering, occur, "
|
||||||
|
+ "first try with the built-in GLFW, and if that solves the issue, report there first.\n"
|
||||||
|
+ "!!! Use outside Minecraft is untested, and things might break.\n");
|
||||||
|
+
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
20
flatpak/patches/0007-Platform-Prefer-Wayland-over-X11.patch
Normal file
20
flatpak/patches/0007-Platform-Prefer-Wayland-over-X11.patch
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
diff --git a/src/platform.c b/src/platform.c
|
||||||
|
index c5966ae7..3e7442f9 100644
|
||||||
|
--- a/src/platform.c
|
||||||
|
+++ b/src/platform.c
|
||||||
|
@@ -49,12 +49,12 @@ static const struct
|
||||||
|
#if defined(_GLFW_COCOA)
|
||||||
|
{ GLFW_PLATFORM_COCOA, _glfwConnectCocoa },
|
||||||
|
#endif
|
||||||
|
-#if defined(_GLFW_X11)
|
||||||
|
- { GLFW_PLATFORM_X11, _glfwConnectX11 },
|
||||||
|
-#endif
|
||||||
|
#if defined(_GLFW_WAYLAND)
|
||||||
|
{ GLFW_PLATFORM_WAYLAND, _glfwConnectWayland },
|
||||||
|
#endif
|
||||||
|
+#if defined(_GLFW_X11)
|
||||||
|
+ { GLFW_PLATFORM_X11, _glfwConnectX11 },
|
||||||
|
+#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
GLFWbool _glfwSelectPlatform(int desiredID, _GLFWplatform* platform)
|
@ -1,59 +0,0 @@
|
|||||||
From 9997ae55a47de469ea26f8437c30b51483abda5f Mon Sep 17 00:00:00 2001
|
|
||||||
From: Dan Klishch <danilklishch@gmail.com>
|
|
||||||
Date: Sat, 30 Sep 2023 23:38:05 -0400
|
|
||||||
Subject: Defer setting cursor position until the cursor is locked
|
|
||||||
|
|
||||||
---
|
|
||||||
src/wl_platform.h | 3 +++
|
|
||||||
src/wl_window.c | 14 ++++++++++++--
|
|
||||||
2 files changed, 15 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/wl_platform.h b/src/wl_platform.h
|
|
||||||
index ca34f66e..cd1f227f 100644
|
|
||||||
--- a/src/wl_platform.h
|
|
||||||
+++ b/src/wl_platform.h
|
|
||||||
@@ -403,6 +403,9 @@ typedef struct _GLFWwindowWayland
|
|
||||||
int scaleSize;
|
|
||||||
int compositorPreferredScale;
|
|
||||||
|
|
||||||
+ double askedCursorPosX, askedCursorPosY;
|
|
||||||
+ GLFWbool didAskForSetCursorPos;
|
|
||||||
+
|
|
||||||
struct zwp_relative_pointer_v1* relativePointer;
|
|
||||||
struct zwp_locked_pointer_v1* lockedPointer;
|
|
||||||
struct zwp_confined_pointer_v1* confinedPointer;
|
|
||||||
diff --git a/src/wl_window.c b/src/wl_window.c
|
|
||||||
index 1de26558..0df16747 100644
|
|
||||||
--- a/src/wl_window.c
|
|
||||||
+++ b/src/wl_window.c
|
|
||||||
@@ -2586,8 +2586,9 @@ void _glfwGetCursorPosWayland(_GLFWwindow* window, double* xpos, double* ypos)
|
|
||||||
|
|
||||||
void _glfwSetCursorPosWayland(_GLFWwindow* window, double x, double y)
|
|
||||||
{
|
|
||||||
- _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
|
||||||
- "Wayland: The platform does not support setting the cursor position");
|
|
||||||
+ window->wl.didAskForSetCursorPos = true;
|
|
||||||
+ window->wl.askedCursorPosX = x;
|
|
||||||
+ window->wl.askedCursorPosY = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _glfwSetCursorModeWayland(_GLFWwindow* window, int mode)
|
|
||||||
@@ -2819,6 +2820,15 @@ static const struct zwp_relative_pointer_v1_listener relativePointerListener =
|
|
||||||
static void lockedPointerHandleLocked(void* userData,
|
|
||||||
struct zwp_locked_pointer_v1* lockedPointer)
|
|
||||||
{
|
|
||||||
+ _GLFWwindow* window = userData;
|
|
||||||
+
|
|
||||||
+ if (window->wl.didAskForSetCursorPos)
|
|
||||||
+ {
|
|
||||||
+ window->wl.didAskForSetCursorPos = false;
|
|
||||||
+ zwp_locked_pointer_v1_set_cursor_position_hint(window->wl.lockedPointer,
|
|
||||||
+ wl_fixed_from_double(window->wl.askedCursorPosX),
|
|
||||||
+ wl_fixed_from_double(window->wl.askedCursorPosY));
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lockedPointerHandleUnlocked(void* userData,
|
|
||||||
--
|
|
||||||
2.42.0
|
|
||||||
|
|
40
flatpak/patches/weird_libdecor.patch
Normal file
40
flatpak/patches/weird_libdecor.patch
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
diff --git a/src/libdecor.c b/src/libdecor.c
|
||||||
|
index a9c1106..1aa38b3 100644
|
||||||
|
--- a/src/libdecor.c
|
||||||
|
+++ b/src/libdecor.c
|
||||||
|
@@ -1391,22 +1391,32 @@ calculate_priority(const struct libdecor_plugin_description *plugin_description)
|
||||||
|
static bool
|
||||||
|
check_symbol_conflicts(const struct libdecor_plugin_description *plugin_description)
|
||||||
|
{
|
||||||
|
+ bool ret = true;
|
||||||
|
char * const *symbol;
|
||||||
|
+ void* main_prog = dlopen(NULL, RTLD_LAZY);
|
||||||
|
+ if (!main_prog) {
|
||||||
|
+ fprintf(stderr, "Plugin \"%s\" couldn't check conflicting symbols: \"%s\".\n",
|
||||||
|
+ plugin_description->description, dlerror());
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
|
||||||
|
symbol = plugin_description->conflicting_symbols;
|
||||||
|
while (*symbol) {
|
||||||
|
dlerror();
|
||||||
|
- dlsym (RTLD_DEFAULT, *symbol);
|
||||||
|
+ dlsym (main_prog, *symbol);
|
||||||
|
if (!dlerror()) {
|
||||||
|
fprintf(stderr, "Plugin \"%s\" uses conflicting symbol \"%s\".\n",
|
||||||
|
plugin_description->description, *symbol);
|
||||||
|
- return false;
|
||||||
|
+ ret = false;
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol++;
|
||||||
|
}
|
||||||
|
|
||||||
|
- return true;
|
||||||
|
+ dlclose(main_prog);
|
||||||
|
+ return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct plugin_loader *
|
@ -1 +1 @@
|
|||||||
Subproject commit 73f08ed2c3187f6648ca04ebef030930a6c9f0be
|
Subproject commit 45094ca570be383d06df729b6972830ec63bd3df
|
6
garnix.yaml
Normal file
6
garnix.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
builds:
|
||||||
|
exclude: []
|
||||||
|
include:
|
||||||
|
- "checks.x86_64-linux.*"
|
||||||
|
- "devShells.*.*"
|
||||||
|
- "packages.*.*"
|
File diff suppressed because it is too large
Load Diff
@ -42,13 +42,13 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFlag>
|
#include <QFlag>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QMutex>
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <BaseInstance.h>
|
#include <BaseInstance.h>
|
||||||
|
|
||||||
#include "minecraft/launch/MinecraftTarget.h"
|
#include "minecraft/launch/MinecraftServerTarget.h"
|
||||||
|
#include "ui/themes/CatPack.h"
|
||||||
|
|
||||||
class LaunchController;
|
class LaunchController;
|
||||||
class LocalPeer;
|
class LocalPeer;
|
||||||
@ -82,12 +82,6 @@ class Index;
|
|||||||
#endif
|
#endif
|
||||||
#define APPLICATION (static_cast<Application*>(QCoreApplication::instance()))
|
#define APPLICATION (static_cast<Application*>(QCoreApplication::instance()))
|
||||||
|
|
||||||
// Used for checking if is a test
|
|
||||||
#if defined(APPLICATION_DYN)
|
|
||||||
#undef APPLICATION_DYN
|
|
||||||
#endif
|
|
||||||
#define APPLICATION_DYN (dynamic_cast<Application*>(QCoreApplication::instance()))
|
|
||||||
|
|
||||||
class Application : public QApplication {
|
class Application : public QApplication {
|
||||||
// friends for the purpose of limiting access to deprecated stuff
|
// friends for the purpose of limiting access to deprecated stuff
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -112,7 +106,7 @@ class Application : public QApplication {
|
|||||||
|
|
||||||
std::shared_ptr<SettingsObject> settings() const { return m_settings; }
|
std::shared_ptr<SettingsObject> settings() const { return m_settings; }
|
||||||
|
|
||||||
qint64 timeSinceStart() const { return m_startTime.msecsTo(QDateTime::currentDateTime()); }
|
qint64 timeSinceStart() const { return startTime.msecsTo(QDateTime::currentDateTime()); }
|
||||||
|
|
||||||
QIcon getThemedIcon(const QString& name);
|
QIcon getThemedIcon(const QString& name);
|
||||||
|
|
||||||
@ -168,9 +162,6 @@ class Application : public QApplication {
|
|||||||
/// the data path the application is using
|
/// the data path the application is using
|
||||||
const QString& dataRoot() { return m_dataPath; }
|
const QString& dataRoot() { return m_dataPath; }
|
||||||
|
|
||||||
/// the java installed path the application is using
|
|
||||||
const QString javaPath();
|
|
||||||
|
|
||||||
bool isPortable() { return m_portable; }
|
bool isPortable() { return m_portable; }
|
||||||
|
|
||||||
const Capabilities capabilities() { return m_capabilities; }
|
const Capabilities capabilities() { return m_capabilities; }
|
||||||
@ -189,6 +180,8 @@ class Application : public QApplication {
|
|||||||
|
|
||||||
void ShowGlobalSettings(class QWidget* parent, QString open_page = QString());
|
void ShowGlobalSettings(class QWidget* parent, QString open_page = QString());
|
||||||
|
|
||||||
|
int suitableMaxMem();
|
||||||
|
|
||||||
bool updaterEnabled();
|
bool updaterEnabled();
|
||||||
QString updaterBinaryName();
|
QString updaterBinaryName();
|
||||||
|
|
||||||
@ -200,8 +193,6 @@ class Application : public QApplication {
|
|||||||
void globalSettingsClosed();
|
void globalSettingsClosed();
|
||||||
int currentCatChanged(int index);
|
int currentCatChanged(int index);
|
||||||
|
|
||||||
void oauthReplyRecieved(QVariantMap);
|
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
void clickedOnDock();
|
void clickedOnDock();
|
||||||
#endif
|
#endif
|
||||||
@ -210,9 +201,8 @@ class Application : public QApplication {
|
|||||||
bool launch(InstancePtr instance,
|
bool launch(InstancePtr instance,
|
||||||
bool online = true,
|
bool online = true,
|
||||||
bool demo = false,
|
bool demo = false,
|
||||||
MinecraftTarget::Ptr targetToJoin = nullptr,
|
MinecraftServerTargetPtr serverToJoin = nullptr,
|
||||||
MinecraftAccountPtr accountToUse = nullptr,
|
MinecraftAccountPtr accountToUse = nullptr);
|
||||||
const QString& offlineName = QString());
|
|
||||||
bool kill(InstancePtr instance);
|
bool kill(InstancePtr instance);
|
||||||
void closeCurrentWindow();
|
void closeCurrentWindow();
|
||||||
|
|
||||||
@ -237,7 +227,7 @@ class Application : public QApplication {
|
|||||||
bool shouldExitNow() const;
|
bool shouldExitNow() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QDateTime m_startTime;
|
QDateTime startTime;
|
||||||
|
|
||||||
shared_qobject_ptr<QNetworkAccessManager> m_network;
|
shared_qobject_ptr<QNetworkAccessManager> m_network;
|
||||||
|
|
||||||
@ -280,7 +270,6 @@ class Application : public QApplication {
|
|||||||
shared_qobject_ptr<LaunchController> controller;
|
shared_qobject_ptr<LaunchController> controller;
|
||||||
};
|
};
|
||||||
std::map<QString, InstanceXtras> m_instanceExtras;
|
std::map<QString, InstanceXtras> m_instanceExtras;
|
||||||
mutable QMutex m_instanceExtrasMutex;
|
|
||||||
|
|
||||||
// main state variables
|
// main state variables
|
||||||
size_t m_openWindows = 0;
|
size_t m_openWindows = 0;
|
||||||
@ -300,21 +289,9 @@ class Application : public QApplication {
|
|||||||
QString m_detectedOpenALPath;
|
QString m_detectedOpenALPath;
|
||||||
QString m_instanceIdToLaunch;
|
QString m_instanceIdToLaunch;
|
||||||
QString m_serverToJoin;
|
QString m_serverToJoin;
|
||||||
QString m_worldToJoin;
|
|
||||||
QString m_profileToUse;
|
QString m_profileToUse;
|
||||||
bool m_offline = false;
|
|
||||||
QString m_offlineName;
|
|
||||||
bool m_liveCheck = false;
|
bool m_liveCheck = false;
|
||||||
QList<QUrl> m_urlsToImport;
|
QList<QUrl> m_urlsToImport;
|
||||||
QString m_instanceIdToShowWindowOf;
|
QString m_instanceIdToShowWindowOf;
|
||||||
std::unique_ptr<QFile> logFile;
|
std::unique_ptr<QFile> logFile;
|
||||||
|
|
||||||
public:
|
|
||||||
void addQSavePath(QString);
|
|
||||||
void removeQSavePath(QString);
|
|
||||||
bool checkQSavePath(QString);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QHash<QString, int> m_qsaveResources;
|
|
||||||
mutable QMutex m_qsaveResourcesMutex;
|
|
||||||
};
|
};
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
|
||||||
#include "BaseInstaller.h"
|
#include "BaseInstaller.h"
|
||||||
#include "FileSystem.h"
|
|
||||||
#include "minecraft/MinecraftInstance.h"
|
#include "minecraft/MinecraftInstance.h"
|
||||||
|
|
||||||
BaseInstaller::BaseInstaller() {}
|
BaseInstaller::BaseInstaller() {}
|
||||||
@ -43,7 +42,7 @@ bool BaseInstaller::add(MinecraftInstance* to)
|
|||||||
|
|
||||||
bool BaseInstaller::remove(MinecraftInstance* from)
|
bool BaseInstaller::remove(MinecraftInstance* from)
|
||||||
{
|
{
|
||||||
return FS::deletePath(filename(from->instanceRoot()));
|
return QFile::remove(filename(from->instanceRoot()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BaseInstaller::filename(const QString& root) const
|
QString BaseInstaller::filename(const QString& root) const
|
||||||
|
@ -29,7 +29,7 @@ class BaseVersion;
|
|||||||
class BaseInstaller {
|
class BaseInstaller {
|
||||||
public:
|
public:
|
||||||
BaseInstaller();
|
BaseInstaller();
|
||||||
virtual ~BaseInstaller() {};
|
virtual ~BaseInstaller(){};
|
||||||
bool isApplied(MinecraftInstance* on);
|
bool isApplied(MinecraftInstance* on);
|
||||||
|
|
||||||
virtual bool add(MinecraftInstance* to);
|
virtual bool add(MinecraftInstance* to);
|
||||||
|
@ -42,8 +42,8 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include "Application.h"
|
|
||||||
#include "settings/INISettingsObject.h"
|
#include "settings/INISettingsObject.h"
|
||||||
#include "settings/OverrideSetting.h"
|
#include "settings/OverrideSetting.h"
|
||||||
#include "settings/Setting.h"
|
#include "settings/Setting.h"
|
||||||
@ -64,8 +64,6 @@ 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", "[]");
|
||||||
@ -174,12 +172,6 @@ void BaseInstance::copyManagedPack(BaseInstance& other)
|
|||||||
m_settings->set("ManagedPackName", other.getManagedPackName());
|
m_settings->set("ManagedPackName", other.getManagedPackName());
|
||||||
m_settings->set("ManagedPackVersionID", other.getManagedPackVersionID());
|
m_settings->set("ManagedPackVersionID", other.getManagedPackVersionID());
|
||||||
m_settings->set("ManagedPackVersionName", other.getManagedPackVersionName());
|
m_settings->set("ManagedPackVersionName", other.getManagedPackVersionName());
|
||||||
|
|
||||||
if (APPLICATION->settings()->get("AutomaticJavaSwitch").toBool() && m_settings->get("AutomaticJava").toBool() &&
|
|
||||||
m_settings->get("OverrideJavaLocation").toBool()) {
|
|
||||||
m_settings->set("OverrideJavaLocation", false);
|
|
||||||
m_settings->set("JavaPath", "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int BaseInstance::getConsoleMaxLines() const
|
int BaseInstance::getConsoleMaxLines() const
|
||||||
@ -275,18 +267,13 @@ void BaseInstance::setRunning(bool running)
|
|||||||
|
|
||||||
m_isRunning = running;
|
m_isRunning = running;
|
||||||
|
|
||||||
emit runningStatusChanged(running);
|
if (!m_settings->get("RecordGameTime").toBool()) {
|
||||||
}
|
emit runningStatusChanged(running);
|
||||||
|
|
||||||
void BaseInstance::setMinecraftRunning(bool running)
|
|
||||||
{
|
|
||||||
if (!settings()->get("RecordGameTime").toBool()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (running) {
|
if (running) {
|
||||||
m_timeStarted = QDateTime::currentDateTime();
|
m_timeStarted = QDateTime::currentDateTime();
|
||||||
setLastLaunch(m_timeStarted.toMSecsSinceEpoch());
|
|
||||||
} else {
|
} else {
|
||||||
QDateTime timeEnded = QDateTime::currentDateTime();
|
QDateTime timeEnded = QDateTime::currentDateTime();
|
||||||
|
|
||||||
@ -296,6 +283,8 @@ void BaseInstance::setMinecraftRunning(bool running)
|
|||||||
|
|
||||||
emit propertiesChanged(this);
|
emit propertiesChanged(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit runningStatusChanged(running);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t BaseInstance::totalTimePlayed() const
|
int64_t BaseInstance::totalTimePlayed() const
|
||||||
@ -392,12 +381,6 @@ void BaseInstance::setName(QString val)
|
|||||||
emit propertiesChanged(this);
|
emit propertiesChanged(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseInstance::syncInstanceDirName(const QString& newRoot) const
|
|
||||||
{
|
|
||||||
auto oldRoot = instanceRoot();
|
|
||||||
return oldRoot == newRoot || QFile::rename(oldRoot, newRoot);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString BaseInstance::name() const
|
QString BaseInstance::name() const
|
||||||
{
|
{
|
||||||
return m_settings->get("name").toString();
|
return m_settings->get("name").toString();
|
||||||
@ -423,8 +406,3 @@ void BaseInstance::updateRuntimeContext()
|
|||||||
{
|
{
|
||||||
// NOOP
|
// NOOP
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseInstance::isLegacy()
|
|
||||||
{
|
|
||||||
return traits().contains("legacyLaunch") || traits().contains("alphaLaunch");
|
|
||||||
}
|
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
#include "net/Mode.h"
|
#include "net/Mode.h"
|
||||||
|
|
||||||
#include "RuntimeContext.h"
|
#include "RuntimeContext.h"
|
||||||
#include "minecraft/launch/MinecraftTarget.h"
|
#include "minecraft/launch/MinecraftServerTarget.h"
|
||||||
|
|
||||||
class QDir;
|
class QDir;
|
||||||
class Task;
|
class Task;
|
||||||
@ -104,7 +104,6 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
/// be unique.
|
/// be unique.
|
||||||
virtual QString id() const;
|
virtual QString id() const;
|
||||||
|
|
||||||
void setMinecraftRunning(bool running);
|
|
||||||
void setRunning(bool running);
|
void setRunning(bool running);
|
||||||
bool isRunning() const;
|
bool isRunning() const;
|
||||||
int64_t totalTimePlayed() const;
|
int64_t totalTimePlayed() const;
|
||||||
@ -126,9 +125,6 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
QString name() const;
|
QString name() const;
|
||||||
void setName(QString val);
|
void setName(QString val);
|
||||||
|
|
||||||
/// Sync name and rename instance dir accordingly; returns true if successful
|
|
||||||
bool syncInstanceDirName(const QString& newRoot) const;
|
|
||||||
|
|
||||||
/// Value used for instance window titles
|
/// Value used for instance window titles
|
||||||
QString windowTitle() const;
|
QString windowTitle() const;
|
||||||
|
|
||||||
@ -151,6 +147,9 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
void setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version);
|
void setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version);
|
||||||
void copyManagedPack(BaseInstance& other);
|
void copyManagedPack(BaseInstance& other);
|
||||||
|
|
||||||
|
/// guess log level from a line of game log
|
||||||
|
virtual MessageLevel::Enum guessLevel([[maybe_unused]] const QString& line, MessageLevel::Enum level) { return level; }
|
||||||
|
|
||||||
virtual QStringList extraArguments();
|
virtual QStringList extraArguments();
|
||||||
|
|
||||||
/// Traits. Normally inside the version, depends on instance implementation.
|
/// Traits. Normally inside the version, depends on instance implementation.
|
||||||
@ -181,10 +180,10 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
virtual void loadSpecificSettings() = 0;
|
virtual void loadSpecificSettings() = 0;
|
||||||
|
|
||||||
/// returns a valid update task
|
/// returns a valid update task
|
||||||
virtual QList<Task::Ptr> createUpdateTask() = 0;
|
virtual Task::Ptr createUpdateTask(Net::Mode mode) = 0;
|
||||||
|
|
||||||
/// returns a valid launcher (task container)
|
/// returns a valid launcher (task container)
|
||||||
virtual shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftTarget::Ptr targetToJoin) = 0;
|
virtual shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) = 0;
|
||||||
|
|
||||||
/// returns the current launch task (if any)
|
/// returns the current launch task (if any)
|
||||||
shared_qobject_ptr<LaunchTask> getLaunchTask();
|
shared_qobject_ptr<LaunchTask> getLaunchTask();
|
||||||
@ -195,10 +194,15 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
virtual QProcessEnvironment createEnvironment() = 0;
|
virtual QProcessEnvironment createEnvironment() = 0;
|
||||||
virtual QProcessEnvironment createLaunchEnvironment() = 0;
|
virtual QProcessEnvironment createLaunchEnvironment() = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a matcher that can maps relative paths within the instance to whether they are 'log files'
|
||||||
|
*/
|
||||||
|
virtual IPathMatcher::Ptr getLogFileMatcher() = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Returns the root folder to use for looking up log files
|
* Returns the root folder to use for looking up log files
|
||||||
*/
|
*/
|
||||||
virtual QStringList getLogFileSearchPaths() = 0;
|
virtual QString getLogFileRoot() = 0;
|
||||||
|
|
||||||
virtual QString getStatusbarDescription() = 0;
|
virtual QString getStatusbarDescription() = 0;
|
||||||
|
|
||||||
@ -210,7 +214,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
|
|
||||||
virtual QString typeName() const = 0;
|
virtual QString typeName() const = 0;
|
||||||
|
|
||||||
virtual void updateRuntimeContext();
|
void updateRuntimeContext();
|
||||||
RuntimeContext runtimeContext() const { return m_runtimeContext; }
|
RuntimeContext runtimeContext() const { return m_runtimeContext; }
|
||||||
|
|
||||||
bool hasVersionBroken() const { return m_hasBrokenVersion; }
|
bool hasVersionBroken() const { return m_hasBrokenVersion; }
|
||||||
@ -251,7 +255,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
/**
|
/**
|
||||||
* 'print' a verbose description of the instance into a QStringList
|
* 'print' a verbose description of the instance into a QStringList
|
||||||
*/
|
*/
|
||||||
virtual QStringList verboseDescription(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin) = 0;
|
virtual QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) = 0;
|
||||||
|
|
||||||
Status currentStatus() const;
|
Status currentStatus() const;
|
||||||
|
|
||||||
@ -264,8 +268,6 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
bool removeLinkedInstanceId(const QString& id);
|
bool removeLinkedInstanceId(const QString& id);
|
||||||
bool isLinkedToInstanceId(const QString& id) const;
|
bool isLinkedToInstanceId(const QString& id) const;
|
||||||
|
|
||||||
bool isLegacy();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void changeStatus(Status newStatus);
|
void changeStatus(Status newStatus);
|
||||||
|
|
||||||
|
@ -78,14 +78,6 @@ QVariant BaseVersionList::data(const QModelIndex& index, int role) const
|
|||||||
case TypeRole:
|
case TypeRole:
|
||||||
return version->typeString();
|
return version->typeString();
|
||||||
|
|
||||||
case JavaMajorRole: {
|
|
||||||
auto major = version->name();
|
|
||||||
if (major.startsWith("java")) {
|
|
||||||
major = "Java " + major.mid(4);
|
|
||||||
}
|
|
||||||
return major;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
@ -118,8 +110,6 @@ QHash<int, QByteArray> BaseVersionList::roleNames() const
|
|||||||
roles.insert(TypeRole, "type");
|
roles.insert(TypeRole, "type");
|
||||||
roles.insert(BranchRole, "branch");
|
roles.insert(BranchRole, "branch");
|
||||||
roles.insert(PathRole, "path");
|
roles.insert(PathRole, "path");
|
||||||
roles.insert(JavaNameRole, "javaName");
|
roles.insert(ArchitectureRole, "architecture");
|
||||||
roles.insert(CPUArchitectureRole, "architecture");
|
|
||||||
roles.insert(JavaMajorRole, "javaMajor");
|
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
@ -48,9 +48,7 @@ class BaseVersionList : public QAbstractListModel {
|
|||||||
TypeRole,
|
TypeRole,
|
||||||
BranchRole,
|
BranchRole,
|
||||||
PathRole,
|
PathRole,
|
||||||
JavaNameRole,
|
ArchitectureRole,
|
||||||
JavaMajorRole,
|
|
||||||
CPUArchitectureRole,
|
|
||||||
SortRole
|
SortRole
|
||||||
};
|
};
|
||||||
using RoleList = QList<int>;
|
using RoleList = QList<int>;
|
||||||
|
@ -21,18 +21,13 @@ set(CORE_SOURCES
|
|||||||
BaseVersion.h
|
BaseVersion.h
|
||||||
BaseInstance.h
|
BaseInstance.h
|
||||||
BaseInstance.cpp
|
BaseInstance.cpp
|
||||||
InstanceDirUpdate.h
|
|
||||||
InstanceDirUpdate.cpp
|
|
||||||
NullInstance.h
|
NullInstance.h
|
||||||
MMCZip.h
|
MMCZip.h
|
||||||
MMCZip.cpp
|
MMCZip.cpp
|
||||||
Untar.h
|
|
||||||
Untar.cpp
|
|
||||||
StringUtils.h
|
StringUtils.h
|
||||||
StringUtils.cpp
|
StringUtils.cpp
|
||||||
QVariantUtils.h
|
QVariantUtils.h
|
||||||
RuntimeContext.h
|
RuntimeContext.h
|
||||||
PSaveFile.h
|
|
||||||
|
|
||||||
# Basic instance manipulation tasks (derived from InstanceTask)
|
# Basic instance manipulation tasks (derived from InstanceTask)
|
||||||
InstanceCreationTask.h
|
InstanceCreationTask.h
|
||||||
@ -99,7 +94,7 @@ set(CORE_SOURCES
|
|||||||
MTPixmapCache.h
|
MTPixmapCache.h
|
||||||
)
|
)
|
||||||
if (UNIX AND NOT CYGWIN AND NOT APPLE)
|
if (UNIX AND NOT CYGWIN AND NOT APPLE)
|
||||||
set(CORE_SOURCES
|
set(CORE_SOURCES
|
||||||
${CORE_SOURCES}
|
${CORE_SOURCES}
|
||||||
|
|
||||||
# MangoHud
|
# MangoHud
|
||||||
@ -131,6 +126,7 @@ set(NET_SOURCES
|
|||||||
net/MetaCacheSink.h
|
net/MetaCacheSink.h
|
||||||
net/Logging.h
|
net/Logging.h
|
||||||
net/Logging.cpp
|
net/Logging.cpp
|
||||||
|
net/NetAction.h
|
||||||
net/NetJob.cpp
|
net/NetJob.cpp
|
||||||
net/NetJob.h
|
net/NetJob.h
|
||||||
net/NetUtils.h
|
net/NetUtils.h
|
||||||
@ -143,6 +139,7 @@ set(NET_SOURCES
|
|||||||
net/HeaderProxy.h
|
net/HeaderProxy.h
|
||||||
net/RawHeaderProxy.h
|
net/RawHeaderProxy.h
|
||||||
net/ApiHeaderProxy.h
|
net/ApiHeaderProxy.h
|
||||||
|
net/StaticHeaderProxy.h
|
||||||
net/ApiDownload.h
|
net/ApiDownload.h
|
||||||
net/ApiDownload.cpp
|
net/ApiDownload.cpp
|
||||||
net/ApiUpload.cpp
|
net/ApiUpload.cpp
|
||||||
@ -163,20 +160,16 @@ set(LAUNCH_SOURCES
|
|||||||
launch/steps/PreLaunchCommand.h
|
launch/steps/PreLaunchCommand.h
|
||||||
launch/steps/TextPrint.cpp
|
launch/steps/TextPrint.cpp
|
||||||
launch/steps/TextPrint.h
|
launch/steps/TextPrint.h
|
||||||
|
launch/steps/Update.cpp
|
||||||
|
launch/steps/Update.h
|
||||||
launch/steps/QuitAfterGameStop.cpp
|
launch/steps/QuitAfterGameStop.cpp
|
||||||
launch/steps/QuitAfterGameStop.h
|
launch/steps/QuitAfterGameStop.h
|
||||||
launch/steps/PrintServers.cpp
|
|
||||||
launch/steps/PrintServers.h
|
|
||||||
launch/LaunchStep.cpp
|
launch/LaunchStep.cpp
|
||||||
launch/LaunchStep.h
|
launch/LaunchStep.h
|
||||||
launch/LaunchTask.cpp
|
launch/LaunchTask.cpp
|
||||||
launch/LaunchTask.h
|
launch/LaunchTask.h
|
||||||
launch/LogModel.cpp
|
launch/LogModel.cpp
|
||||||
launch/LogModel.h
|
launch/LogModel.h
|
||||||
launch/TaskStepWrapper.cpp
|
|
||||||
launch/TaskStepWrapper.h
|
|
||||||
logs/LogParser.cpp
|
|
||||||
logs/LogParser.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Old update system
|
# Old update system
|
||||||
@ -212,27 +205,33 @@ set(ICONS_SOURCES
|
|||||||
|
|
||||||
# Support for Minecraft instances and launch
|
# Support for Minecraft instances and launch
|
||||||
set(MINECRAFT_SOURCES
|
set(MINECRAFT_SOURCES
|
||||||
|
|
||||||
# Logging
|
|
||||||
minecraft/Logging.h
|
|
||||||
minecraft/Logging.cpp
|
|
||||||
|
|
||||||
# Minecraft support
|
# Minecraft support
|
||||||
minecraft/auth/AccountData.cpp
|
minecraft/auth/AccountData.cpp
|
||||||
minecraft/auth/AccountData.h
|
minecraft/auth/AccountData.h
|
||||||
minecraft/auth/AccountList.cpp
|
minecraft/auth/AccountList.cpp
|
||||||
minecraft/auth/AccountList.h
|
minecraft/auth/AccountList.h
|
||||||
|
minecraft/auth/AccountTask.cpp
|
||||||
|
minecraft/auth/AccountTask.h
|
||||||
|
minecraft/auth/AuthRequest.cpp
|
||||||
|
minecraft/auth/AuthRequest.h
|
||||||
minecraft/auth/AuthSession.cpp
|
minecraft/auth/AuthSession.cpp
|
||||||
minecraft/auth/AuthSession.h
|
minecraft/auth/AuthSession.h
|
||||||
|
minecraft/auth/AuthStep.cpp
|
||||||
minecraft/auth/AuthStep.h
|
minecraft/auth/AuthStep.h
|
||||||
minecraft/auth/MinecraftAccount.cpp
|
minecraft/auth/MinecraftAccount.cpp
|
||||||
minecraft/auth/MinecraftAccount.h
|
minecraft/auth/MinecraftAccount.h
|
||||||
minecraft/auth/Parsers.cpp
|
minecraft/auth/Parsers.cpp
|
||||||
minecraft/auth/Parsers.h
|
minecraft/auth/Parsers.h
|
||||||
|
|
||||||
minecraft/auth/AuthFlow.cpp
|
minecraft/auth/flows/AuthFlow.cpp
|
||||||
minecraft/auth/AuthFlow.h
|
minecraft/auth/flows/AuthFlow.h
|
||||||
|
minecraft/auth/flows/MSA.cpp
|
||||||
|
minecraft/auth/flows/MSA.h
|
||||||
|
minecraft/auth/flows/Offline.cpp
|
||||||
|
minecraft/auth/flows/Offline.h
|
||||||
|
|
||||||
|
minecraft/auth/steps/OfflineStep.cpp
|
||||||
|
minecraft/auth/steps/OfflineStep.h
|
||||||
minecraft/auth/steps/EntitlementsStep.cpp
|
minecraft/auth/steps/EntitlementsStep.cpp
|
||||||
minecraft/auth/steps/EntitlementsStep.h
|
minecraft/auth/steps/EntitlementsStep.h
|
||||||
minecraft/auth/steps/GetSkinStep.cpp
|
minecraft/auth/steps/GetSkinStep.cpp
|
||||||
@ -241,8 +240,6 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/auth/steps/LauncherLoginStep.h
|
minecraft/auth/steps/LauncherLoginStep.h
|
||||||
minecraft/auth/steps/MinecraftProfileStep.cpp
|
minecraft/auth/steps/MinecraftProfileStep.cpp
|
||||||
minecraft/auth/steps/MinecraftProfileStep.h
|
minecraft/auth/steps/MinecraftProfileStep.h
|
||||||
minecraft/auth/steps/MSADeviceCodeStep.cpp
|
|
||||||
minecraft/auth/steps/MSADeviceCodeStep.h
|
|
||||||
minecraft/auth/steps/MSAStep.cpp
|
minecraft/auth/steps/MSAStep.cpp
|
||||||
minecraft/auth/steps/MSAStep.h
|
minecraft/auth/steps/MSAStep.h
|
||||||
minecraft/auth/steps/XboxAuthorizationStep.cpp
|
minecraft/auth/steps/XboxAuthorizationStep.cpp
|
||||||
@ -274,8 +271,8 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/launch/ExtractNatives.h
|
minecraft/launch/ExtractNatives.h
|
||||||
minecraft/launch/LauncherPartLaunch.cpp
|
minecraft/launch/LauncherPartLaunch.cpp
|
||||||
minecraft/launch/LauncherPartLaunch.h
|
minecraft/launch/LauncherPartLaunch.h
|
||||||
minecraft/launch/MinecraftTarget.cpp
|
minecraft/launch/MinecraftServerTarget.cpp
|
||||||
minecraft/launch/MinecraftTarget.h
|
minecraft/launch/MinecraftServerTarget.h
|
||||||
minecraft/launch/PrintInstanceInfo.cpp
|
minecraft/launch/PrintInstanceInfo.cpp
|
||||||
minecraft/launch/PrintInstanceInfo.h
|
minecraft/launch/PrintInstanceInfo.h
|
||||||
minecraft/launch/ReconstructAssets.cpp
|
minecraft/launch/ReconstructAssets.cpp
|
||||||
@ -284,8 +281,6 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/launch/ScanModFolders.h
|
minecraft/launch/ScanModFolders.h
|
||||||
minecraft/launch/VerifyJavaInstall.cpp
|
minecraft/launch/VerifyJavaInstall.cpp
|
||||||
minecraft/launch/VerifyJavaInstall.h
|
minecraft/launch/VerifyJavaInstall.h
|
||||||
minecraft/launch/AutoInstallJava.cpp
|
|
||||||
minecraft/launch/AutoInstallJava.h
|
|
||||||
|
|
||||||
minecraft/GradleSpecifier.h
|
minecraft/GradleSpecifier.h
|
||||||
minecraft/MinecraftInstance.cpp
|
minecraft/MinecraftInstance.cpp
|
||||||
@ -300,6 +295,8 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/ComponentUpdateTask.h
|
minecraft/ComponentUpdateTask.h
|
||||||
minecraft/MinecraftLoadAndCheck.h
|
minecraft/MinecraftLoadAndCheck.h
|
||||||
minecraft/MinecraftLoadAndCheck.cpp
|
minecraft/MinecraftLoadAndCheck.cpp
|
||||||
|
minecraft/MinecraftUpdate.h
|
||||||
|
minecraft/MinecraftUpdate.cpp
|
||||||
minecraft/MojangVersionFormat.cpp
|
minecraft/MojangVersionFormat.cpp
|
||||||
minecraft/MojangVersionFormat.h
|
minecraft/MojangVersionFormat.h
|
||||||
minecraft/Rule.cpp
|
minecraft/Rule.cpp
|
||||||
@ -349,12 +346,13 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/mod/TexturePackFolderModel.h
|
minecraft/mod/TexturePackFolderModel.h
|
||||||
minecraft/mod/TexturePackFolderModel.cpp
|
minecraft/mod/TexturePackFolderModel.cpp
|
||||||
minecraft/mod/ShaderPackFolderModel.h
|
minecraft/mod/ShaderPackFolderModel.h
|
||||||
minecraft/mod/tasks/ResourceFolderLoadTask.h
|
minecraft/mod/tasks/BasicFolderLoadTask.h
|
||||||
minecraft/mod/tasks/ResourceFolderLoadTask.cpp
|
minecraft/mod/tasks/ModFolderLoadTask.h
|
||||||
|
minecraft/mod/tasks/ModFolderLoadTask.cpp
|
||||||
minecraft/mod/tasks/LocalModParseTask.h
|
minecraft/mod/tasks/LocalModParseTask.h
|
||||||
minecraft/mod/tasks/LocalModParseTask.cpp
|
minecraft/mod/tasks/LocalModParseTask.cpp
|
||||||
minecraft/mod/tasks/LocalResourceUpdateTask.h
|
minecraft/mod/tasks/LocalModUpdateTask.h
|
||||||
minecraft/mod/tasks/LocalResourceUpdateTask.cpp
|
minecraft/mod/tasks/LocalModUpdateTask.cpp
|
||||||
minecraft/mod/tasks/LocalDataPackParseTask.h
|
minecraft/mod/tasks/LocalDataPackParseTask.h
|
||||||
minecraft/mod/tasks/LocalDataPackParseTask.cpp
|
minecraft/mod/tasks/LocalDataPackParseTask.cpp
|
||||||
minecraft/mod/tasks/LocalResourcePackParseTask.h
|
minecraft/mod/tasks/LocalResourcePackParseTask.h
|
||||||
@ -374,17 +372,13 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/AssetsUtils.h
|
minecraft/AssetsUtils.h
|
||||||
minecraft/AssetsUtils.cpp
|
minecraft/AssetsUtils.cpp
|
||||||
|
|
||||||
# Minecraft skins
|
# Minecraft services
|
||||||
minecraft/skins/CapeChange.cpp
|
minecraft/services/CapeChange.cpp
|
||||||
minecraft/skins/CapeChange.h
|
minecraft/services/CapeChange.h
|
||||||
minecraft/skins/SkinUpload.cpp
|
minecraft/services/SkinUpload.cpp
|
||||||
minecraft/skins/SkinUpload.h
|
minecraft/services/SkinUpload.h
|
||||||
minecraft/skins/SkinDelete.cpp
|
minecraft/services/SkinDelete.cpp
|
||||||
minecraft/skins/SkinDelete.h
|
minecraft/services/SkinDelete.h
|
||||||
minecraft/skins/SkinModel.cpp
|
|
||||||
minecraft/skins/SkinModel.h
|
|
||||||
minecraft/skins/SkinList.cpp
|
|
||||||
minecraft/skins/SkinList.h
|
|
||||||
|
|
||||||
minecraft/Agent.h)
|
minecraft/Agent.h)
|
||||||
|
|
||||||
@ -428,6 +422,8 @@ set(SETTINGS_SOURCES
|
|||||||
set(JAVA_SOURCES
|
set(JAVA_SOURCES
|
||||||
java/JavaChecker.h
|
java/JavaChecker.h
|
||||||
java/JavaChecker.cpp
|
java/JavaChecker.cpp
|
||||||
|
java/JavaCheckerJob.h
|
||||||
|
java/JavaCheckerJob.cpp
|
||||||
java/JavaInstall.h
|
java/JavaInstall.h
|
||||||
java/JavaInstall.cpp
|
java/JavaInstall.cpp
|
||||||
java/JavaInstallList.h
|
java/JavaInstallList.h
|
||||||
@ -436,20 +432,6 @@ set(JAVA_SOURCES
|
|||||||
java/JavaUtils.cpp
|
java/JavaUtils.cpp
|
||||||
java/JavaVersion.h
|
java/JavaVersion.h
|
||||||
java/JavaVersion.cpp
|
java/JavaVersion.cpp
|
||||||
|
|
||||||
java/JavaMetadata.h
|
|
||||||
java/JavaMetadata.cpp
|
|
||||||
java/download/ArchiveDownloadTask.cpp
|
|
||||||
java/download/ArchiveDownloadTask.h
|
|
||||||
java/download/ManifestDownloadTask.cpp
|
|
||||||
java/download/ManifestDownloadTask.h
|
|
||||||
java/download/SymlinkTask.cpp
|
|
||||||
java/download/SymlinkTask.h
|
|
||||||
|
|
||||||
ui/java/InstallJavaDialog.h
|
|
||||||
ui/java/InstallJavaDialog.cpp
|
|
||||||
ui/java/VersionList.h
|
|
||||||
ui/java/VersionList.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(TRANSLATIONS_SOURCES
|
set(TRANSLATIONS_SOURCES
|
||||||
@ -471,8 +453,6 @@ set(TOOLS_SOURCES
|
|||||||
tools/JVisualVM.h
|
tools/JVisualVM.h
|
||||||
tools/MCEditTool.cpp
|
tools/MCEditTool.cpp
|
||||||
tools/MCEditTool.h
|
tools/MCEditTool.h
|
||||||
tools/GenericProfiler.cpp
|
|
||||||
tools/GenericProfiler.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(META_SOURCES
|
set(META_SOURCES
|
||||||
@ -591,8 +571,8 @@ set(ATLAUNCHER_SOURCES
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(LINKEXE_SOURCES
|
set(LINKEXE_SOURCES
|
||||||
console/WindowsConsole.h
|
WindowsConsole.cpp
|
||||||
console/WindowsConsole.cpp
|
WindowsConsole.h
|
||||||
|
|
||||||
filelink/FileLink.h
|
filelink/FileLink.h
|
||||||
filelink/FileLink.cpp
|
filelink/FileLink.cpp
|
||||||
@ -612,7 +592,7 @@ set(PRISMUPDATER_SOURCES
|
|||||||
updater/prismupdater/UpdaterDialogs.cpp
|
updater/prismupdater/UpdaterDialogs.cpp
|
||||||
updater/prismupdater/GitHubRelease.h
|
updater/prismupdater/GitHubRelease.h
|
||||||
updater/prismupdater/GitHubRelease.cpp
|
updater/prismupdater/GitHubRelease.cpp
|
||||||
|
|
||||||
Json.h
|
Json.h
|
||||||
Json.cpp
|
Json.cpp
|
||||||
FileSystem.h
|
FileSystem.h
|
||||||
@ -629,7 +609,7 @@ set(PRISMUPDATER_SOURCES
|
|||||||
# Zip
|
# Zip
|
||||||
MMCZip.h
|
MMCZip.h
|
||||||
MMCZip.cpp
|
MMCZip.cpp
|
||||||
|
|
||||||
# Time
|
# Time
|
||||||
MMCTime.h
|
MMCTime.h
|
||||||
MMCTime.cpp
|
MMCTime.cpp
|
||||||
@ -644,6 +624,7 @@ set(PRISMUPDATER_SOURCES
|
|||||||
net/HttpMetaCache.h
|
net/HttpMetaCache.h
|
||||||
net/Logging.h
|
net/Logging.h
|
||||||
net/Logging.cpp
|
net/Logging.cpp
|
||||||
|
net/NetAction.h
|
||||||
net/NetRequest.cpp
|
net/NetRequest.cpp
|
||||||
net/NetRequest.h
|
net/NetRequest.h
|
||||||
net/NetJob.cpp
|
net/NetJob.cpp
|
||||||
@ -661,14 +642,6 @@ set(PRISMUPDATER_SOURCES
|
|||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
set(PRISMUPDATER_SOURCES
|
|
||||||
console/WindowsConsole.h
|
|
||||||
console/WindowsConsole.cpp
|
|
||||||
${PRISMUPDATER_SOURCES}
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
######## Logging categories ########
|
######## Logging categories ########
|
||||||
|
|
||||||
ecm_qt_declare_logging_category(CORE_SOURCES
|
ecm_qt_declare_logging_category(CORE_SOURCES
|
||||||
@ -680,22 +653,6 @@ ecm_qt_declare_logging_category(CORE_SOURCES
|
|||||||
EXPORT "${Launcher_Name}"
|
EXPORT "${Launcher_Name}"
|
||||||
)
|
)
|
||||||
|
|
||||||
ecm_qt_export_logging_category(
|
|
||||||
IDENTIFIER instanceProfileC
|
|
||||||
CATEGORY_NAME "launcher.instance.profile"
|
|
||||||
DEFAULT_SEVERITY Debug
|
|
||||||
DESCRIPTION "Profile actions"
|
|
||||||
EXPORT "${Launcher_Name}"
|
|
||||||
)
|
|
||||||
|
|
||||||
ecm_qt_export_logging_category(
|
|
||||||
IDENTIFIER instanceProfileResolveC
|
|
||||||
CATEGORY_NAME "launcher.instance.profile.resolve"
|
|
||||||
DEFAULT_SEVERITY Debug
|
|
||||||
DESCRIPTION "Profile component resolusion actions"
|
|
||||||
EXPORT "${Launcher_Name}"
|
|
||||||
)
|
|
||||||
|
|
||||||
ecm_qt_export_logging_category(
|
ecm_qt_export_logging_category(
|
||||||
IDENTIFIER taskLogC
|
IDENTIFIER taskLogC
|
||||||
CATEGORY_NAME "launcher.task"
|
CATEGORY_NAME "launcher.task"
|
||||||
@ -708,7 +665,7 @@ ecm_qt_export_logging_category(
|
|||||||
IDENTIFIER taskNetLogC
|
IDENTIFIER taskNetLogC
|
||||||
CATEGORY_NAME "launcher.task.net"
|
CATEGORY_NAME "launcher.task.net"
|
||||||
DEFAULT_SEVERITY Debug
|
DEFAULT_SEVERITY Debug
|
||||||
DESCRIPTION "Task network action"
|
DESCRIPTION "task network action"
|
||||||
EXPORT "${Launcher_Name}"
|
EXPORT "${Launcher_Name}"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -716,14 +673,14 @@ ecm_qt_export_logging_category(
|
|||||||
IDENTIFIER taskDownloadLogC
|
IDENTIFIER taskDownloadLogC
|
||||||
CATEGORY_NAME "launcher.task.net.download"
|
CATEGORY_NAME "launcher.task.net.download"
|
||||||
DEFAULT_SEVERITY Debug
|
DEFAULT_SEVERITY Debug
|
||||||
DESCRIPTION "Task network download actions"
|
DESCRIPTION "task network download actions"
|
||||||
EXPORT "${Launcher_Name}"
|
EXPORT "${Launcher_Name}"
|
||||||
)
|
)
|
||||||
ecm_qt_export_logging_category(
|
ecm_qt_export_logging_category(
|
||||||
IDENTIFIER taskUploadLogC
|
IDENTIFIER taskUploadLogC
|
||||||
CATEGORY_NAME "launcher.task.net.upload"
|
CATEGORY_NAME "launcher.task.net.upload"
|
||||||
DEFAULT_SEVERITY Debug
|
DEFAULT_SEVERITY Debug
|
||||||
DESCRIPTION "Task network upload actions"
|
DESCRIPTION "task network upload actions"
|
||||||
EXPORT "${Launcher_Name}"
|
EXPORT "${Launcher_Name}"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -793,11 +750,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
DataMigrationTask.cpp
|
DataMigrationTask.cpp
|
||||||
ApplicationMessage.h
|
ApplicationMessage.h
|
||||||
ApplicationMessage.cpp
|
ApplicationMessage.cpp
|
||||||
SysInfo.h
|
|
||||||
SysInfo.cpp
|
|
||||||
|
|
||||||
# console utils
|
|
||||||
console/Console.h
|
|
||||||
|
|
||||||
# GUI - general utilities
|
# GUI - general utilities
|
||||||
DesktopServices.h
|
DesktopServices.h
|
||||||
@ -825,8 +777,7 @@ SET(LAUNCHER_SOURCES
|
|||||||
resources/flat/flat.qrc
|
resources/flat/flat.qrc
|
||||||
resources/flat_white/flat_white.qrc
|
resources/flat_white/flat_white.qrc
|
||||||
resources/documents/documents.qrc
|
resources/documents/documents.qrc
|
||||||
resources/shaders/shaders.qrc
|
../${Launcher_Branding_LogoQRC}
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/../${Launcher_Branding_LogoQRC}"
|
|
||||||
|
|
||||||
# Icons
|
# Icons
|
||||||
icons/MMCIcon.h
|
icons/MMCIcon.h
|
||||||
@ -837,12 +788,16 @@ SET(LAUNCHER_SOURCES
|
|||||||
# GUI - windows
|
# GUI - windows
|
||||||
ui/GuiUtil.h
|
ui/GuiUtil.h
|
||||||
ui/GuiUtil.cpp
|
ui/GuiUtil.cpp
|
||||||
|
ui/ColorCache.h
|
||||||
|
ui/ColorCache.cpp
|
||||||
ui/MainWindow.h
|
ui/MainWindow.h
|
||||||
ui/MainWindow.cpp
|
ui/MainWindow.cpp
|
||||||
ui/InstanceWindow.h
|
ui/InstanceWindow.h
|
||||||
ui/InstanceWindow.cpp
|
ui/InstanceWindow.cpp
|
||||||
|
|
||||||
# FIXME: maybe find a better home for this.
|
# FIXME: maybe find a better home for this.
|
||||||
|
SkinUtils.cpp
|
||||||
|
SkinUtils.h
|
||||||
FileIgnoreProxy.cpp
|
FileIgnoreProxy.cpp
|
||||||
FileIgnoreProxy.h
|
FileIgnoreProxy.h
|
||||||
FastFileIconProvider.cpp
|
FastFileIconProvider.cpp
|
||||||
@ -860,10 +815,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/setupwizard/PasteWizardPage.h
|
ui/setupwizard/PasteWizardPage.h
|
||||||
ui/setupwizard/ThemeWizardPage.cpp
|
ui/setupwizard/ThemeWizardPage.cpp
|
||||||
ui/setupwizard/ThemeWizardPage.h
|
ui/setupwizard/ThemeWizardPage.h
|
||||||
ui/setupwizard/AutoJavaWizardPage.cpp
|
|
||||||
ui/setupwizard/AutoJavaWizardPage.h
|
|
||||||
ui/setupwizard/LoginWizardPage.cpp
|
|
||||||
ui/setupwizard/LoginWizardPage.h
|
|
||||||
|
|
||||||
# GUI - themes
|
# GUI - themes
|
||||||
ui/themes/FusionTheme.cpp
|
ui/themes/FusionTheme.cpp
|
||||||
@ -876,8 +827,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/themes/DarkTheme.h
|
ui/themes/DarkTheme.h
|
||||||
ui/themes/ITheme.cpp
|
ui/themes/ITheme.cpp
|
||||||
ui/themes/ITheme.h
|
ui/themes/ITheme.h
|
||||||
ui/themes/HintOverrideProxyStyle.cpp
|
|
||||||
ui/themes/HintOverrideProxyStyle.h
|
|
||||||
ui/themes/SystemTheme.cpp
|
ui/themes/SystemTheme.cpp
|
||||||
ui/themes/SystemTheme.h
|
ui/themes/SystemTheme.h
|
||||||
ui/themes/IconTheme.cpp
|
ui/themes/IconTheme.cpp
|
||||||
@ -924,6 +873,7 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/pages/instance/NotesPage.h
|
ui/pages/instance/NotesPage.h
|
||||||
ui/pages/instance/LogPage.cpp
|
ui/pages/instance/LogPage.cpp
|
||||||
ui/pages/instance/LogPage.h
|
ui/pages/instance/LogPage.h
|
||||||
|
ui/pages/instance/InstanceSettingsPage.cpp
|
||||||
ui/pages/instance/InstanceSettingsPage.h
|
ui/pages/instance/InstanceSettingsPage.h
|
||||||
ui/pages/instance/ScreenshotsPage.cpp
|
ui/pages/instance/ScreenshotsPage.cpp
|
||||||
ui/pages/instance/ScreenshotsPage.h
|
ui/pages/instance/ScreenshotsPage.h
|
||||||
@ -933,22 +883,21 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/pages/instance/ServersPage.h
|
ui/pages/instance/ServersPage.h
|
||||||
ui/pages/instance/WorldListPage.cpp
|
ui/pages/instance/WorldListPage.cpp
|
||||||
ui/pages/instance/WorldListPage.h
|
ui/pages/instance/WorldListPage.h
|
||||||
ui/pages/instance/McClient.cpp
|
|
||||||
ui/pages/instance/McClient.h
|
|
||||||
ui/pages/instance/McResolver.cpp
|
|
||||||
ui/pages/instance/McResolver.h
|
|
||||||
ui/pages/instance/ServerPingTask.cpp
|
|
||||||
ui/pages/instance/ServerPingTask.h
|
|
||||||
|
|
||||||
# GUI - global settings pages
|
# GUI - global settings pages
|
||||||
ui/pages/global/AccountListPage.cpp
|
ui/pages/global/AccountListPage.cpp
|
||||||
ui/pages/global/AccountListPage.h
|
ui/pages/global/AccountListPage.h
|
||||||
|
ui/pages/global/CustomCommandsPage.cpp
|
||||||
|
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
|
||||||
ui/pages/global/JavaPage.h
|
ui/pages/global/JavaPage.h
|
||||||
ui/pages/global/LanguagePage.cpp
|
ui/pages/global/LanguagePage.cpp
|
||||||
ui/pages/global/LanguagePage.h
|
ui/pages/global/LanguagePage.h
|
||||||
|
ui/pages/global/MinecraftPage.cpp
|
||||||
ui/pages/global/MinecraftPage.h
|
ui/pages/global/MinecraftPage.h
|
||||||
ui/pages/global/LauncherPage.cpp
|
ui/pages/global/LauncherPage.cpp
|
||||||
ui/pages/global/LauncherPage.h
|
ui/pages/global/LauncherPage.h
|
||||||
@ -981,9 +930,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/pages/modplatform/ShaderPackPage.cpp
|
ui/pages/modplatform/ShaderPackPage.cpp
|
||||||
ui/pages/modplatform/ShaderPackModel.cpp
|
ui/pages/modplatform/ShaderPackModel.cpp
|
||||||
|
|
||||||
|
|
||||||
ui/pages/modplatform/ModpackProviderBasePage.h
|
|
||||||
|
|
||||||
ui/pages/modplatform/atlauncher/AtlFilterModel.cpp
|
ui/pages/modplatform/atlauncher/AtlFilterModel.cpp
|
||||||
ui/pages/modplatform/atlauncher/AtlFilterModel.h
|
ui/pages/modplatform/atlauncher/AtlFilterModel.h
|
||||||
ui/pages/modplatform/atlauncher/AtlListModel.cpp
|
ui/pages/modplatform/atlauncher/AtlListModel.cpp
|
||||||
@ -1046,6 +992,8 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/dialogs/CopyInstanceDialog.h
|
ui/dialogs/CopyInstanceDialog.h
|
||||||
ui/dialogs/CustomMessageBox.cpp
|
ui/dialogs/CustomMessageBox.cpp
|
||||||
ui/dialogs/CustomMessageBox.h
|
ui/dialogs/CustomMessageBox.h
|
||||||
|
ui/dialogs/EditAccountDialog.cpp
|
||||||
|
ui/dialogs/EditAccountDialog.h
|
||||||
ui/dialogs/ExportInstanceDialog.cpp
|
ui/dialogs/ExportInstanceDialog.cpp
|
||||||
ui/dialogs/ExportInstanceDialog.h
|
ui/dialogs/ExportInstanceDialog.h
|
||||||
ui/dialogs/ExportPackDialog.cpp
|
ui/dialogs/ExportPackDialog.cpp
|
||||||
@ -1074,6 +1022,8 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/dialogs/ReviewMessageBox.h
|
ui/dialogs/ReviewMessageBox.h
|
||||||
ui/dialogs/VersionSelectDialog.cpp
|
ui/dialogs/VersionSelectDialog.cpp
|
||||||
ui/dialogs/VersionSelectDialog.h
|
ui/dialogs/VersionSelectDialog.h
|
||||||
|
ui/dialogs/SkinUploadDialog.cpp
|
||||||
|
ui/dialogs/SkinUploadDialog.h
|
||||||
ui/dialogs/ResourceDownloadDialog.cpp
|
ui/dialogs/ResourceDownloadDialog.cpp
|
||||||
ui/dialogs/ResourceDownloadDialog.h
|
ui/dialogs/ResourceDownloadDialog.h
|
||||||
ui/dialogs/ScrollMessageBox.cpp
|
ui/dialogs/ScrollMessageBox.cpp
|
||||||
@ -1082,36 +1032,26 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/dialogs/BlockedModsDialog.h
|
ui/dialogs/BlockedModsDialog.h
|
||||||
ui/dialogs/ChooseProviderDialog.h
|
ui/dialogs/ChooseProviderDialog.h
|
||||||
ui/dialogs/ChooseProviderDialog.cpp
|
ui/dialogs/ChooseProviderDialog.cpp
|
||||||
ui/dialogs/ResourceUpdateDialog.cpp
|
ui/dialogs/ModUpdateDialog.cpp
|
||||||
ui/dialogs/ResourceUpdateDialog.h
|
ui/dialogs/ModUpdateDialog.h
|
||||||
ui/dialogs/InstallLoaderDialog.cpp
|
ui/dialogs/InstallLoaderDialog.cpp
|
||||||
ui/dialogs/InstallLoaderDialog.h
|
ui/dialogs/InstallLoaderDialog.h
|
||||||
|
|
||||||
ui/dialogs/skins/SkinManageDialog.cpp
|
|
||||||
ui/dialogs/skins/SkinManageDialog.h
|
|
||||||
|
|
||||||
ui/dialogs/skins/draw/SkinOpenGLWindow.h
|
|
||||||
ui/dialogs/skins/draw/SkinOpenGLWindow.cpp
|
|
||||||
ui/dialogs/skins/draw/Scene.h
|
|
||||||
ui/dialogs/skins/draw/Scene.cpp
|
|
||||||
ui/dialogs/skins/draw/BoxGeometry.h
|
|
||||||
ui/dialogs/skins/draw/BoxGeometry.cpp
|
|
||||||
|
|
||||||
# GUI - widgets
|
# GUI - widgets
|
||||||
ui/widgets/CheckComboBox.cpp
|
|
||||||
ui/widgets/CheckComboBox.h
|
|
||||||
ui/widgets/Common.cpp
|
ui/widgets/Common.cpp
|
||||||
ui/widgets/Common.h
|
ui/widgets/Common.h
|
||||||
ui/widgets/CustomCommands.cpp
|
ui/widgets/CustomCommands.cpp
|
||||||
ui/widgets/CustomCommands.h
|
ui/widgets/CustomCommands.h
|
||||||
ui/widgets/EnvironmentVariables.cpp
|
ui/widgets/EnvironmentVariables.cpp
|
||||||
ui/widgets/EnvironmentVariables.h
|
ui/widgets/EnvironmentVariables.h
|
||||||
|
ui/widgets/DropLabel.cpp
|
||||||
|
ui/widgets/DropLabel.h
|
||||||
ui/widgets/FocusLineEdit.cpp
|
ui/widgets/FocusLineEdit.cpp
|
||||||
ui/widgets/FocusLineEdit.h
|
ui/widgets/FocusLineEdit.h
|
||||||
ui/widgets/IconLabel.cpp
|
ui/widgets/IconLabel.cpp
|
||||||
ui/widgets/IconLabel.h
|
ui/widgets/IconLabel.h
|
||||||
ui/widgets/JavaWizardWidget.cpp
|
ui/widgets/JavaSettingsWidget.cpp
|
||||||
ui/widgets/JavaWizardWidget.h
|
ui/widgets/JavaSettingsWidget.h
|
||||||
ui/widgets/LabeledToolButton.cpp
|
ui/widgets/LabeledToolButton.cpp
|
||||||
ui/widgets/LabeledToolButton.h
|
ui/widgets/LabeledToolButton.h
|
||||||
ui/widgets/LanguageSelectionWidget.cpp
|
ui/widgets/LanguageSelectionWidget.cpp
|
||||||
@ -1147,10 +1087,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/widgets/WideBar.cpp
|
ui/widgets/WideBar.cpp
|
||||||
ui/widgets/ThemeCustomizationWidget.h
|
ui/widgets/ThemeCustomizationWidget.h
|
||||||
ui/widgets/ThemeCustomizationWidget.cpp
|
ui/widgets/ThemeCustomizationWidget.cpp
|
||||||
ui/widgets/MinecraftSettingsWidget.h
|
|
||||||
ui/widgets/MinecraftSettingsWidget.cpp
|
|
||||||
ui/widgets/JavaSettingsWidget.h
|
|
||||||
ui/widgets/JavaSettingsWidget.cpp
|
|
||||||
|
|
||||||
# GUI - instance group view
|
# GUI - instance group view
|
||||||
ui/instanceview/InstanceProxyModel.cpp
|
ui/instanceview/InstanceProxyModel.cpp
|
||||||
@ -1167,7 +1103,7 @@ SET(LAUNCHER_SOURCES
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (NOT Apple)
|
if (NOT Apple)
|
||||||
set(LAUNCHER_SOURCES
|
set(LAUNCHER_SOURCES
|
||||||
${LAUNCHER_SOURCES}
|
${LAUNCHER_SOURCES}
|
||||||
|
|
||||||
ui/dialogs/UpdateAvailableDialog.h
|
ui/dialogs/UpdateAvailableDialog.h
|
||||||
@ -1177,8 +1113,8 @@ endif()
|
|||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(LAUNCHER_SOURCES
|
set(LAUNCHER_SOURCES
|
||||||
console/WindowsConsole.h
|
WindowsConsole.cpp
|
||||||
console/WindowsConsole.cpp
|
WindowsConsole.h
|
||||||
${LAUNCHER_SOURCES}
|
${LAUNCHER_SOURCES}
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
@ -1186,14 +1122,13 @@ endif()
|
|||||||
qt_wrap_ui(LAUNCHER_UI
|
qt_wrap_ui(LAUNCHER_UI
|
||||||
ui/MainWindow.ui
|
ui/MainWindow.ui
|
||||||
ui/setupwizard/PasteWizardPage.ui
|
ui/setupwizard/PasteWizardPage.ui
|
||||||
ui/setupwizard/AutoJavaWizardPage.ui
|
|
||||||
ui/setupwizard/LoginWizardPage.ui
|
|
||||||
ui/setupwizard/ThemeWizardPage.ui
|
ui/setupwizard/ThemeWizardPage.ui
|
||||||
ui/pages/global/AccountListPage.ui
|
ui/pages/global/AccountListPage.ui
|
||||||
ui/pages/global/JavaPage.ui
|
ui/pages/global/JavaPage.ui
|
||||||
ui/pages/global/LauncherPage.ui
|
ui/pages/global/LauncherPage.ui
|
||||||
ui/pages/global/APIPage.ui
|
ui/pages/global/APIPage.ui
|
||||||
ui/pages/global/ProxyPage.ui
|
ui/pages/global/ProxyPage.ui
|
||||||
|
ui/pages/global/MinecraftPage.ui
|
||||||
ui/pages/global/ExternalToolsPage.ui
|
ui/pages/global/ExternalToolsPage.ui
|
||||||
ui/pages/instance/ExternalResourcesPage.ui
|
ui/pages/instance/ExternalResourcesPage.ui
|
||||||
ui/pages/instance/NotesPage.ui
|
ui/pages/instance/NotesPage.ui
|
||||||
@ -1201,6 +1136,7 @@ qt_wrap_ui(LAUNCHER_UI
|
|||||||
ui/pages/instance/ServersPage.ui
|
ui/pages/instance/ServersPage.ui
|
||||||
ui/pages/instance/GameOptionsPage.ui
|
ui/pages/instance/GameOptionsPage.ui
|
||||||
ui/pages/instance/OtherLogsPage.ui
|
ui/pages/instance/OtherLogsPage.ui
|
||||||
|
ui/pages/instance/InstanceSettingsPage.ui
|
||||||
ui/pages/instance/VersionPage.ui
|
ui/pages/instance/VersionPage.ui
|
||||||
ui/pages/instance/ManagedPackPage.ui
|
ui/pages/instance/ManagedPackPage.ui
|
||||||
ui/pages/instance/WorldListPage.ui
|
ui/pages/instance/WorldListPage.ui
|
||||||
@ -1223,8 +1159,6 @@ qt_wrap_ui(LAUNCHER_UI
|
|||||||
ui/widgets/ModFilterWidget.ui
|
ui/widgets/ModFilterWidget.ui
|
||||||
ui/widgets/SubTaskProgressBar.ui
|
ui/widgets/SubTaskProgressBar.ui
|
||||||
ui/widgets/ThemeCustomizationWidget.ui
|
ui/widgets/ThemeCustomizationWidget.ui
|
||||||
ui/widgets/MinecraftSettingsWidget.ui
|
|
||||||
ui/widgets/JavaSettingsWidget.ui
|
|
||||||
ui/dialogs/CopyInstanceDialog.ui
|
ui/dialogs/CopyInstanceDialog.ui
|
||||||
ui/dialogs/ProfileSetupDialog.ui
|
ui/dialogs/ProfileSetupDialog.ui
|
||||||
ui/dialogs/ProgressDialog.ui
|
ui/dialogs/ProgressDialog.ui
|
||||||
@ -1232,6 +1166,7 @@ qt_wrap_ui(LAUNCHER_UI
|
|||||||
ui/dialogs/NewComponentDialog.ui
|
ui/dialogs/NewComponentDialog.ui
|
||||||
ui/dialogs/NewsDialog.ui
|
ui/dialogs/NewsDialog.ui
|
||||||
ui/dialogs/ProfileSelectDialog.ui
|
ui/dialogs/ProfileSelectDialog.ui
|
||||||
|
ui/dialogs/SkinUploadDialog.ui
|
||||||
ui/dialogs/ExportInstanceDialog.ui
|
ui/dialogs/ExportInstanceDialog.ui
|
||||||
ui/dialogs/ExportPackDialog.ui
|
ui/dialogs/ExportPackDialog.ui
|
||||||
ui/dialogs/ExportToModListDialog.ui
|
ui/dialogs/ExportToModListDialog.ui
|
||||||
@ -1240,11 +1175,11 @@ 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/EditAccountDialog.ui
|
||||||
ui/dialogs/ReviewMessageBox.ui
|
ui/dialogs/ReviewMessageBox.ui
|
||||||
ui/dialogs/ScrollMessageBox.ui
|
ui/dialogs/ScrollMessageBox.ui
|
||||||
ui/dialogs/BlockedModsDialog.ui
|
ui/dialogs/BlockedModsDialog.ui
|
||||||
ui/dialogs/ChooseProviderDialog.ui
|
ui/dialogs/ChooseProviderDialog.ui
|
||||||
ui/dialogs/skins/SkinManageDialog.ui
|
|
||||||
)
|
)
|
||||||
|
|
||||||
qt_wrap_ui(PRISM_UPDATE_UI
|
qt_wrap_ui(PRISM_UPDATE_UI
|
||||||
@ -1268,8 +1203,7 @@ qt_add_resources(LAUNCHER_RESOURCES
|
|||||||
resources/iOS/iOS.qrc
|
resources/iOS/iOS.qrc
|
||||||
resources/flat/flat.qrc
|
resources/flat/flat.qrc
|
||||||
resources/documents/documents.qrc
|
resources/documents/documents.qrc
|
||||||
resources/shaders/shaders.qrc
|
../${Launcher_Branding_LogoQRC}
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/../${Launcher_Branding_LogoQRC}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
qt_wrap_ui(PRISMUPDATER_UI
|
qt_wrap_ui(PRISMUPDATER_UI
|
||||||
@ -1287,10 +1221,14 @@ include(CompilerWarnings)
|
|||||||
|
|
||||||
# Add executable
|
# Add executable
|
||||||
add_library(Launcher_logic STATIC ${LOGIC_SOURCES} ${LAUNCHER_SOURCES} ${LAUNCHER_UI} ${LAUNCHER_RESOURCES})
|
add_library(Launcher_logic STATIC ${LOGIC_SOURCES} ${LAUNCHER_SOURCES} ${LAUNCHER_UI} ${LAUNCHER_RESOURCES})
|
||||||
|
if(BUILD_TESTING)
|
||||||
|
target_compile_definitions(Launcher_logic PUBLIC LAUNCHER_TEST)
|
||||||
|
endif()
|
||||||
set_project_warnings(Launcher_logic
|
set_project_warnings(Launcher_logic
|
||||||
"${Launcher_MSVC_WARNINGS}"
|
"${Launcher_MSVC_WARNINGS}"
|
||||||
"${Launcher_CLANG_WARNINGS}"
|
"${Launcher_CLANG_WARNINGS}"
|
||||||
"${Launcher_GCC_WARNINGS}")
|
"${Launcher_GCC_WARNINGS}")
|
||||||
|
target_compile_definitions(Launcher_logic PUBLIC LAUNCHER_APPLICATION)
|
||||||
target_include_directories(Launcher_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(Launcher_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
target_compile_definitions(Launcher_logic PUBLIC LAUNCHER_APPLICATION)
|
target_compile_definitions(Launcher_logic PUBLIC LAUNCHER_APPLICATION)
|
||||||
target_link_libraries(Launcher_logic
|
target_link_libraries(Launcher_logic
|
||||||
@ -1301,8 +1239,9 @@ target_link_libraries(Launcher_logic
|
|||||||
tomlplusplus::tomlplusplus
|
tomlplusplus::tomlplusplus
|
||||||
qdcss
|
qdcss
|
||||||
BuildConfig
|
BuildConfig
|
||||||
|
Katabasis
|
||||||
Qt${QT_VERSION_MAJOR}::Widgets
|
Qt${QT_VERSION_MAJOR}::Widgets
|
||||||
qrcode
|
ghcFilesystem::ghc_filesystem
|
||||||
)
|
)
|
||||||
|
|
||||||
if (UNIX AND NOT CYGWIN AND NOT APPLE)
|
if (UNIX AND NOT CYGWIN AND NOT APPLE)
|
||||||
@ -1318,9 +1257,6 @@ target_link_libraries(Launcher_logic
|
|||||||
Qt${QT_VERSION_MAJOR}::Concurrent
|
Qt${QT_VERSION_MAJOR}::Concurrent
|
||||||
Qt${QT_VERSION_MAJOR}::Gui
|
Qt${QT_VERSION_MAJOR}::Gui
|
||||||
Qt${QT_VERSION_MAJOR}::Widgets
|
Qt${QT_VERSION_MAJOR}::Widgets
|
||||||
Qt${QT_VERSION_MAJOR}::NetworkAuth
|
|
||||||
Qt${QT_VERSION_MAJOR}::OpenGL
|
|
||||||
${Launcher_QT_DBUS}
|
|
||||||
${Launcher_QT_LIBS}
|
${Launcher_QT_LIBS}
|
||||||
)
|
)
|
||||||
target_link_libraries(Launcher_logic
|
target_link_libraries(Launcher_logic
|
||||||
@ -1329,20 +1265,16 @@ target_link_libraries(Launcher_logic
|
|||||||
LocalPeer
|
LocalPeer
|
||||||
Launcher_rainbow
|
Launcher_rainbow
|
||||||
)
|
)
|
||||||
if (TARGET ${Launcher_QT_DBUS})
|
|
||||||
add_compile_definitions(WITH_QTDBUS)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set(CMAKE_MACOSX_RPATH 1)
|
set(CMAKE_MACOSX_RPATH 1)
|
||||||
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks/")
|
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks/")
|
||||||
|
|
||||||
if(Launcher_ENABLE_UPDATER)
|
if(Launcher_ENABLE_UPDATER)
|
||||||
file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256})
|
file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256})
|
||||||
file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle)
|
file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle)
|
||||||
|
|
||||||
find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
||||||
add_compile_definitions(SPARKLE_ENABLED)
|
add_compile_definitions(SPARKLE_ENABLED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(Launcher_logic
|
target_link_libraries(Launcher_logic
|
||||||
@ -1352,7 +1284,7 @@ if(APPLE)
|
|||||||
"-framework ApplicationServices"
|
"-framework ApplicationServices"
|
||||||
)
|
)
|
||||||
if(Launcher_ENABLE_UPDATER)
|
if(Launcher_ENABLE_UPDATER)
|
||||||
target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK})
|
target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -1389,17 +1321,19 @@ if(Launcher_BUILD_UPDATER)
|
|||||||
${ZLIB_LIBRARIES}
|
${ZLIB_LIBRARIES}
|
||||||
systeminfo
|
systeminfo
|
||||||
BuildConfig
|
BuildConfig
|
||||||
|
ghcFilesystem::ghc_filesystem
|
||||||
Qt${QT_VERSION_MAJOR}::Widgets
|
Qt${QT_VERSION_MAJOR}::Widgets
|
||||||
Qt${QT_VERSION_MAJOR}::Core
|
Qt${QT_VERSION_MAJOR}::Core
|
||||||
Qt${QT_VERSION_MAJOR}::Network
|
Qt${QT_VERSION_MAJOR}::Network
|
||||||
${Launcher_QT_LIBS}
|
${Launcher_QT_LIBS}
|
||||||
cmark::cmark
|
cmark::cmark
|
||||||
|
Katabasis
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable("${Launcher_Name}_updater" WIN32 updater/prismupdater/updater_main.cpp)
|
add_executable("${Launcher_Name}_updater" WIN32 updater/prismupdater/updater_main.cpp)
|
||||||
target_sources("${Launcher_Name}_updater" PRIVATE updater/prismupdater/updater.exe.manifest)
|
target_sources("${Launcher_Name}_updater" PRIVATE updater/prismupdater/updater.exe.manifest)
|
||||||
target_link_libraries("${Launcher_Name}_updater" prism_updater_logic)
|
target_link_libraries("${Launcher_Name}_updater" prism_updater_logic)
|
||||||
|
|
||||||
if(DEFINED Launcher_APP_BINARY_NAME)
|
if(DEFINED Launcher_APP_BINARY_NAME)
|
||||||
set_target_properties("${Launcher_Name}_updater" PROPERTIES OUTPUT_NAME "${Launcher_APP_BINARY_NAME}_updater")
|
set_target_properties("${Launcher_Name}_updater" PROPERTIES OUTPUT_NAME "${Launcher_APP_BINARY_NAME}_updater")
|
||||||
endif()
|
endif()
|
||||||
@ -1427,6 +1361,7 @@ if(WIN32 OR (DEFINED Launcher_BUILD_FILELINKER AND Launcher_BUILD_FILELINKER))
|
|||||||
target_link_libraries(filelink_logic
|
target_link_libraries(filelink_logic
|
||||||
systeminfo
|
systeminfo
|
||||||
BuildConfig
|
BuildConfig
|
||||||
|
ghcFilesystem::ghc_filesystem
|
||||||
Qt${QT_VERSION_MAJOR}::Widgets
|
Qt${QT_VERSION_MAJOR}::Widgets
|
||||||
Qt${QT_VERSION_MAJOR}::Core
|
Qt${QT_VERSION_MAJOR}::Core
|
||||||
Qt${QT_VERSION_MAJOR}::Network
|
Qt${QT_VERSION_MAJOR}::Network
|
||||||
@ -1557,6 +1492,7 @@ if(INSTALL_BUNDLE STREQUAL "full")
|
|||||||
CONFIGURATIONS Debug RelWithDebInfo ""
|
CONFIGURATIONS Debug RelWithDebInfo ""
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
COMPONENT Runtime
|
COMPONENT Runtime
|
||||||
|
PATTERN "*qopensslbackend*" EXCLUDE
|
||||||
PATTERN "*qcertonlybackend*" EXCLUDE
|
PATTERN "*qcertonlybackend*" EXCLUDE
|
||||||
)
|
)
|
||||||
install(
|
install(
|
||||||
@ -1567,78 +1503,10 @@ if(INSTALL_BUNDLE STREQUAL "full")
|
|||||||
REGEX "dd\\." EXCLUDE
|
REGEX "dd\\." EXCLUDE
|
||||||
REGEX "_debug\\." EXCLUDE
|
REGEX "_debug\\." EXCLUDE
|
||||||
REGEX "\\.dSYM" EXCLUDE
|
REGEX "\\.dSYM" EXCLUDE
|
||||||
|
PATTERN "*qopensslbackend*" EXCLUDE
|
||||||
PATTERN "*qcertonlybackend*" EXCLUDE
|
PATTERN "*qcertonlybackend*" EXCLUDE
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
# Wayland support
|
|
||||||
if(EXISTS "${QT_PLUGINS_DIR}/wayland-graphics-integration-client")
|
|
||||||
install(
|
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/wayland-graphics-integration-client"
|
|
||||||
CONFIGURATIONS Debug RelWithDebInfo ""
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
)
|
|
||||||
install(
|
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/wayland-graphics-integration-client"
|
|
||||||
CONFIGURATIONS Release MinSizeRel
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
REGEX "dd\\." EXCLUDE
|
|
||||||
REGEX "_debug\\." EXCLUDE
|
|
||||||
REGEX "\\.dSYM" EXCLUDE
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
if(EXISTS "${QT_PLUGINS_DIR}/wayland-graphics-integration-server")
|
|
||||||
install(
|
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/wayland-graphics-integration-server"
|
|
||||||
CONFIGURATIONS Debug RelWithDebInfo ""
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
)
|
|
||||||
install(
|
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/wayland-graphics-integration-server"
|
|
||||||
CONFIGURATIONS Release MinSizeRel
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
REGEX "dd\\." EXCLUDE
|
|
||||||
REGEX "_debug\\." EXCLUDE
|
|
||||||
REGEX "\\.dSYM" EXCLUDE
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
if(EXISTS "${QT_PLUGINS_DIR}/wayland-decoration-client")
|
|
||||||
install(
|
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/wayland-decoration-client"
|
|
||||||
CONFIGURATIONS Debug RelWithDebInfo ""
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
)
|
|
||||||
install(
|
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/wayland-decoration-client"
|
|
||||||
CONFIGURATIONS Release MinSizeRel
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
REGEX "dd\\." EXCLUDE
|
|
||||||
REGEX "_debug\\." EXCLUDE
|
|
||||||
REGEX "\\.dSYM" EXCLUDE
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
if(EXISTS "${QT_PLUGINS_DIR}/wayland-shell-integration")
|
|
||||||
install(
|
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/wayland-shell-integration"
|
|
||||||
CONFIGURATIONS Debug RelWithDebInfo ""
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
)
|
|
||||||
install(
|
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/wayland-shell-integration"
|
|
||||||
CONFIGURATIONS Release MinSizeRel
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
REGEX "dd\\." EXCLUDE
|
|
||||||
REGEX "_debug\\." EXCLUDE
|
|
||||||
REGEX "\\.dSYM" EXCLUDE
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
configure_file(
|
configure_file(
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in"
|
"${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in"
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake"
|
"${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake"
|
||||||
|
@ -12,10 +12,13 @@
|
|||||||
|
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
|
|
||||||
DataMigrationTask::DataMigrationTask(const QString& sourcePath, const QString& targetPath, const IPathMatcher::Ptr pathMatcher)
|
DataMigrationTask::DataMigrationTask(QObject* parent,
|
||||||
: Task(), m_sourcePath(sourcePath), m_targetPath(targetPath), m_pathMatcher(pathMatcher), m_copy(sourcePath, targetPath)
|
const QString& sourcePath,
|
||||||
|
const QString& targetPath,
|
||||||
|
const IPathMatcher::Ptr pathMatcher)
|
||||||
|
: Task(parent), m_sourcePath(sourcePath), m_targetPath(targetPath), m_pathMatcher(pathMatcher), m_copy(sourcePath, targetPath)
|
||||||
{
|
{
|
||||||
m_copy.matcher(m_pathMatcher).whitelist(true);
|
m_copy.matcher(m_pathMatcher.get()).whitelist(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataMigrationTask::executeTask()
|
void DataMigrationTask::executeTask()
|
||||||
@ -24,7 +27,7 @@ void DataMigrationTask::executeTask()
|
|||||||
|
|
||||||
// 1. Scan
|
// 1. Scan
|
||||||
// Check how many files we gotta copy
|
// Check how many files we gotta copy
|
||||||
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this] {
|
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [&] {
|
||||||
return m_copy(true); // dry run to collect amount of files
|
return m_copy(true); // dry run to collect amount of files
|
||||||
});
|
});
|
||||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished);
|
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished);
|
||||||
@ -37,7 +40,11 @@ void DataMigrationTask::dryRunFinished()
|
|||||||
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished);
|
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished);
|
||||||
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::dryRunAborted);
|
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::dryRunAborted);
|
||||||
|
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||||
if (!m_copyFuture.isValid() || !m_copyFuture.result()) {
|
if (!m_copyFuture.isValid() || !m_copyFuture.result()) {
|
||||||
|
#else
|
||||||
|
if (!m_copyFuture.result()) {
|
||||||
|
#endif
|
||||||
emitFailed(tr("Failed to scan source path."));
|
emitFailed(tr("Failed to scan source path."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -53,7 +60,7 @@ void DataMigrationTask::dryRunFinished()
|
|||||||
setProgress(m_copy.totalCopied(), m_toCopy);
|
setProgress(m_copy.totalCopied(), m_toCopy);
|
||||||
setStatus(tr("Copying %1…").arg(shortenedName));
|
setStatus(tr("Copying %1…").arg(shortenedName));
|
||||||
});
|
});
|
||||||
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this] {
|
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [&] {
|
||||||
return m_copy(false); // actually copy now
|
return m_copy(false); // actually copy now
|
||||||
});
|
});
|
||||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished);
|
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished);
|
||||||
@ -71,7 +78,11 @@ void DataMigrationTask::copyFinished()
|
|||||||
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished);
|
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished);
|
||||||
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::copyAborted);
|
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::copyAborted);
|
||||||
|
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||||
if (!m_copyFuture.isValid() || !m_copyFuture.result()) {
|
if (!m_copyFuture.isValid() || !m_copyFuture.result()) {
|
||||||
|
#else
|
||||||
|
if (!m_copyFuture.result()) {
|
||||||
|
#endif
|
||||||
emitFailed(tr("Some paths could not be copied!"));
|
emitFailed(tr("Some paths could not be copied!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
class DataMigrationTask : public Task {
|
class DataMigrationTask : public Task {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit DataMigrationTask(const QString& sourcePath, const QString& targetPath, IPathMatcher::Ptr pathmatcher);
|
explicit DataMigrationTask(QObject* parent, const QString& sourcePath, const QString& targetPath, const IPathMatcher::Ptr pathmatcher);
|
||||||
~DataMigrationTask() override = default;
|
~DataMigrationTask() override = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -37,33 +37,143 @@
|
|||||||
#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 openPath(const QFileInfo& path, bool ensureFolderPathExists)
|
bool openDirectory(const QString& path, [[maybe_unused]] bool ensureExists)
|
||||||
{
|
{
|
||||||
qDebug() << "Opening path" << path;
|
qDebug() << "Opening directory" << path;
|
||||||
if (ensureFolderPathExists) {
|
QDir parentPath;
|
||||||
FS::ensureFolderPathExists(path);
|
QDir dir(path);
|
||||||
|
if (ensureExists && !dir.exists()) {
|
||||||
|
parentPath.mkpath(dir.absolutePath());
|
||||||
}
|
}
|
||||||
return openUrl(QUrl::fromLocalFile(QFileInfo(path).absoluteFilePath()));
|
auto f = [&]() { return QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath())); };
|
||||||
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||||
|
if (!isSandbox()) {
|
||||||
|
return IndirectOpen(f);
|
||||||
|
} else {
|
||||||
|
return f();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return f();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool openPath(const QString& path, bool ensureFolderPathExists)
|
bool openFile(const QString& path)
|
||||||
{
|
{
|
||||||
return openPath(QFileInfo(path), ensureFolderPathExists);
|
qDebug() << "Opening file" << path;
|
||||||
|
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();
|
||||||
return QDesktopServices::openUrl(url);
|
auto f = [&]() { 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()
|
||||||
@ -84,4 +194,9 @@ bool isSnap()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isSandbox()
|
||||||
|
{
|
||||||
|
return isSnap() || isFlatpak();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace DesktopServices
|
} // namespace DesktopServices
|
||||||
|
@ -3,30 +3,31 @@
|
|||||||
#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 path in whatever application is applicable.
|
* Open a file in whatever application is applicable
|
||||||
* @param ensureFolderPathExists Make sure the path exists
|
|
||||||
*/
|
*/
|
||||||
bool openPath(const QFileInfo& path, bool ensureFolderPathExists = false);
|
bool openFile(const QString& path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a path in whatever application is applicable.
|
* Open a file in the specified application
|
||||||
* @param ensureFolderPathExists Make sure the path exists
|
|
||||||
*/
|
*/
|
||||||
bool openPath(const QString& path, bool ensureFolderPathExists = false);
|
bool openFile(const QString& application, const QString& path, const QString& workingDirectory = QString(), qint64* pid = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
@ -41,4 +42,9 @@ 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,37 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0
|
// Licensed under the Apache-2.0 license. See README.md for details.
|
||||||
/*
|
|
||||||
* 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
|
||||||
|
|
||||||
@ -41,12 +8,12 @@
|
|||||||
|
|
||||||
class Exception : public std::exception {
|
class Exception : public std::exception {
|
||||||
public:
|
public:
|
||||||
Exception(const QString& message) : std::exception(), m_message(message.toUtf8()) { qCritical() << "Exception:" << message; }
|
Exception(const QString& message) : std::exception(), m_message(message) { qCritical() << "Exception:" << message; }
|
||||||
Exception(const Exception& other) : std::exception(), m_message(other.m_message) {}
|
Exception(const Exception& other) : std::exception(), m_message(other.cause()) {}
|
||||||
virtual ~Exception() noexcept {}
|
virtual ~Exception() noexcept {}
|
||||||
const char* what() const noexcept { return m_message.constData(); }
|
const char* what() const noexcept { return m_message.toLatin1().constData(); }
|
||||||
QString cause() const { return QString::fromUtf8(m_message); }
|
QString cause() const { return m_message; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QByteArray m_message;
|
QString m_message;
|
||||||
};
|
};
|
||||||
|
@ -40,11 +40,12 @@
|
|||||||
#include <QFileSystemModel>
|
#include <QFileSystemModel>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
#include <QStack>
|
#include <QStack>
|
||||||
|
#include <algorithm>
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "SeparatorPrefixTree.h"
|
#include "SeparatorPrefixTree.h"
|
||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
|
|
||||||
FileIgnoreProxy::FileIgnoreProxy(QString root, QObject* parent) : QSortFilterProxyModel(parent), m_root(root) {}
|
FileIgnoreProxy::FileIgnoreProxy(QString root, QObject* parent) : QSortFilterProxyModel(parent), root(root) {}
|
||||||
// NOTE: Sadly, we have to do sorting ourselves.
|
// NOTE: Sadly, we have to do sorting ourselves.
|
||||||
bool FileIgnoreProxy::lessThan(const QModelIndex& left, const QModelIndex& right) const
|
bool FileIgnoreProxy::lessThan(const QModelIndex& left, const QModelIndex& right) const
|
||||||
{
|
{
|
||||||
@ -103,10 +104,10 @@ QVariant FileIgnoreProxy::data(const QModelIndex& index, int role) const
|
|||||||
if (index.column() == 0 && role == Qt::CheckStateRole) {
|
if (index.column() == 0 && role == Qt::CheckStateRole) {
|
||||||
QFileSystemModel* fsm = qobject_cast<QFileSystemModel*>(sourceModel());
|
QFileSystemModel* fsm = qobject_cast<QFileSystemModel*>(sourceModel());
|
||||||
auto blockedPath = relPath(fsm->filePath(sourceIndex));
|
auto blockedPath = relPath(fsm->filePath(sourceIndex));
|
||||||
auto cover = m_blocked.cover(blockedPath);
|
auto cover = blocked.cover(blockedPath);
|
||||||
if (!cover.isNull()) {
|
if (!cover.isNull()) {
|
||||||
return QVariant(Qt::Unchecked);
|
return QVariant(Qt::Unchecked);
|
||||||
} else if (m_blocked.exists(blockedPath)) {
|
} else if (blocked.exists(blockedPath)) {
|
||||||
return QVariant(Qt::PartiallyChecked);
|
return QVariant(Qt::PartiallyChecked);
|
||||||
} else {
|
} else {
|
||||||
return QVariant(Qt::Checked);
|
return QVariant(Qt::Checked);
|
||||||
@ -129,7 +130,7 @@ bool FileIgnoreProxy::setData(const QModelIndex& index, const QVariant& value, i
|
|||||||
|
|
||||||
QString FileIgnoreProxy::relPath(const QString& path) const
|
QString FileIgnoreProxy::relPath(const QString& path) const
|
||||||
{
|
{
|
||||||
return QDir(m_root).relativeFilePath(path);
|
return QDir(root).relativeFilePath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileIgnoreProxy::setFilterState(QModelIndex index, Qt::CheckState state)
|
bool FileIgnoreProxy::setFilterState(QModelIndex index, Qt::CheckState state)
|
||||||
@ -145,18 +146,18 @@ bool FileIgnoreProxy::setFilterState(QModelIndex index, Qt::CheckState state)
|
|||||||
bool changed = false;
|
bool changed = false;
|
||||||
if (state == Qt::Unchecked) {
|
if (state == Qt::Unchecked) {
|
||||||
// blocking a path
|
// blocking a path
|
||||||
auto& node = m_blocked.insert(blockedPath);
|
auto& node = blocked.insert(blockedPath);
|
||||||
// get rid of all blocked nodes below
|
// get rid of all blocked nodes below
|
||||||
node.clear();
|
node.clear();
|
||||||
changed = true;
|
changed = true;
|
||||||
} else if (state == Qt::Checked || state == Qt::PartiallyChecked) {
|
} else if (state == Qt::Checked || state == Qt::PartiallyChecked) {
|
||||||
if (!m_blocked.remove(blockedPath)) {
|
if (!blocked.remove(blockedPath)) {
|
||||||
auto cover = m_blocked.cover(blockedPath);
|
auto cover = blocked.cover(blockedPath);
|
||||||
qDebug() << "Blocked by cover" << cover;
|
qDebug() << "Blocked by cover" << cover;
|
||||||
// uncover
|
// uncover
|
||||||
m_blocked.remove(cover);
|
blocked.remove(cover);
|
||||||
// block all contents, except for any cover
|
// block all contents, except for any cover
|
||||||
QModelIndex rootIndex = fsm->index(FS::PathCombine(m_root, cover));
|
QModelIndex rootIndex = fsm->index(FS::PathCombine(root, cover));
|
||||||
QModelIndex doing = rootIndex;
|
QModelIndex doing = rootIndex;
|
||||||
int row = 0;
|
int row = 0;
|
||||||
QStack<QModelIndex> todo;
|
QStack<QModelIndex> todo;
|
||||||
@ -178,7 +179,7 @@ bool FileIgnoreProxy::setFilterState(QModelIndex index, Qt::CheckState state)
|
|||||||
todo.push(node);
|
todo.push(node);
|
||||||
} else {
|
} else {
|
||||||
// or just block this one.
|
// or just block this one.
|
||||||
m_blocked.insert(relpath);
|
blocked.insert(relpath);
|
||||||
}
|
}
|
||||||
row++;
|
row++;
|
||||||
}
|
}
|
||||||
@ -228,7 +229,7 @@ bool FileIgnoreProxy::shouldExpand(QModelIndex index)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto blockedPath = relPath(fsm->filePath(sourceIndex));
|
auto blockedPath = relPath(fsm->filePath(sourceIndex));
|
||||||
auto found = m_blocked.find(blockedPath);
|
auto found = blocked.find(blockedPath);
|
||||||
if (found) {
|
if (found) {
|
||||||
return !found->leaf();
|
return !found->leaf();
|
||||||
}
|
}
|
||||||
@ -238,8 +239,8 @@ bool FileIgnoreProxy::shouldExpand(QModelIndex index)
|
|||||||
void FileIgnoreProxy::setBlockedPaths(QStringList paths)
|
void FileIgnoreProxy::setBlockedPaths(QStringList paths)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_blocked.clear();
|
blocked.clear();
|
||||||
m_blocked.insert(paths);
|
blocked.insert(paths);
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,28 +270,7 @@ bool FileIgnoreProxy::ignoreFile(QFileInfo fileInfo) const
|
|||||||
return m_ignoreFiles.contains(fileInfo.fileName()) || m_ignoreFilePaths.covers(relPath(fileInfo.absoluteFilePath()));
|
return m_ignoreFiles.contains(fileInfo.fileName()) || m_ignoreFilePaths.covers(relPath(fileInfo.absoluteFilePath()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileIgnoreProxy::filterFile(const QFileInfo& file) const
|
bool FileIgnoreProxy::filterFile(const QString& fileName) const
|
||||||
{
|
{
|
||||||
return m_blocked.covers(relPath(file.absoluteFilePath())) || ignoreFile(file);
|
return blocked.covers(fileName) || ignoreFile(QFileInfo(QDir(root), fileName));
|
||||||
}
|
|
||||||
|
|
||||||
void FileIgnoreProxy::loadBlockedPathsFromFile(const QString& fileName)
|
|
||||||
{
|
|
||||||
QFile ignoreFile(fileName);
|
|
||||||
if (!ignoreFile.open(QIODevice::ReadOnly)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto ignoreData = ignoreFile.readAll();
|
|
||||||
auto string = QString::fromUtf8(ignoreData);
|
|
||||||
setBlockedPaths(string.split('\n', Qt::SkipEmptyParts));
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileIgnoreProxy::saveBlockedPathsToFile(const QString& fileName)
|
|
||||||
{
|
|
||||||
auto ignoreData = blockedPaths().toStringList().join('\n').toUtf8();
|
|
||||||
try {
|
|
||||||
FS::write(fileName, ignoreData);
|
|
||||||
} catch (const Exception& e) {
|
|
||||||
qWarning() << e.cause();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -61,19 +61,15 @@ class FileIgnoreProxy : public QSortFilterProxyModel {
|
|||||||
|
|
||||||
void setBlockedPaths(QStringList paths);
|
void setBlockedPaths(QStringList paths);
|
||||||
|
|
||||||
inline const SeparatorPrefixTree<'/'>& blockedPaths() const { return m_blocked; }
|
inline const SeparatorPrefixTree<'/'>& blockedPaths() const { return blocked; }
|
||||||
inline SeparatorPrefixTree<'/'>& blockedPaths() { return m_blocked; }
|
inline SeparatorPrefixTree<'/'>& blockedPaths() { return blocked; }
|
||||||
|
|
||||||
// list of file names that need to be removed completely from model
|
// list of file names that need to be removed completely from model
|
||||||
inline QStringList& ignoreFilesWithName() { return m_ignoreFiles; }
|
inline QStringList& ignoreFilesWithName() { return m_ignoreFiles; }
|
||||||
// list of relative paths that need to be removed completely from model
|
// list of relative paths that need to be removed completely from model
|
||||||
inline SeparatorPrefixTree<'/'>& ignoreFilesWithPath() { return m_ignoreFilePaths; }
|
inline SeparatorPrefixTree<'/'>& ignoreFilesWithPath() { return m_ignoreFilePaths; }
|
||||||
|
|
||||||
bool filterFile(const QFileInfo& fileName) const;
|
bool filterFile(const QString& fileName) const;
|
||||||
|
|
||||||
void loadBlockedPathsFromFile(const QString& fileName);
|
|
||||||
|
|
||||||
void saveBlockedPathsToFile(const QString& fileName);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool filterAcceptsColumn(int source_column, const QModelIndex& source_parent) const;
|
bool filterAcceptsColumn(int source_column, const QModelIndex& source_parent) const;
|
||||||
@ -82,8 +78,8 @@ class FileIgnoreProxy : public QSortFilterProxyModel {
|
|||||||
bool ignoreFile(QFileInfo file) const;
|
bool ignoreFile(QFileInfo file) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const QString m_root;
|
const QString root;
|
||||||
SeparatorPrefixTree<'/'> m_blocked;
|
SeparatorPrefixTree<'/'> blocked;
|
||||||
QStringList m_ignoreFiles;
|
QStringList m_ignoreFiles;
|
||||||
SeparatorPrefixTree<'/'> m_ignoreFilePaths;
|
SeparatorPrefixTree<'/'> m_ignoreFilePaths;
|
||||||
};
|
};
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QSaveFile>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QStorageInfo>
|
#include <QStorageInfo>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
@ -53,7 +54,6 @@
|
|||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
|
||||||
#include "DesktopServices.h"
|
#include "DesktopServices.h"
|
||||||
#include "PSaveFile.h"
|
|
||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
@ -77,8 +77,24 @@
|
|||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Snippet from https://github.com/gulrak/filesystem#using-it-as-single-file-header
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <Availability.h> // for deployment target to support pre-catalina targets without std::fs
|
||||||
|
#endif // __APPLE__
|
||||||
|
|
||||||
|
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
|
||||||
|
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
|
||||||
|
#define GHC_USE_STD_FS
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
#endif // MacOS min version check
|
||||||
|
#endif // Other OSes version check
|
||||||
|
|
||||||
|
#ifndef GHC_USE_STD_FS
|
||||||
|
#include <ghc/filesystem.hpp>
|
||||||
|
namespace fs = ghc::filesystem;
|
||||||
|
#endif
|
||||||
|
|
||||||
// clone
|
// clone
|
||||||
#if defined(Q_OS_LINUX)
|
#if defined(Q_OS_LINUX)
|
||||||
@ -175,8 +191,8 @@ void ensureExists(const QDir& dir)
|
|||||||
void write(const QString& filename, const QByteArray& data)
|
void write(const QString& filename, const QByteArray& data)
|
||||||
{
|
{
|
||||||
ensureExists(QFileInfo(filename).dir());
|
ensureExists(QFileInfo(filename).dir());
|
||||||
PSaveFile file(filename);
|
QSaveFile file(filename);
|
||||||
if (!file.open(PSaveFile::WriteOnly)) {
|
if (!file.open(QSaveFile::WriteOnly)) {
|
||||||
throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString());
|
throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString());
|
||||||
}
|
}
|
||||||
if (data.size() != file.write(data)) {
|
if (data.size() != file.write(data)) {
|
||||||
@ -197,8 +213,8 @@ void appendSafe(const QString& filename, const QByteArray& data)
|
|||||||
buffer = QByteArray();
|
buffer = QByteArray();
|
||||||
}
|
}
|
||||||
buffer.append(data);
|
buffer.append(data);
|
||||||
PSaveFile file(filename);
|
QSaveFile file(filename);
|
||||||
if (!file.open(PSaveFile::WriteOnly)) {
|
if (!file.open(QSaveFile::WriteOnly)) {
|
||||||
throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString());
|
throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString());
|
||||||
}
|
}
|
||||||
if (buffer.size() != file.write(buffer)) {
|
if (buffer.size() != file.write(buffer)) {
|
||||||
@ -256,22 +272,15 @@ bool ensureFilePathExists(QString filenamepath)
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ensureFolderPathExists(const QFileInfo folderPath)
|
bool ensureFolderPathExists(QString foldernamepath)
|
||||||
{
|
{
|
||||||
|
QFileInfo a(foldernamepath);
|
||||||
QDir dir;
|
QDir dir;
|
||||||
QString ensuredPath = folderPath.filePath();
|
QString ensuredPath = a.filePath();
|
||||||
if (folderPath.exists())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
bool success = dir.mkpath(ensuredPath);
|
bool success = dir.mkpath(ensuredPath);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ensureFolderPathExists(const QString folderPathName)
|
|
||||||
{
|
|
||||||
return ensureFolderPathExists(QFileInfo(folderPathName));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool copyFileAttributes(QString src, QString dst)
|
bool copyFileAttributes(QString src, QString dst)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
@ -325,7 +334,7 @@ bool copy::operator()(const QString& offset, bool dryRun)
|
|||||||
opt |= copy_opts::overwrite_existing;
|
opt |= copy_opts::overwrite_existing;
|
||||||
|
|
||||||
// Function that'll do the actual copying
|
// Function that'll do the actual copying
|
||||||
auto copy_file = [this, dryRun, src, dst, opt, &err](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))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -412,7 +421,7 @@ void create_link::make_link_list(const QString& offset)
|
|||||||
m_recursive = true;
|
m_recursive = true;
|
||||||
|
|
||||||
// Function that'll do the actual linking
|
// Function that'll do the actual linking
|
||||||
auto link_file = [this, dst](QString src_path, QString relative_dst_path) {
|
auto link_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)) {
|
||||||
qDebug() << "path" << relative_dst_path << "in black list or not in whitelist";
|
qDebug() << "path" << relative_dst_path << "in black list or not in whitelist";
|
||||||
return;
|
return;
|
||||||
@ -507,7 +516,7 @@ void create_link::runPrivileged(const QString& offset)
|
|||||||
|
|
||||||
QString serverName = BuildConfig.LAUNCHER_APP_BINARY_NAME + "_filelink_server" + StringUtils::getRandomAlphaNumeric();
|
QString serverName = BuildConfig.LAUNCHER_APP_BINARY_NAME + "_filelink_server" + StringUtils::getRandomAlphaNumeric();
|
||||||
|
|
||||||
connect(&m_linkServer, &QLocalServer::newConnection, this, [this, &gotResults]() {
|
connect(&m_linkServer, &QLocalServer::newConnection, this, [&]() {
|
||||||
qDebug() << "Client connected, sending out pairs";
|
qDebug() << "Client connected, sending out pairs";
|
||||||
// construct block of data to send
|
// construct block of data to send
|
||||||
QByteArray block;
|
QByteArray block;
|
||||||
@ -589,7 +598,7 @@ void create_link::runPrivileged(const QString& offset)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ExternalLinkFileProcess* linkFileProcess = new ExternalLinkFileProcess(serverName, m_useHardLinks, this);
|
ExternalLinkFileProcess* linkFileProcess = new ExternalLinkFileProcess(serverName, m_useHardLinks, this);
|
||||||
connect(linkFileProcess, &ExternalLinkFileProcess::processExited, this, [this, gotResults]() { emit finishedPrivileged(gotResults); });
|
connect(linkFileProcess, &ExternalLinkFileProcess::processExited, this, [&]() { emit finishedPrivileged(gotResults); });
|
||||||
connect(linkFileProcess, &ExternalLinkFileProcess::finished, linkFileProcess, &QObject::deleteLater);
|
connect(linkFileProcess, &ExternalLinkFileProcess::finished, linkFileProcess, &QObject::deleteLater);
|
||||||
|
|
||||||
linkFileProcess->start();
|
linkFileProcess->start();
|
||||||
@ -634,19 +643,6 @@ void ExternalLinkFileProcess::runLinkFile()
|
|||||||
qDebug() << "Process exited";
|
qDebug() << "Process exited";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool moveByCopy(const QString& source, const QString& dest)
|
|
||||||
{
|
|
||||||
if (!copy(source, dest)()) { // copy
|
|
||||||
qDebug() << "Copy of" << source << "to" << dest << "failed!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!deletePath(source)) { // remove original
|
|
||||||
qDebug() << "Deletion of" << source << "failed!";
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool move(const QString& source, const QString& dest)
|
bool move(const QString& source, const QString& dest)
|
||||||
{
|
{
|
||||||
std::error_code err;
|
std::error_code err;
|
||||||
@ -654,14 +650,13 @@ bool move(const QString& source, const QString& dest)
|
|||||||
ensureFilePathExists(dest);
|
ensureFilePathExists(dest);
|
||||||
fs::rename(StringUtils::toStdString(source), StringUtils::toStdString(dest), err);
|
fs::rename(StringUtils::toStdString(source), StringUtils::toStdString(dest), err);
|
||||||
|
|
||||||
if (err.value() != 0) {
|
if (err) {
|
||||||
if (moveByCopy(source, dest))
|
qWarning() << "Failed to move file:" << QString::fromStdString(err.message());
|
||||||
return true;
|
qDebug() << "Source file:" << source;
|
||||||
qDebug() << "Move of" << source << "to" << dest << "failed!";
|
qDebug() << "Destination file:" << dest;
|
||||||
qWarning() << "Failed to move file:" << QString::fromStdString(err.message()) << QString::number(err.value());
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
return err.value() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deletePath(QString path)
|
bool deletePath(QString path)
|
||||||
@ -679,6 +674,9 @@ bool deletePath(QString path)
|
|||||||
|
|
||||||
bool trash(QString path, QString* pathInTrash)
|
bool trash(QString path, QString* pathInTrash)
|
||||||
{
|
{
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
// FIXME: Figure out trash in Flatpak. Qt seemingly doesn't use the Trash portal
|
// FIXME: Figure out trash in Flatpak. Qt seemingly doesn't use the Trash portal
|
||||||
if (DesktopServices::isFlatpak())
|
if (DesktopServices::isFlatpak())
|
||||||
return false;
|
return false;
|
||||||
@ -687,6 +685,7 @@ bool trash(QString path, QString* pathInTrash)
|
|||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
return QFile::moveToTrash(path, pathInTrash);
|
return QFile::moveToTrash(path, pathInTrash);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QString PathCombine(const QString& path1, const QString& path2)
|
QString PathCombine(const QString& path1, const QString& path2)
|
||||||
@ -720,7 +719,11 @@ int pathDepth(const QString& path)
|
|||||||
|
|
||||||
QFileInfo info(path);
|
QFileInfo info(path);
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||||
|
auto parts = QDir::toNativeSeparators(info.path()).split(QDir::separator(), QString::SkipEmptyParts);
|
||||||
|
#else
|
||||||
auto parts = QDir::toNativeSeparators(info.path()).split(QDir::separator(), Qt::SkipEmptyParts);
|
auto parts = QDir::toNativeSeparators(info.path()).split(QDir::separator(), Qt::SkipEmptyParts);
|
||||||
|
#endif
|
||||||
|
|
||||||
int numParts = parts.length();
|
int numParts = parts.length();
|
||||||
numParts -= parts.count(".");
|
numParts -= parts.count(".");
|
||||||
@ -740,7 +743,11 @@ QString pathTruncate(const QString& path, int depth)
|
|||||||
return pathTruncate(trunc, depth);
|
return pathTruncate(trunc, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||||
|
auto parts = QDir::toNativeSeparators(trunc).split(QDir::separator(), QString::SkipEmptyParts);
|
||||||
|
#else
|
||||||
auto parts = QDir::toNativeSeparators(trunc).split(QDir::separator(), Qt::SkipEmptyParts);
|
auto parts = QDir::toNativeSeparators(trunc).split(QDir::separator(), Qt::SkipEmptyParts);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (parts.startsWith(".") && !path.startsWith(".")) {
|
if (parts.startsWith(".") && !path.startsWith(".")) {
|
||||||
parts.removeFirst();
|
parts.removeFirst();
|
||||||
@ -790,68 +797,16 @@ QString NormalizePath(QString path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QString BAD_WIN_CHARS = "<>:\"|?*\r\n";
|
QString badFilenameChars = "\"\\/?<>:;*|!+\r\n";
|
||||||
static const QString BAD_NTFS_CHARS = "<>:\"|?*";
|
|
||||||
static const QString BAD_HFS_CHARS = ":";
|
|
||||||
|
|
||||||
static const QString BAD_FILENAME_CHARS = BAD_WIN_CHARS + "\\/";
|
|
||||||
|
|
||||||
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith)
|
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < string.length(); i++)
|
for (int i = 0; i < string.length(); i++) {
|
||||||
if (string.at(i) < ' ' || BAD_FILENAME_CHARS.contains(string.at(i)))
|
if (badFilenameChars.contains(string[i])) {
|
||||||
string[i] = replaceWith;
|
string[i] = replaceWith;
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString RemoveInvalidPathChars(QString path, QChar replaceWith)
|
|
||||||
{
|
|
||||||
QString invalidChars;
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
invalidChars = BAD_WIN_CHARS;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// the null character is ignored in this check as it was not a problem until now
|
|
||||||
switch (statFS(path).fsType) {
|
|
||||||
case FilesystemType::FAT: // similar to NTFS
|
|
||||||
/* fallthrough */
|
|
||||||
case FilesystemType::NTFS:
|
|
||||||
/* fallthrough */
|
|
||||||
case FilesystemType::REFS: // similar to NTFS(should be available only on windows)
|
|
||||||
invalidChars += BAD_NTFS_CHARS;
|
|
||||||
break;
|
|
||||||
// case FilesystemType::EXT:
|
|
||||||
// case FilesystemType::EXT_2_OLD:
|
|
||||||
// case FilesystemType::EXT_2_3_4:
|
|
||||||
// case FilesystemType::XFS:
|
|
||||||
// case FilesystemType::BTRFS:
|
|
||||||
// case FilesystemType::NFS:
|
|
||||||
// case FilesystemType::ZFS:
|
|
||||||
case FilesystemType::APFS:
|
|
||||||
/* fallthrough */
|
|
||||||
case FilesystemType::HFS:
|
|
||||||
/* fallthrough */
|
|
||||||
case FilesystemType::HFSPLUS:
|
|
||||||
/* fallthrough */
|
|
||||||
case FilesystemType::HFSX:
|
|
||||||
invalidChars += BAD_HFS_CHARS;
|
|
||||||
break;
|
|
||||||
// case FilesystemType::FUSEBLK:
|
|
||||||
// case FilesystemType::F2FS:
|
|
||||||
// case FilesystemType::UNKNOWN:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (invalidChars.size() != 0) {
|
|
||||||
for (int i = 0; i < path.length(); i++) {
|
|
||||||
if (path.at(i) < ' ' || invalidChars.contains(path.at(i))) {
|
|
||||||
path[i] = replaceWith;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return string;
|
||||||
return path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DirNameFromString(QString string, QString inDir)
|
QString DirNameFromString(QString string, QString inDir)
|
||||||
@ -893,10 +848,6 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
|
|||||||
if (destination.isEmpty()) {
|
if (destination.isEmpty()) {
|
||||||
destination = PathCombine(getDesktopDir(), RemoveInvalidFilenameChars(name));
|
destination = PathCombine(getDesktopDir(), RemoveInvalidFilenameChars(name));
|
||||||
}
|
}
|
||||||
if (!ensureFilePathExists(destination)) {
|
|
||||||
qWarning() << "Destination path can't be created!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#if defined(Q_OS_MACOS)
|
#if defined(Q_OS_MACOS)
|
||||||
// Create the Application
|
// Create the Application
|
||||||
QDir applicationDirectory =
|
QDir applicationDirectory =
|
||||||
@ -922,7 +873,7 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
|
|||||||
QDir content = application.path() + "/Contents/";
|
QDir content = application.path() + "/Contents/";
|
||||||
QDir resources = content.path() + "/Resources/";
|
QDir resources = content.path() + "/Resources/";
|
||||||
QDir binaryDir = content.path() + "/MacOS/";
|
QDir binaryDir = content.path() + "/MacOS/";
|
||||||
QFile info(content.path() + "/Info.plist");
|
QFile info = content.path() + "/Info.plist";
|
||||||
|
|
||||||
if (!(content.mkpath(".") && resources.mkpath(".") && binaryDir.mkpath("."))) {
|
if (!(content.mkpath(".") && resources.mkpath(".") && binaryDir.mkpath("."))) {
|
||||||
qWarning() << "Couldn't create directories within application";
|
qWarning() << "Couldn't create directories within application";
|
||||||
@ -943,7 +894,8 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
|
|||||||
if (!args.empty())
|
if (!args.empty())
|
||||||
argstring = " \"" + args.join("\" \"") + "\"";
|
argstring = " \"" + args.join("\" \"") + "\"";
|
||||||
|
|
||||||
stream << "#!/bin/bash" << "\n";
|
stream << "#!/bin/bash"
|
||||||
|
<< "\n";
|
||||||
stream << "\"" << target << "\" " << argstring << "\n";
|
stream << "\"" << target << "\" " << argstring << "\n";
|
||||||
|
|
||||||
stream.flush();
|
stream.flush();
|
||||||
@ -987,9 +939,10 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
|
|||||||
if (!args.empty())
|
if (!args.empty())
|
||||||
argstring = " '" + args.join("' '") + "'";
|
argstring = " '" + args.join("' '") + "'";
|
||||||
|
|
||||||
stream << "[Desktop Entry]" << "\n";
|
stream << "[Desktop Entry]"
|
||||||
stream << "Type=Application" << "\n";
|
<< "\n";
|
||||||
stream << "Categories=Game;ActionGame;AdventureGame;Simulation" << "\n";
|
stream << "Type=Application"
|
||||||
|
<< "\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()) {
|
||||||
@ -1267,7 +1220,7 @@ bool clone::operator()(const QString& offset, bool dryRun)
|
|||||||
std::error_code err;
|
std::error_code err;
|
||||||
|
|
||||||
// Function that'll do the actual cloneing
|
// Function that'll do the actual cloneing
|
||||||
auto cloneFile = [this, dryRun, dst, &err](QString src_path, QString relative_dst_path) {
|
auto cloneFile = [&](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))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1626,70 +1579,4 @@ uintmax_t hardLinkCount(const QString& path)
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
// returns 8.3 file format from long path
|
|
||||||
QString shortPathName(const QString& file)
|
|
||||||
{
|
|
||||||
auto input = file.toStdWString();
|
|
||||||
std::wstring output;
|
|
||||||
long length = GetShortPathNameW(input.c_str(), NULL, 0);
|
|
||||||
if (length == 0)
|
|
||||||
return {};
|
|
||||||
// NOTE: this resizing might seem weird...
|
|
||||||
// when GetShortPathNameW fails, it returns length including null character
|
|
||||||
// when it succeeds, it returns length excluding null character
|
|
||||||
// See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364989(v=vs.85).aspx
|
|
||||||
output.resize(length);
|
|
||||||
if (GetShortPathNameW(input.c_str(), (LPWSTR)output.c_str(), length) == 0)
|
|
||||||
return {};
|
|
||||||
output.resize(length - 1);
|
|
||||||
QString ret = QString::fromStdWString(output);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the string survives roundtrip through local 8bit encoding...
|
|
||||||
bool fitsInLocal8bit(const QString& string)
|
|
||||||
{
|
|
||||||
return string == QString::fromLocal8Bit(string.toLocal8Bit());
|
|
||||||
}
|
|
||||||
|
|
||||||
QString getPathNameInLocal8bit(const QString& file)
|
|
||||||
{
|
|
||||||
if (!fitsInLocal8bit(file)) {
|
|
||||||
auto path = shortPathName(file);
|
|
||||||
if (!path.isEmpty()) {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
// in case shortPathName fails just return the path as is
|
|
||||||
}
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QString getUniqueResourceName(const QString& filePath)
|
|
||||||
{
|
|
||||||
auto newFileName = filePath;
|
|
||||||
if (!newFileName.endsWith(".disabled")) {
|
|
||||||
return newFileName; // prioritize enabled mods
|
|
||||||
}
|
|
||||||
newFileName.chop(9);
|
|
||||||
if (!QFile::exists(newFileName)) {
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
QFileInfo fileInfo(filePath);
|
|
||||||
auto baseName = fileInfo.completeBaseName();
|
|
||||||
auto path = fileInfo.absolutePath();
|
|
||||||
|
|
||||||
int counter = 1;
|
|
||||||
do {
|
|
||||||
if (counter == 1) {
|
|
||||||
newFileName = FS::PathCombine(path, baseName + ".duplicate");
|
|
||||||
} else {
|
|
||||||
newFileName = FS::PathCombine(path, baseName + ".duplicate" + QString::number(counter));
|
|
||||||
}
|
|
||||||
counter++;
|
|
||||||
} while (QFile::exists(newFileName));
|
|
||||||
|
|
||||||
return newFileName;
|
|
||||||
}
|
|
||||||
} // namespace FS
|
} // namespace FS
|
||||||
|
@ -72,7 +72,7 @@ void appendSafe(const QString& filename, const QByteArray& data);
|
|||||||
void append(const QString& filename, const QByteArray& data);
|
void append(const QString& filename, const QByteArray& data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* read data from a file safely
|
* read data from a file safely\
|
||||||
*/
|
*/
|
||||||
QByteArray read(const QString& filename);
|
QByteArray read(const QString& filename);
|
||||||
|
|
||||||
@ -91,13 +91,7 @@ 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(const QFileInfo folderPath);
|
bool ensureFolderPathExists(QString filenamepath);
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
||||||
@ -115,7 +109,7 @@ class copy : public QObject {
|
|||||||
m_followSymlinks = follow;
|
m_followSymlinks = follow;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
copy& matcher(IPathMatcher::Ptr filter)
|
copy& matcher(const IPathMatcher* filter)
|
||||||
{
|
{
|
||||||
m_matcher = filter;
|
m_matcher = filter;
|
||||||
return *this;
|
return *this;
|
||||||
@ -147,7 +141,7 @@ class copy : public QObject {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_followSymlinks = true;
|
bool m_followSymlinks = true;
|
||||||
IPathMatcher::Ptr m_matcher = nullptr;
|
const IPathMatcher* m_matcher = nullptr;
|
||||||
bool m_whitelist = false;
|
bool m_whitelist = false;
|
||||||
bool m_overwrite = false;
|
bool m_overwrite = false;
|
||||||
QDir m_src;
|
QDir m_src;
|
||||||
@ -209,7 +203,7 @@ class create_link : public QObject {
|
|||||||
m_useHardLinks = useHard;
|
m_useHardLinks = useHard;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
create_link& matcher(IPathMatcher::Ptr filter)
|
create_link& matcher(const IPathMatcher* filter)
|
||||||
{
|
{
|
||||||
m_matcher = filter;
|
m_matcher = filter;
|
||||||
return *this;
|
return *this;
|
||||||
@ -240,7 +234,6 @@ class create_link : public QObject {
|
|||||||
bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
|
bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
|
||||||
|
|
||||||
int totalLinked() { return m_linked; }
|
int totalLinked() { return m_linked; }
|
||||||
int totalToLink() { return static_cast<int>(m_links_to_make.size()); }
|
|
||||||
|
|
||||||
void runPrivileged() { runPrivileged(QString()); }
|
void runPrivileged() { runPrivileged(QString()); }
|
||||||
void runPrivileged(const QString& offset);
|
void runPrivileged(const QString& offset);
|
||||||
@ -260,7 +253,7 @@ class create_link : public QObject {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_useHardLinks = false;
|
bool m_useHardLinks = false;
|
||||||
IPathMatcher::Ptr m_matcher = nullptr;
|
const IPathMatcher* m_matcher = nullptr;
|
||||||
bool m_whitelist = false;
|
bool m_whitelist = false;
|
||||||
bool m_recursive = true;
|
bool m_recursive = true;
|
||||||
|
|
||||||
@ -343,8 +336,6 @@ QString NormalizePath(QString path);
|
|||||||
|
|
||||||
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith = '-');
|
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith = '-');
|
||||||
|
|
||||||
QString RemoveInvalidPathChars(QString string, QChar replaceWith = '-');
|
|
||||||
|
|
||||||
QString DirNameFromString(QString string, QString inDir = ".");
|
QString DirNameFromString(QString string, QString inDir = ".");
|
||||||
|
|
||||||
/// Checks if the a given Path contains "!"
|
/// Checks if the a given Path contains "!"
|
||||||
@ -379,7 +370,6 @@ enum class FilesystemType {
|
|||||||
HFSX,
|
HFSX,
|
||||||
FUSEBLK,
|
FUSEBLK,
|
||||||
F2FS,
|
F2FS,
|
||||||
BCACHEFS,
|
|
||||||
UNKNOWN
|
UNKNOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -408,7 +398,6 @@ static const QMap<FilesystemType, QStringList> s_filesystem_type_names = { { Fil
|
|||||||
{ FilesystemType::HFSX, { "HFSX" } },
|
{ FilesystemType::HFSX, { "HFSX" } },
|
||||||
{ FilesystemType::FUSEBLK, { "FUSEBLK" } },
|
{ FilesystemType::FUSEBLK, { "FUSEBLK" } },
|
||||||
{ FilesystemType::F2FS, { "F2FS" } },
|
{ FilesystemType::F2FS, { "F2FS" } },
|
||||||
{ FilesystemType::BCACHEFS, { "BCACHEFS" } },
|
|
||||||
{ FilesystemType::UNKNOWN, { "UNKNOWN" } } };
|
{ FilesystemType::UNKNOWN, { "UNKNOWN" } } };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -461,7 +450,7 @@ QString nearestExistentAncestor(const QString& path);
|
|||||||
FilesystemInfo statFS(const QString& path);
|
FilesystemInfo statFS(const QString& path);
|
||||||
|
|
||||||
static const QList<FilesystemType> s_clone_filesystems = { FilesystemType::BTRFS, FilesystemType::APFS, FilesystemType::ZFS,
|
static const QList<FilesystemType> s_clone_filesystems = { FilesystemType::BTRFS, FilesystemType::APFS, FilesystemType::ZFS,
|
||||||
FilesystemType::XFS, FilesystemType::REFS, FilesystemType::BCACHEFS };
|
FilesystemType::XFS, FilesystemType::REFS };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief if the Filesystem is reflink/clone capable
|
* @brief if the Filesystem is reflink/clone capable
|
||||||
@ -488,7 +477,7 @@ class clone : public QObject {
|
|||||||
m_src.setPath(src);
|
m_src.setPath(src);
|
||||||
m_dst.setPath(dst);
|
m_dst.setPath(dst);
|
||||||
}
|
}
|
||||||
clone& matcher(IPathMatcher::Ptr filter)
|
clone& matcher(const IPathMatcher* filter)
|
||||||
{
|
{
|
||||||
m_matcher = filter;
|
m_matcher = filter;
|
||||||
return *this;
|
return *this;
|
||||||
@ -514,7 +503,7 @@ class clone : public QObject {
|
|||||||
bool operator()(const QString& offset, bool dryRun = false);
|
bool operator()(const QString& offset, bool dryRun = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IPathMatcher::Ptr m_matcher = nullptr;
|
const IPathMatcher* m_matcher = nullptr;
|
||||||
bool m_whitelist = false;
|
bool m_whitelist = false;
|
||||||
QDir m_src;
|
QDir m_src;
|
||||||
QDir m_dst;
|
QDir m_dst;
|
||||||
@ -556,10 +545,4 @@ bool canLink(const QString& src, const QString& dst);
|
|||||||
|
|
||||||
uintmax_t hardLinkCount(const QString& path);
|
uintmax_t hardLinkCount(const QString& path);
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
QString getPathNameInLocal8bit(const QString& file);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QString getUniqueResourceName(const QString& filePath);
|
|
||||||
|
|
||||||
} // namespace FS
|
} // namespace FS
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
#include "Filter.h"
|
#include "Filter.h"
|
||||||
|
|
||||||
|
Filter::~Filter() {}
|
||||||
|
|
||||||
ContainsFilter::ContainsFilter(const QString& pattern) : pattern(pattern) {}
|
ContainsFilter::ContainsFilter(const QString& pattern) : pattern(pattern) {}
|
||||||
|
ContainsFilter::~ContainsFilter() {}
|
||||||
bool ContainsFilter::accepts(const QString& value)
|
bool ContainsFilter::accepts(const QString& value)
|
||||||
{
|
{
|
||||||
return value.contains(pattern);
|
return value.contains(pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactFilter::ExactFilter(const QString& pattern) : pattern(pattern) {}
|
ExactFilter::ExactFilter(const QString& pattern) : pattern(pattern) {}
|
||||||
|
ExactFilter::~ExactFilter() {}
|
||||||
bool ExactFilter::accepts(const QString& value)
|
bool ExactFilter::accepts(const QString& value)
|
||||||
{
|
{
|
||||||
return value == pattern;
|
return value == pattern;
|
||||||
@ -23,15 +27,10 @@ RegexpFilter::RegexpFilter(const QString& regexp, bool invert) : invert(invert)
|
|||||||
pattern.setPattern(regexp);
|
pattern.setPattern(regexp);
|
||||||
pattern.optimize();
|
pattern.optimize();
|
||||||
}
|
}
|
||||||
|
RegexpFilter::~RegexpFilter() {}
|
||||||
bool RegexpFilter::accepts(const QString& value)
|
bool RegexpFilter::accepts(const QString& value)
|
||||||
{
|
{
|
||||||
auto match = pattern.match(value);
|
auto match = pattern.match(value);
|
||||||
bool matched = match.hasMatch();
|
bool matched = match.hasMatch();
|
||||||
return invert ? (!matched) : (matched);
|
return invert ? (!matched) : (matched);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactListFilter::ExactListFilter(const QStringList& pattern) : m_pattern(pattern) {}
|
|
||||||
bool ExactListFilter::accepts(const QString& value)
|
|
||||||
{
|
|
||||||
return m_pattern.isEmpty() || m_pattern.contains(value);
|
|
||||||
}
|
|
@ -5,14 +5,14 @@
|
|||||||
|
|
||||||
class Filter {
|
class Filter {
|
||||||
public:
|
public:
|
||||||
virtual ~Filter() = default;
|
virtual ~Filter();
|
||||||
virtual bool accepts(const QString& value) = 0;
|
virtual bool accepts(const QString& value) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ContainsFilter : public Filter {
|
class ContainsFilter : public Filter {
|
||||||
public:
|
public:
|
||||||
ContainsFilter(const QString& pattern);
|
ContainsFilter(const QString& pattern);
|
||||||
virtual ~ContainsFilter() = default;
|
virtual ~ContainsFilter();
|
||||||
bool accepts(const QString& value) override;
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -22,7 +22,7 @@ class ContainsFilter : public Filter {
|
|||||||
class ExactFilter : public Filter {
|
class ExactFilter : public Filter {
|
||||||
public:
|
public:
|
||||||
ExactFilter(const QString& pattern);
|
ExactFilter(const QString& pattern);
|
||||||
virtual ~ExactFilter() = default;
|
virtual ~ExactFilter();
|
||||||
bool accepts(const QString& value) override;
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -32,7 +32,7 @@ class ExactFilter : public Filter {
|
|||||||
class ExactIfPresentFilter : public Filter {
|
class ExactIfPresentFilter : public Filter {
|
||||||
public:
|
public:
|
||||||
ExactIfPresentFilter(const QString& pattern);
|
ExactIfPresentFilter(const QString& pattern);
|
||||||
virtual ~ExactIfPresentFilter() override = default;
|
~ExactIfPresentFilter() override = default;
|
||||||
bool accepts(const QString& value) override;
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -42,20 +42,10 @@ class ExactIfPresentFilter : public Filter {
|
|||||||
class RegexpFilter : public Filter {
|
class RegexpFilter : public Filter {
|
||||||
public:
|
public:
|
||||||
RegexpFilter(const QString& regexp, bool invert);
|
RegexpFilter(const QString& regexp, bool invert);
|
||||||
virtual ~RegexpFilter() = default;
|
virtual ~RegexpFilter();
|
||||||
bool accepts(const QString& value) override;
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QRegularExpression pattern;
|
QRegularExpression pattern;
|
||||||
bool invert = false;
|
bool invert = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExactListFilter : public Filter {
|
|
||||||
public:
|
|
||||||
ExactListFilter(const QStringList& pattern = {});
|
|
||||||
virtual ~ExactListFilter() = default;
|
|
||||||
bool accepts(const QString& value) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QStringList m_pattern;
|
|
||||||
};
|
|
||||||
|
@ -36,8 +36,6 @@
|
|||||||
#include "GZip.h"
|
#include "GZip.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QDebug>
|
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
bool GZip::unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes)
|
bool GZip::unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes)
|
||||||
{
|
{
|
||||||
@ -138,81 +136,3 @@ bool GZip::zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes)
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int inf(QFile* source, std::function<bool(const QByteArray&)> handleBlock)
|
|
||||||
{
|
|
||||||
constexpr auto CHUNK = 16384;
|
|
||||||
int ret;
|
|
||||||
unsigned have;
|
|
||||||
z_stream strm;
|
|
||||||
memset(&strm, 0, sizeof(strm));
|
|
||||||
char in[CHUNK];
|
|
||||||
unsigned char out[CHUNK];
|
|
||||||
|
|
||||||
ret = inflateInit2(&strm, (16 + MAX_WBITS));
|
|
||||||
if (ret != Z_OK)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* decompress until deflate stream ends or end of file */
|
|
||||||
do {
|
|
||||||
strm.avail_in = source->read(in, CHUNK);
|
|
||||||
if (source->error()) {
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return Z_ERRNO;
|
|
||||||
}
|
|
||||||
if (strm.avail_in == 0)
|
|
||||||
break;
|
|
||||||
strm.next_in = reinterpret_cast<Bytef*>(in);
|
|
||||||
|
|
||||||
/* run inflate() on input until output buffer not full */
|
|
||||||
do {
|
|
||||||
strm.avail_out = CHUNK;
|
|
||||||
strm.next_out = out;
|
|
||||||
ret = inflate(&strm, Z_NO_FLUSH);
|
|
||||||
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
|
|
||||||
switch (ret) {
|
|
||||||
case Z_NEED_DICT:
|
|
||||||
ret = Z_DATA_ERROR; /* and fall through */
|
|
||||||
case Z_DATA_ERROR:
|
|
||||||
case Z_MEM_ERROR:
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
have = CHUNK - strm.avail_out;
|
|
||||||
if (!handleBlock(QByteArray(reinterpret_cast<const char*>(out), have))) {
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return Z_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (strm.avail_out == 0);
|
|
||||||
|
|
||||||
/* done when inflate() says it's done */
|
|
||||||
} while (ret != Z_STREAM_END);
|
|
||||||
|
|
||||||
/* clean up and return */
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString zerr(int ret)
|
|
||||||
{
|
|
||||||
switch (ret) {
|
|
||||||
case Z_ERRNO:
|
|
||||||
return QObject::tr("error handling file");
|
|
||||||
case Z_STREAM_ERROR:
|
|
||||||
return QObject::tr("invalid compression level");
|
|
||||||
case Z_DATA_ERROR:
|
|
||||||
return QObject::tr("invalid or incomplete deflate data");
|
|
||||||
case Z_MEM_ERROR:
|
|
||||||
return QObject::tr("out of memory");
|
|
||||||
case Z_VERSION_ERROR:
|
|
||||||
return QObject::tr("zlib version mismatch!");
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
QString GZip::readGzFileByBlocks(QFile* source, std::function<bool(const QByteArray&)> handleBlock)
|
|
||||||
{
|
|
||||||
auto ret = inf(source, handleBlock);
|
|
||||||
return zerr(ret);
|
|
||||||
}
|
|
@ -1,11 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
namespace GZip {
|
class GZip {
|
||||||
|
public:
|
||||||
bool unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes);
|
static bool unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes);
|
||||||
bool zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes);
|
static bool zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes);
|
||||||
QString readGzFileByBlocks(QFile* source, std::function<bool(const QByteArray&)> handleBlock);
|
};
|
||||||
|
|
||||||
} // namespace GZip
|
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
#include "InstanceCopyTask.h"
|
#include "InstanceCopyTask.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
#include <memory>
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "NullInstance.h"
|
#include "NullInstance.h"
|
||||||
#include "pathmatcher/RegexpMatcher.h"
|
#include "pathmatcher/RegexpMatcher.h"
|
||||||
#include "settings/INISettingsObject.h"
|
#include "settings/INISettingsObject.h"
|
||||||
#include "tasks/Task.h"
|
|
||||||
|
|
||||||
InstanceCopyTask::InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs)
|
InstanceCopyTask::InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs)
|
||||||
{
|
{
|
||||||
@ -40,50 +38,38 @@ void InstanceCopyTask::executeTask()
|
|||||||
{
|
{
|
||||||
setStatus(tr("Copying instance %1").arg(m_origInstance->name()));
|
setStatus(tr("Copying instance %1").arg(m_origInstance->name()));
|
||||||
|
|
||||||
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this] {
|
auto copySaves = [&]() {
|
||||||
|
QFileInfo mcDir(FS::PathCombine(m_stagingPath, "minecraft"));
|
||||||
|
QFileInfo dotMCDir(FS::PathCombine(m_stagingPath, ".minecraft"));
|
||||||
|
|
||||||
|
QString staging_mc_dir;
|
||||||
|
if (mcDir.exists() && !dotMCDir.exists())
|
||||||
|
staging_mc_dir = mcDir.filePath();
|
||||||
|
else
|
||||||
|
staging_mc_dir = dotMCDir.filePath();
|
||||||
|
|
||||||
|
FS::copy savesCopy(FS::PathCombine(m_origInstance->gameRoot(), "saves"), FS::PathCombine(staging_mc_dir, "saves"));
|
||||||
|
savesCopy.followSymlinks(true);
|
||||||
|
|
||||||
|
return savesCopy();
|
||||||
|
};
|
||||||
|
|
||||||
|
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this, copySaves] {
|
||||||
if (m_useClone) {
|
if (m_useClone) {
|
||||||
FS::clone folderClone(m_origInstance->instanceRoot(), m_stagingPath);
|
FS::clone folderClone(m_origInstance->instanceRoot(), m_stagingPath);
|
||||||
folderClone.matcher(m_matcher);
|
folderClone.matcher(m_matcher.get());
|
||||||
|
|
||||||
folderClone(true);
|
|
||||||
setProgress(0, folderClone.totalCloned());
|
|
||||||
connect(&folderClone, &FS::clone::fileCloned,
|
|
||||||
[this](QString src, QString dst) { setProgress(m_progress + 1, m_progressTotal); });
|
|
||||||
return folderClone();
|
return folderClone();
|
||||||
}
|
} else if (m_useLinks || m_useHardLinks) {
|
||||||
if (m_useLinks || m_useHardLinks) {
|
|
||||||
std::unique_ptr<FS::copy> savesCopy;
|
|
||||||
if (m_copySaves) {
|
|
||||||
QFileInfo mcDir(FS::PathCombine(m_stagingPath, "minecraft"));
|
|
||||||
QFileInfo dotMCDir(FS::PathCombine(m_stagingPath, ".minecraft"));
|
|
||||||
|
|
||||||
QString staging_mc_dir;
|
|
||||||
if (dotMCDir.exists() && !mcDir.exists())
|
|
||||||
staging_mc_dir = dotMCDir.filePath();
|
|
||||||
else
|
|
||||||
staging_mc_dir = mcDir.filePath();
|
|
||||||
|
|
||||||
savesCopy = std::make_unique<FS::copy>(FS::PathCombine(m_origInstance->gameRoot(), "saves"),
|
|
||||||
FS::PathCombine(staging_mc_dir, "saves"));
|
|
||||||
savesCopy->followSymlinks(true);
|
|
||||||
(*savesCopy)(true);
|
|
||||||
setProgress(0, savesCopy->totalCopied());
|
|
||||||
connect(savesCopy.get(), &FS::copy::fileCopied, [this](QString src) { setProgress(m_progress + 1, m_progressTotal); });
|
|
||||||
}
|
|
||||||
FS::create_link folderLink(m_origInstance->instanceRoot(), m_stagingPath);
|
FS::create_link folderLink(m_origInstance->instanceRoot(), m_stagingPath);
|
||||||
int depth = m_linkRecursively ? -1 : 0; // we need to at least link the top level instead of the instance folder
|
int depth = m_linkRecursively ? -1 : 0; // we need to at least link the top level instead of the instance folder
|
||||||
folderLink.linkRecursively(true).setMaxDepth(depth).useHardLinks(m_useHardLinks).matcher(m_matcher);
|
folderLink.linkRecursively(true).setMaxDepth(depth).useHardLinks(m_useHardLinks).matcher(m_matcher.get());
|
||||||
|
|
||||||
folderLink(true);
|
|
||||||
setProgress(0, m_progressTotal + folderLink.totalToLink());
|
|
||||||
connect(&folderLink, &FS::create_link::fileLinked,
|
|
||||||
[this](QString src, QString dst) { setProgress(m_progress + 1, m_progressTotal); });
|
|
||||||
bool there_were_errors = false;
|
bool there_were_errors = false;
|
||||||
|
|
||||||
if (!folderLink()) {
|
if (!folderLink()) {
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
if (!m_useHardLinks) {
|
if (!m_useHardLinks) {
|
||||||
setProgress(0, m_progressTotal);
|
|
||||||
qDebug() << "EXPECTED: Link failure, Windows requires permissions for symlinks";
|
qDebug() << "EXPECTED: Link failure, Windows requires permissions for symlinks";
|
||||||
|
|
||||||
qDebug() << "attempting to run with privelage";
|
qDebug() << "attempting to run with privelage";
|
||||||
@ -91,7 +77,7 @@ void InstanceCopyTask::executeTask()
|
|||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
bool got_priv_results = false;
|
bool got_priv_results = false;
|
||||||
|
|
||||||
connect(&folderLink, &FS::create_link::finishedPrivileged, this, [&got_priv_results, &loop](bool gotResults) {
|
connect(&folderLink, &FS::create_link::finishedPrivileged, this, [&](bool gotResults) {
|
||||||
if (!gotResults) {
|
if (!gotResults) {
|
||||||
qDebug() << "Privileged run exited without results!";
|
qDebug() << "Privileged run exited without results!";
|
||||||
}
|
}
|
||||||
@ -108,11 +94,13 @@ void InstanceCopyTask::executeTask()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (savesCopy) {
|
if (m_copySaves) {
|
||||||
there_were_errors |= !(*savesCopy)();
|
there_were_errors |= !copySaves();
|
||||||
}
|
}
|
||||||
|
|
||||||
return got_priv_results && !there_were_errors;
|
return got_priv_results && !there_were_errors;
|
||||||
|
} else {
|
||||||
|
qDebug() << "Link Failed!" << folderLink.getOSError().value() << folderLink.getOSError().message().c_str();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
qDebug() << "Link Failed!" << folderLink.getOSError().value() << folderLink.getOSError().message().c_str();
|
qDebug() << "Link Failed!" << folderLink.getOSError().value() << folderLink.getOSError().message().c_str();
|
||||||
@ -120,19 +108,17 @@ void InstanceCopyTask::executeTask()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (savesCopy) {
|
if (m_copySaves) {
|
||||||
there_were_errors |= !(*savesCopy)();
|
there_were_errors |= !copySaves();
|
||||||
}
|
}
|
||||||
|
|
||||||
return !there_were_errors;
|
return !there_were_errors;
|
||||||
}
|
} else {
|
||||||
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
|
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
|
||||||
folderCopy.followSymlinks(false).matcher(m_matcher);
|
folderCopy.followSymlinks(false).matcher(m_matcher.get());
|
||||||
|
|
||||||
folderCopy(true);
|
return folderCopy();
|
||||||
setProgress(0, folderCopy.totalCopied());
|
}
|
||||||
connect(&folderCopy, &FS::copy::fileCopied, [this](QString src) { setProgress(m_progress + 1, m_progressTotal); });
|
|
||||||
return folderCopy();
|
|
||||||
});
|
});
|
||||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &InstanceCopyTask::copyFinished);
|
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &InstanceCopyTask::copyFinished);
|
||||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &InstanceCopyTask::copyAborted);
|
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &InstanceCopyTask::copyAborted);
|
||||||
@ -156,8 +142,9 @@ void InstanceCopyTask::copyFinished()
|
|||||||
if (!m_keepPlaytime) {
|
if (!m_keepPlaytime) {
|
||||||
inst->resetTimePlayed();
|
inst->resetTimePlayed();
|
||||||
}
|
}
|
||||||
if (m_useLinks) {
|
if (m_useLinks)
|
||||||
inst->addLinkedInstanceId(m_origInstance->id());
|
inst->addLinkedInstanceId(m_origInstance->id());
|
||||||
|
if (m_useLinks) {
|
||||||
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;
|
||||||
@ -173,11 +160,7 @@ void InstanceCopyTask::copyFinished()
|
|||||||
allowed_symlinks_file
|
allowed_symlinks_file
|
||||||
.filePath()); // we dont want to modify the original. also make sure the resulting file is not itself a link.
|
.filePath()); // we dont want to modify the original. also make sure the resulting file is not itself a link.
|
||||||
|
|
||||||
try {
|
FS::write(allowed_symlinks_file.filePath(), allowed_symlinks);
|
||||||
FS::write(allowed_symlinks_file.filePath(), allowed_symlinks);
|
|
||||||
} catch (const FS::FileSystemException& e) {
|
|
||||||
qCritical() << "Failed to write symlink :" << e.cause();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
@ -188,14 +171,3 @@ void InstanceCopyTask::copyAborted()
|
|||||||
emitFailed(tr("Instance folder copy has been aborted."));
|
emitFailed(tr("Instance folder copy has been aborted."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstanceCopyTask::abort()
|
|
||||||
{
|
|
||||||
if (m_copyFutureWatcher.isRunning()) {
|
|
||||||
m_copyFutureWatcher.cancel();
|
|
||||||
// NOTE: Here we don't do `emitAborted()` because it will be done when `m_copyFutureWatcher` actually cancels, which may not occur
|
|
||||||
// immediately.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
@ -19,7 +19,6 @@ class InstanceCopyTask : public InstanceTask {
|
|||||||
protected:
|
protected:
|
||||||
//! Entry point for tasks.
|
//! Entry point for tasks.
|
||||||
virtual void executeTask() override;
|
virtual void executeTask() override;
|
||||||
bool abort() override;
|
|
||||||
void copyFinished();
|
void copyFinished();
|
||||||
void copyAborted();
|
void copyAborted();
|
||||||
|
|
||||||
@ -28,7 +27,7 @@ class InstanceCopyTask : public InstanceTask {
|
|||||||
InstancePtr m_origInstance;
|
InstancePtr m_origInstance;
|
||||||
QFuture<bool> m_copyFuture;
|
QFuture<bool> m_copyFuture;
|
||||||
QFutureWatcher<bool> m_copyFutureWatcher;
|
QFutureWatcher<bool> m_copyFutureWatcher;
|
||||||
IPathMatcher::Ptr m_matcher;
|
std::unique_ptr<IPathMatcher> m_matcher;
|
||||||
bool m_keepPlaytime;
|
bool m_keepPlaytime;
|
||||||
bool m_useLinks = false;
|
bool m_useLinks = false;
|
||||||
bool m_useHardLinks = false;
|
bool m_useHardLinks = false;
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include "FileSystem.h"
|
|
||||||
|
InstanceCreationTask::InstanceCreationTask() = default;
|
||||||
|
|
||||||
void InstanceCreationTask::executeTask()
|
void InstanceCreationTask::executeTask()
|
||||||
{
|
{
|
||||||
@ -38,29 +39,22 @@ void InstanceCreationTask::executeTask()
|
|||||||
// files scheduled to, and we'd better not let the user abort in the middle of it, since it'd
|
// files scheduled to, and we'd better not let the user abort in the middle of it, since it'd
|
||||||
// put the instance in an invalid state.
|
// put the instance in an invalid state.
|
||||||
if (shouldOverride()) {
|
if (shouldOverride()) {
|
||||||
bool deleteFailed = false;
|
|
||||||
|
|
||||||
setAbortable(false);
|
setAbortable(false);
|
||||||
setStatus(tr("Removing old conflicting files..."));
|
setStatus(tr("Removing old conflicting files..."));
|
||||||
qDebug() << "Removing old files";
|
qDebug() << "Removing old files";
|
||||||
|
|
||||||
for (const QString& path : m_files_to_remove) {
|
for (auto path : m_files_to_remove) {
|
||||||
if (!QFile::exists(path))
|
if (!QFile::exists(path))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
qDebug() << "Removing" << path;
|
qDebug() << "Removing" << path;
|
||||||
|
|
||||||
if (!QFile::remove(path)) {
|
if (!QFile::remove(path)) {
|
||||||
qCritical() << "Could not remove" << path;
|
qCritical() << "Couldn't remove the old conflicting files.";
|
||||||
deleteFailed = true;
|
emitFailed(tr("Failed to remove old conflicting files."));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deleteFailed) {
|
|
||||||
emitFailed(tr("Failed to remove old conflicting files."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!m_abort)
|
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
class InstanceCreationTask : public InstanceTask {
|
class InstanceCreationTask : public InstanceTask {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
InstanceCreationTask() = default;
|
InstanceCreationTask();
|
||||||
virtual ~InstanceCreationTask() = default;
|
virtual ~InstanceCreationTask() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -1,126 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* Prism Launcher - Minecraft Launcher
|
|
||||||
*
|
|
||||||
* 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 "InstanceDirUpdate.h"
|
|
||||||
|
|
||||||
#include <QCheckBox>
|
|
||||||
|
|
||||||
#include "Application.h"
|
|
||||||
#include "FileSystem.h"
|
|
||||||
|
|
||||||
#include "InstanceList.h"
|
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
|
||||||
|
|
||||||
QString askToUpdateInstanceDirName(InstancePtr instance, const QString& oldName, const QString& newName, QWidget* parent)
|
|
||||||
{
|
|
||||||
if (oldName == newName)
|
|
||||||
return QString();
|
|
||||||
|
|
||||||
QString renamingMode = APPLICATION->settings()->get("InstRenamingMode").toString();
|
|
||||||
if (renamingMode == "MetadataOnly")
|
|
||||||
return QString();
|
|
||||||
|
|
||||||
auto oldRoot = instance->instanceRoot();
|
|
||||||
auto newDirName = FS::DirNameFromString(newName, QFileInfo(oldRoot).dir().absolutePath());
|
|
||||||
auto newRoot = FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), newDirName);
|
|
||||||
if (oldRoot == newRoot)
|
|
||||||
return QString();
|
|
||||||
if (oldRoot == FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), newName))
|
|
||||||
return QString();
|
|
||||||
|
|
||||||
// Check for conflict
|
|
||||||
if (QDir(newRoot).exists()) {
|
|
||||||
QMessageBox::warning(parent, QObject::tr("Cannot rename instance"),
|
|
||||||
QObject::tr("New instance root (%1) already exists. <br />Only the metadata will be renamed.").arg(newRoot));
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ask if we should rename
|
|
||||||
if (renamingMode == "AskEverytime") {
|
|
||||||
auto checkBox = new QCheckBox(QObject::tr("&Remember my choice"), parent);
|
|
||||||
auto dialog =
|
|
||||||
CustomMessageBox::selectable(parent, QObject::tr("Rename instance folder"),
|
|
||||||
QObject::tr("Would you also like to rename the instance folder?\n\n"
|
|
||||||
"Old name: %1\n"
|
|
||||||
"New name: %2")
|
|
||||||
.arg(oldName, newName),
|
|
||||||
QMessageBox::Question, QMessageBox::No | QMessageBox::Yes, QMessageBox::NoButton, checkBox);
|
|
||||||
|
|
||||||
auto res = dialog->exec();
|
|
||||||
if (checkBox->isChecked()) {
|
|
||||||
if (res == QMessageBox::Yes)
|
|
||||||
APPLICATION->settings()->set("InstRenamingMode", "PhysicalDir");
|
|
||||||
else
|
|
||||||
APPLICATION->settings()->set("InstRenamingMode", "MetadataOnly");
|
|
||||||
}
|
|
||||||
if (res == QMessageBox::No)
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for linked instances
|
|
||||||
if (!checkLinkedInstances(instance->id(), parent, QObject::tr("Renaming")))
|
|
||||||
return QString();
|
|
||||||
|
|
||||||
// Now we can confirm that a renaming is happening
|
|
||||||
if (!instance->syncInstanceDirName(newRoot)) {
|
|
||||||
QMessageBox::warning(parent, QObject::tr("Cannot rename instance"),
|
|
||||||
QObject::tr("An error occurred when performing the following renaming operation: <br/>"
|
|
||||||
" - Old instance root: %1<br/>"
|
|
||||||
" - New instance root: %2<br/>"
|
|
||||||
"Only the metadata is renamed.")
|
|
||||||
.arg(oldRoot, newRoot));
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
return newRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool checkLinkedInstances(const QString& id, QWidget* parent, const QString& verb)
|
|
||||||
{
|
|
||||||
auto linkedInstances = APPLICATION->instances()->getLinkedInstancesById(id);
|
|
||||||
if (!linkedInstances.empty()) {
|
|
||||||
auto response = CustomMessageBox::selectable(parent, QObject::tr("There are linked instances"),
|
|
||||||
QObject::tr("The following instance(s) might reference files in this instance:\n\n"
|
|
||||||
"%1\n\n"
|
|
||||||
"%2 it could break the other instance(s), \n\n"
|
|
||||||
"Do you wish to proceed?",
|
|
||||||
nullptr, linkedInstances.count())
|
|
||||||
.arg(linkedInstances.join("\n"))
|
|
||||||
.arg(verb),
|
|
||||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
|
||||||
->exec();
|
|
||||||
if (response != QMessageBox::Yes)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* Prism Launcher - Minecraft Launcher
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* This file incorporates work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Copyright 2013-2021 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "BaseInstance.h"
|
|
||||||
|
|
||||||
/// Update instanceRoot to make it sync with name/id; return newRoot if a directory rename happened
|
|
||||||
QString askToUpdateInstanceDirName(InstancePtr instance, const QString& oldName, const QString& newName, QWidget* parent);
|
|
||||||
|
|
||||||
/// Check if there are linked instances, and display a warning; return true if the operation should proceed
|
|
||||||
bool checkLinkedInstances(const QString& id, QWidget* parent, const QString& verb);
|
|
@ -56,11 +56,10 @@
|
|||||||
|
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#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)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -69,10 +68,16 @@ bool InstanceImportTask::abort()
|
|||||||
if (!canAbort())
|
if (!canAbort())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool wasAborted = false;
|
if (m_filesNetJob)
|
||||||
if (m_task)
|
m_filesNetJob->abort();
|
||||||
wasAborted = m_task->abort();
|
if (m_extractFuture.isRunning()) {
|
||||||
return wasAborted;
|
// NOTE: The tasks created by QtConcurrent::run() can't actually get cancelled,
|
||||||
|
// but we can use this call to check the state when the extraction finishes.
|
||||||
|
m_extractFuture.cancel();
|
||||||
|
m_extractFuture.waitForFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceImportTask::executeTask()
|
void InstanceImportTask::executeTask()
|
||||||
@ -84,6 +89,7 @@ void InstanceImportTask::executeTask()
|
|||||||
processZipPack();
|
processZipPack();
|
||||||
} else {
|
} else {
|
||||||
setStatus(tr("Downloading modpack:\n%1").arg(m_sourceUrl.toString()));
|
setStatus(tr("Downloading modpack:\n%1").arg(m_sourceUrl.toString()));
|
||||||
|
m_downloadRequired = true;
|
||||||
|
|
||||||
downloadFromUrl();
|
downloadFromUrl();
|
||||||
}
|
}
|
||||||
@ -91,133 +97,115 @@ void InstanceImportTask::executeTask()
|
|||||||
|
|
||||||
void InstanceImportTask::downloadFromUrl()
|
void InstanceImportTask::downloadFromUrl()
|
||||||
{
|
{
|
||||||
const QString path(m_sourceUrl.host() + '/' + m_sourceUrl.path());
|
const QString path = m_sourceUrl.host() + '/' + m_sourceUrl.path();
|
||||||
|
|
||||||
auto entry = APPLICATION->metacache()->resolveEntry("general", path);
|
auto entry = APPLICATION->metacache()->resolveEntry("general", path);
|
||||||
entry->setStale(true);
|
entry->setStale(true);
|
||||||
|
m_filesNetJob.reset(new NetJob(tr("Modpack download"), APPLICATION->network()));
|
||||||
|
m_filesNetJob->addNetAction(Net::ApiDownload::makeCached(m_sourceUrl, entry));
|
||||||
m_archivePath = entry->getFullPath();
|
m_archivePath = entry->getFullPath();
|
||||||
|
|
||||||
auto filesNetJob = makeShared<NetJob>(tr("Modpack download"), APPLICATION->network());
|
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded);
|
||||||
filesNetJob->addNetAction(Net::ApiDownload::makeCached(m_sourceUrl, entry));
|
connect(m_filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged);
|
||||||
|
connect(m_filesNetJob.get(), &NetJob::stepProgress, this, &InstanceImportTask::propagateStepProgress);
|
||||||
connect(filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::processZipPack);
|
connect(m_filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::downloadFailed);
|
||||||
connect(filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::setProgress);
|
connect(m_filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::downloadAborted);
|
||||||
connect(filesNetJob.get(), &NetJob::stepProgress, this, &InstanceImportTask::propagateStepProgress);
|
m_filesNetJob->start();
|
||||||
connect(filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::emitFailed);
|
|
||||||
connect(filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::emitAborted);
|
|
||||||
m_task.reset(filesNetJob);
|
|
||||||
filesNetJob->start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString InstanceImportTask::getRootFromZip(QuaZip* zip, const QString& root)
|
void InstanceImportTask::downloadSucceeded()
|
||||||
{
|
{
|
||||||
if (!isRunning()) {
|
processZipPack();
|
||||||
return {};
|
m_filesNetJob.reset();
|
||||||
}
|
}
|
||||||
QuaZipDir rootDir(zip, root);
|
|
||||||
for (auto&& fileName : rootDir.entryList(QDir::Files)) {
|
|
||||||
setDetails(fileName);
|
|
||||||
if (fileName == "instance.cfg") {
|
|
||||||
qDebug() << "MultiMC:" << true;
|
|
||||||
m_modpackType = ModpackType::MultiMC;
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
if (fileName == "manifest.json") {
|
|
||||||
qDebug() << "Flame:" << true;
|
|
||||||
m_modpackType = ModpackType::Flame;
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
QCoreApplication::processEvents();
|
void InstanceImportTask::downloadFailed(QString reason)
|
||||||
}
|
{
|
||||||
|
emitFailed(reason);
|
||||||
|
m_filesNetJob.reset();
|
||||||
|
}
|
||||||
|
|
||||||
// Recurse the search to non-ignored subfolders
|
void InstanceImportTask::downloadProgressChanged(qint64 current, qint64 total)
|
||||||
for (auto&& fileName : rootDir.entryList(QDir::Dirs)) {
|
{
|
||||||
if ("overrides/" == fileName)
|
setProgress(current, total);
|
||||||
continue;
|
}
|
||||||
|
|
||||||
QString result = getRootFromZip(zip, root + fileName);
|
void InstanceImportTask::downloadAborted()
|
||||||
if (!result.isEmpty())
|
{
|
||||||
return result;
|
emitAborted();
|
||||||
}
|
m_filesNetJob.reset();
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceImportTask::processZipPack()
|
void InstanceImportTask::processZipPack()
|
||||||
{
|
{
|
||||||
setStatus(tr("Attempting to determine instance type"));
|
setStatus(tr("Extracting modpack"));
|
||||||
QDir extractDir(m_stagingPath);
|
QDir extractDir(m_stagingPath);
|
||||||
qDebug() << "Attempting to create instance from" << m_archivePath;
|
qDebug() << "Attempting to create instance from" << m_archivePath;
|
||||||
|
|
||||||
// open the zip and find relevant files in it
|
// open the zip and find relevant files in it
|
||||||
auto packZip = std::make_shared<QuaZip>(m_archivePath);
|
m_packZip.reset(new QuaZip(m_archivePath));
|
||||||
if (!packZip->open(QuaZip::mdUnzip)) {
|
if (!m_packZip->open(QuaZip::mdUnzip)) {
|
||||||
emitFailed(tr("Unable to open supplied modpack zip file."));
|
emitFailed(tr("Unable to open supplied modpack zip file."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QuaZipDir packZipDir(packZip.get());
|
QuaZipDir packZipDir(m_packZip.get());
|
||||||
qDebug() << "Attempting to determine instance type";
|
|
||||||
|
|
||||||
|
// https://docs.modrinth.com/docs/modpacks/format_definition/#storage
|
||||||
|
bool modrinthFound = packZipDir.exists("/modrinth.index.json");
|
||||||
|
bool technicFound = packZipDir.exists("/bin/modpack.jar") || packZipDir.exists("/bin/version.json");
|
||||||
QString root;
|
QString root;
|
||||||
|
|
||||||
// NOTE: Prioritize modpack platforms that aren't searched for recursively.
|
// NOTE: Prioritize modpack platforms that aren't searched for recursively.
|
||||||
// Especially Flame has a very common filename for its manifest, which may appear inside overrides for example
|
// Especially Flame has a very common filename for its manifest, which may appear inside overrides for example
|
||||||
// https://docs.modrinth.com/docs/modpacks/format_definition/#storage
|
if (modrinthFound) {
|
||||||
if (packZipDir.exists("/modrinth.index.json")) {
|
|
||||||
// process as Modrinth pack
|
// process as Modrinth pack
|
||||||
qDebug() << "Modrinth:" << true;
|
qDebug() << "Modrinth:" << modrinthFound;
|
||||||
m_modpackType = ModpackType::Modrinth;
|
m_modpackType = ModpackType::Modrinth;
|
||||||
} else if (packZipDir.exists("/bin/modpack.jar") || packZipDir.exists("/bin/version.json")) {
|
} else if (technicFound) {
|
||||||
// process as Technic pack
|
// process as Technic pack
|
||||||
qDebug() << "Technic:" << true;
|
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 {
|
||||||
root = getRootFromZip(packZip.get());
|
QStringList paths_to_ignore{ "overrides/" };
|
||||||
setDetails("");
|
|
||||||
|
if (QString mmcRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg", paths_to_ignore); !mmcRoot.isNull()) {
|
||||||
|
// process as MultiMC instance/pack
|
||||||
|
qDebug() << "MultiMC:" << mmcRoot;
|
||||||
|
root = mmcRoot;
|
||||||
|
m_modpackType = ModpackType::MultiMC;
|
||||||
|
} else if (QString flameRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json", paths_to_ignore);
|
||||||
|
!flameRoot.isNull()) {
|
||||||
|
// process as Flame pack
|
||||||
|
qDebug() << "Flame:" << flameRoot;
|
||||||
|
root = flameRoot;
|
||||||
|
m_modpackType = ModpackType::Flame;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (m_modpackType == ModpackType::Unknown) {
|
if (m_modpackType == ModpackType::Unknown) {
|
||||||
emitFailed(tr("Archive does not contain a recognized modpack type."));
|
emitFailed(tr("Archive does not contain a recognized modpack type."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setStatus(tr("Extracting modpack"));
|
|
||||||
|
|
||||||
// make sure we extract just the pack
|
// make sure we extract just the pack
|
||||||
auto zipTask = makeShared<MMCZip::ExtractZipTask>(packZip, extractDir, root);
|
m_extractFuture =
|
||||||
|
QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractSubDir, m_packZip.get(), root, extractDir.absolutePath());
|
||||||
auto progressStep = std::make_shared<TaskStepProgress>();
|
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, &InstanceImportTask::extractFinished);
|
||||||
connect(zipTask.get(), &Task::finished, this, [this, progressStep] {
|
m_extractFutureWatcher.setFuture(m_extractFuture);
|
||||||
progressStep->state = TaskStepState::Succeeded;
|
|
||||||
stepProgress(*progressStep);
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(zipTask.get(), &Task::succeeded, this, &InstanceImportTask::extractFinished, Qt::QueuedConnection);
|
|
||||||
connect(zipTask.get(), &Task::aborted, this, &InstanceImportTask::emitAborted);
|
|
||||||
connect(zipTask.get(), &Task::failed, this, [this, progressStep](QString reason) {
|
|
||||||
progressStep->state = TaskStepState::Failed;
|
|
||||||
stepProgress(*progressStep);
|
|
||||||
emitFailed(reason);
|
|
||||||
});
|
|
||||||
connect(zipTask.get(), &Task::stepProgress, this, &InstanceImportTask::propagateStepProgress);
|
|
||||||
|
|
||||||
connect(zipTask.get(), &Task::progress, this, [this, progressStep](qint64 current, qint64 total) {
|
|
||||||
progressStep->update(current, total);
|
|
||||||
stepProgress(*progressStep);
|
|
||||||
});
|
|
||||||
connect(zipTask.get(), &Task::status, this, [this, progressStep](QString status) {
|
|
||||||
progressStep->status = status;
|
|
||||||
stepProgress(*progressStep);
|
|
||||||
});
|
|
||||||
m_task.reset(zipTask);
|
|
||||||
zipTask->start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceImportTask::extractFinished()
|
void InstanceImportTask::extractFinished()
|
||||||
{
|
{
|
||||||
setAbortable(false);
|
m_packZip.reset();
|
||||||
|
|
||||||
|
if (m_extractFuture.isCanceled())
|
||||||
|
return;
|
||||||
|
if (!m_extractFuture.result().has_value()) {
|
||||||
|
emitFailed(tr("Failed to extract modpack"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QDir extractDir(m_stagingPath);
|
QDir extractDir(m_stagingPath);
|
||||||
|
|
||||||
qDebug() << "Fixing permissions for extracted pack files...";
|
qDebug() << "Fixing permissions for extracted pack files...";
|
||||||
@ -291,11 +279,8 @@ void InstanceImportTask::processFlame()
|
|||||||
inst_creation_task->setGroup(m_instGroup);
|
inst_creation_task->setGroup(m_instGroup);
|
||||||
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
|
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
|
||||||
|
|
||||||
auto weak = inst_creation_task.toWeakRef();
|
connect(inst_creation_task.get(), &Task::succeeded, this, [this, inst_creation_task] {
|
||||||
connect(inst_creation_task.get(), &Task::succeeded, this, [this, weak] {
|
setOverride(inst_creation_task->shouldOverride(), inst_creation_task->originalInstanceID());
|
||||||
if (auto sp = weak.lock()) {
|
|
||||||
setOverride(sp->shouldOverride(), sp->originalInstanceID());
|
|
||||||
}
|
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
});
|
});
|
||||||
connect(inst_creation_task.get(), &Task::failed, this, &InstanceImportTask::emitFailed);
|
connect(inst_creation_task.get(), &Task::failed, this, &InstanceImportTask::emitFailed);
|
||||||
@ -304,12 +289,11 @@ void InstanceImportTask::processFlame()
|
|||||||
connect(inst_creation_task.get(), &Task::status, this, &InstanceImportTask::setStatus);
|
connect(inst_creation_task.get(), &Task::status, this, &InstanceImportTask::setStatus);
|
||||||
connect(inst_creation_task.get(), &Task::details, this, &InstanceImportTask::setDetails);
|
connect(inst_creation_task.get(), &Task::details, this, &InstanceImportTask::setDetails);
|
||||||
|
|
||||||
connect(inst_creation_task.get(), &Task::aborted, this, &InstanceImportTask::emitAborted);
|
connect(this, &Task::aborted, inst_creation_task.get(), &InstanceCreationTask::abort);
|
||||||
|
connect(inst_creation_task.get(), &Task::aborted, this, &Task::abort);
|
||||||
connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable);
|
connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable);
|
||||||
|
|
||||||
m_task.reset(inst_creation_task);
|
inst_creation_task->start();
|
||||||
setAbortable(true);
|
|
||||||
m_task->start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceImportTask::processTechnic()
|
void InstanceImportTask::processTechnic()
|
||||||
@ -340,15 +324,13 @@ void InstanceImportTask::processMultiMC()
|
|||||||
m_instIcon = instance.iconKey();
|
m_instIcon = instance.iconKey();
|
||||||
|
|
||||||
auto importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), m_instIcon);
|
auto importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), m_instIcon);
|
||||||
if (importIconPath.isNull() || !QFile::exists(importIconPath))
|
|
||||||
importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), "icon.png");
|
|
||||||
if (!importIconPath.isNull() && QFile::exists(importIconPath)) {
|
if (!importIconPath.isNull() && QFile::exists(importIconPath)) {
|
||||||
// import icon
|
// import icon
|
||||||
auto iconList = APPLICATION->icons();
|
auto iconList = APPLICATION->icons();
|
||||||
if (iconList->iconFileExists(m_instIcon)) {
|
if (iconList->iconFileExists(m_instIcon)) {
|
||||||
iconList->deleteIcon(m_instIcon);
|
iconList->deleteIcon(m_instIcon);
|
||||||
}
|
}
|
||||||
iconList->installIcon(importIconPath, m_instIcon);
|
iconList->installIcons({ importIconPath });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
@ -356,7 +338,7 @@ void InstanceImportTask::processMultiMC()
|
|||||||
|
|
||||||
void InstanceImportTask::processModrinth()
|
void InstanceImportTask::processModrinth()
|
||||||
{
|
{
|
||||||
shared_qobject_ptr<ModrinthCreationTask> inst_creation_task = nullptr;
|
ModrinthCreationTask* inst_creation_task = nullptr;
|
||||||
if (!m_extra_info.isEmpty()) {
|
if (!m_extra_info.isEmpty()) {
|
||||||
auto pack_id_it = m_extra_info.constFind("pack_id");
|
auto pack_id_it = m_extra_info.constFind("pack_id");
|
||||||
Q_ASSERT(pack_id_it != m_extra_info.constEnd());
|
Q_ASSERT(pack_id_it != m_extra_info.constEnd());
|
||||||
@ -373,16 +355,16 @@ void InstanceImportTask::processModrinth()
|
|||||||
original_instance_id = original_instance_id_it.value();
|
original_instance_id = original_instance_id_it.value();
|
||||||
|
|
||||||
inst_creation_task =
|
inst_creation_task =
|
||||||
makeShared<ModrinthCreationTask>(m_stagingPath, m_globalSettings, m_parent, pack_id, pack_version_id, original_instance_id);
|
new ModrinthCreationTask(m_stagingPath, m_globalSettings, m_parent, pack_id, pack_version_id, original_instance_id);
|
||||||
} else {
|
} else {
|
||||||
QString pack_id;
|
QString pack_id;
|
||||||
if (!m_sourceUrl.isEmpty()) {
|
if (!m_sourceUrl.isEmpty()) {
|
||||||
static const QRegularExpression s_regex(R"(data\/([^\/]*)\/versions)");
|
QRegularExpression regex(R"(data\/([^\/]*)\/versions)");
|
||||||
pack_id = s_regex.match(m_sourceUrl.toString()).captured(1);
|
pack_id = regex.match(m_sourceUrl.toString()).captured(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Find a way to get the ID in directly imported ZIPs
|
// FIXME: Find a way to get the ID in directly imported ZIPs
|
||||||
inst_creation_task = makeShared<ModrinthCreationTask>(m_stagingPath, m_globalSettings, m_parent, pack_id);
|
inst_creation_task = new ModrinthCreationTask(m_stagingPath, m_globalSettings, m_parent, pack_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
inst_creation_task->setName(*this);
|
inst_creation_task->setName(*this);
|
||||||
@ -390,23 +372,20 @@ void InstanceImportTask::processModrinth()
|
|||||||
inst_creation_task->setGroup(m_instGroup);
|
inst_creation_task->setGroup(m_instGroup);
|
||||||
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
|
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
|
||||||
|
|
||||||
auto weak = inst_creation_task.toWeakRef();
|
connect(inst_creation_task, &Task::succeeded, this, [this, inst_creation_task] {
|
||||||
connect(inst_creation_task.get(), &Task::succeeded, this, [this, weak] {
|
setOverride(inst_creation_task->shouldOverride(), inst_creation_task->originalInstanceID());
|
||||||
if (auto sp = weak.lock()) {
|
|
||||||
setOverride(sp->shouldOverride(), sp->originalInstanceID());
|
|
||||||
}
|
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
});
|
});
|
||||||
connect(inst_creation_task.get(), &Task::failed, this, &InstanceImportTask::emitFailed);
|
connect(inst_creation_task, &Task::failed, this, &InstanceImportTask::emitFailed);
|
||||||
connect(inst_creation_task.get(), &Task::progress, this, &InstanceImportTask::setProgress);
|
connect(inst_creation_task, &Task::progress, this, &InstanceImportTask::setProgress);
|
||||||
connect(inst_creation_task.get(), &Task::stepProgress, this, &InstanceImportTask::propagateStepProgress);
|
connect(inst_creation_task, &Task::stepProgress, this, &InstanceImportTask::propagateStepProgress);
|
||||||
connect(inst_creation_task.get(), &Task::status, this, &InstanceImportTask::setStatus);
|
connect(inst_creation_task, &Task::status, this, &InstanceImportTask::setStatus);
|
||||||
connect(inst_creation_task.get(), &Task::details, this, &InstanceImportTask::setDetails);
|
connect(inst_creation_task, &Task::details, this, &InstanceImportTask::setDetails);
|
||||||
|
connect(inst_creation_task, &Task::finished, inst_creation_task, &InstanceCreationTask::deleteLater);
|
||||||
|
|
||||||
connect(inst_creation_task.get(), &Task::aborted, this, &InstanceImportTask::emitAborted);
|
connect(this, &Task::aborted, inst_creation_task, &InstanceCreationTask::abort);
|
||||||
connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable);
|
connect(inst_creation_task, &Task::aborted, this, &Task::abort);
|
||||||
|
connect(inst_creation_task, &Task::abortStatusChanged, this, &Task::setAbortable);
|
||||||
|
|
||||||
m_task.reset(inst_creation_task);
|
inst_creation_task->start();
|
||||||
setAbortable(true);
|
|
||||||
m_task->start();
|
|
||||||
}
|
}
|
||||||
|
@ -39,35 +39,54 @@
|
|||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include "InstanceTask.h"
|
#include "InstanceTask.h"
|
||||||
|
#include "QObjectPtr.h"
|
||||||
|
#include "modplatform/flame/PackManifest.h"
|
||||||
|
#include "net/NetJob.h"
|
||||||
|
#include "settings/SettingsObject.h"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
class QuaZip;
|
class QuaZip;
|
||||||
|
namespace Flame {
|
||||||
|
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 = {});
|
||||||
virtual ~InstanceImportTask() = default;
|
|
||||||
bool abort() override;
|
bool abort() override;
|
||||||
|
const QVector<Flame::File>& getBlockedFiles() const { return m_blockedMods; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Entry point for tasks.
|
//! Entry point for tasks.
|
||||||
virtual void executeTask() override;
|
virtual void executeTask() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void processZipPack();
|
||||||
void processMultiMC();
|
void processMultiMC();
|
||||||
void processTechnic();
|
void processTechnic();
|
||||||
void processFlame();
|
void processFlame();
|
||||||
void processModrinth();
|
void processModrinth();
|
||||||
QString getRootFromZip(QuaZip* zip, const QString& root = "");
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void processZipPack();
|
void downloadSucceeded();
|
||||||
|
void downloadFailed(QString reason);
|
||||||
|
void downloadProgressChanged(qint64 current, qint64 total);
|
||||||
|
void downloadAborted();
|
||||||
void extractFinished();
|
void extractFinished();
|
||||||
|
|
||||||
private: /* data */
|
private: /* data */
|
||||||
|
NetJob::Ptr m_filesNetJob;
|
||||||
|
shared_qobject_ptr<Flame::FileResolvingTask> m_modIdResolver;
|
||||||
QUrl m_sourceUrl;
|
QUrl m_sourceUrl;
|
||||||
QString m_archivePath;
|
QString m_archivePath;
|
||||||
Task::Ptr m_task;
|
bool m_downloadRequired = false;
|
||||||
|
std::unique_ptr<QuaZip> m_packZip;
|
||||||
|
QFuture<std::optional<QStringList>> m_extractFuture;
|
||||||
|
QFutureWatcher<std::optional<QStringList>> m_extractFutureWatcher;
|
||||||
|
QVector<Flame::File> m_blockedMods;
|
||||||
enum class ModpackType {
|
enum class ModpackType {
|
||||||
Unknown,
|
Unknown,
|
||||||
MultiMC,
|
MultiMC,
|
||||||
|
@ -38,7 +38,6 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QFileSystemWatcher>
|
#include <QFileSystemWatcher>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
@ -372,13 +371,13 @@ void InstanceList::undoTrashInstance()
|
|||||||
|
|
||||||
auto top = m_trashHistory.pop();
|
auto top = m_trashHistory.pop();
|
||||||
|
|
||||||
while (QDir(top.path).exists()) {
|
while (QDir(top.polyPath).exists()) {
|
||||||
top.id += "1";
|
top.id += "1";
|
||||||
top.path += "1";
|
top.polyPath += "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "Moving" << top.trashPath << "back to" << top.path;
|
qDebug() << "Moving" << top.trashPath << "back to" << top.polyPath;
|
||||||
QFile(top.trashPath).rename(top.path);
|
QFile(top.trashPath).rename(top.polyPath);
|
||||||
|
|
||||||
m_instanceGroupIndex[top.id] = top.groupName;
|
m_instanceGroupIndex[top.id] = top.groupName;
|
||||||
increaseGroupCount(top.groupName);
|
increaseGroupCount(top.groupName);
|
||||||
@ -428,7 +427,7 @@ static QMap<InstanceId, InstanceLocator> getIdMapping(const QList<InstancePtr>&
|
|||||||
|
|
||||||
QList<InstanceId> InstanceList::discoverInstances()
|
QList<InstanceId> InstanceList::discoverInstances()
|
||||||
{
|
{
|
||||||
qInfo() << "Discovering instances in" << m_instDir;
|
qDebug() << "Discovering instances in" << m_instDir;
|
||||||
QList<InstanceId> out;
|
QList<InstanceId> out;
|
||||||
QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable | QDir::Hidden, QDirIterator::FollowSymlinks);
|
QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable | QDir::Hidden, QDirIterator::FollowSymlinks);
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
@ -447,9 +446,13 @@ QList<InstanceId> InstanceList::discoverInstances()
|
|||||||
}
|
}
|
||||||
auto id = dirInfo.fileName();
|
auto id = dirInfo.fileName();
|
||||||
out.append(id);
|
out.append(id);
|
||||||
qInfo() << "Found instance ID" << id;
|
qDebug() << "Found instance ID" << id;
|
||||||
}
|
}
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||||
instanceSet = QSet<QString>(out.begin(), out.end());
|
instanceSet = QSet<QString>(out.begin(), out.end());
|
||||||
|
#else
|
||||||
|
instanceSet = out.toSet();
|
||||||
|
#endif
|
||||||
m_instancesProbed = true;
|
m_instancesProbed = true;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@ -464,7 +467,7 @@ InstanceList::InstListError InstanceList::loadList()
|
|||||||
if (existingIds.contains(id)) {
|
if (existingIds.contains(id)) {
|
||||||
auto instPair = existingIds[id];
|
auto instPair = existingIds[id];
|
||||||
existingIds.remove(id);
|
existingIds.remove(id);
|
||||||
qInfo() << "Should keep and soft-reload" << id;
|
qDebug() << "Should keep and soft-reload" << id;
|
||||||
} else {
|
} else {
|
||||||
InstancePtr instPtr = loadInstance(id);
|
InstancePtr instPtr = loadInstance(id);
|
||||||
if (instPtr) {
|
if (instPtr) {
|
||||||
@ -483,7 +486,7 @@ InstanceList::InstListError InstanceList::loadList()
|
|||||||
int front_bookmark = -1;
|
int front_bookmark = -1;
|
||||||
int back_bookmark = -1;
|
int back_bookmark = -1;
|
||||||
int currentItem = -1;
|
int currentItem = -1;
|
||||||
auto removeNow = [this, &front_bookmark, &back_bookmark, ¤tItem]() {
|
auto removeNow = [&]() {
|
||||||
beginRemoveRows(QModelIndex(), front_bookmark, back_bookmark);
|
beginRemoveRows(QModelIndex(), front_bookmark, back_bookmark);
|
||||||
m_instances.erase(m_instances.begin() + front_bookmark, m_instances.begin() + back_bookmark + 1);
|
m_instances.erase(m_instances.begin() + front_bookmark, m_instances.begin() + back_bookmark + 1);
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
@ -631,8 +634,8 @@ InstancePtr InstanceList::loadInstance(const InstanceId& id)
|
|||||||
|
|
||||||
QString inst_type = instanceSettings->get("InstanceType").toString();
|
QString inst_type = instanceSettings->get("InstanceType").toString();
|
||||||
|
|
||||||
// NOTE: Some launcher versions didn't save the InstanceType properly. We will just bank on the probability that this is probably a
|
// NOTE: Some PolyMC versions didn't save the InstanceType properly. We will just bank on the probability that this is probably a OneSix
|
||||||
// OneSix instance
|
// instance
|
||||||
if (inst_type == "OneSix" || inst_type.isEmpty()) {
|
if (inst_type == "OneSix" || inst_type.isEmpty()) {
|
||||||
inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot));
|
inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot));
|
||||||
} else {
|
} else {
|
||||||
@ -706,12 +709,6 @@ void InstanceList::saveGroupList()
|
|||||||
groupsArr.insert(name, groupObj);
|
groupsArr.insert(name, groupObj);
|
||||||
}
|
}
|
||||||
toplevel.insert("groups", groupsArr);
|
toplevel.insert("groups", groupsArr);
|
||||||
// empty string represents ungrouped "group"
|
|
||||||
if (m_collapsedGroups.contains("")) {
|
|
||||||
QJsonObject ungrouped;
|
|
||||||
ungrouped.insert("hidden", QJsonValue(true));
|
|
||||||
toplevel.insert("ungrouped", ungrouped);
|
|
||||||
}
|
|
||||||
QJsonDocument doc(toplevel);
|
QJsonDocument doc(toplevel);
|
||||||
try {
|
try {
|
||||||
FS::write(groupFileName, doc.toJson());
|
FS::write(groupFileName, doc.toJson());
|
||||||
@ -807,16 +804,6 @@ void InstanceList::loadGroupList()
|
|||||||
increaseGroupCount(groupName);
|
increaseGroupCount(groupName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ungroupedHidden = false;
|
|
||||||
if (rootObj.value("ungrouped").isObject()) {
|
|
||||||
QJsonObject ungrouped = rootObj.value("ungrouped").toObject();
|
|
||||||
ungroupedHidden = ungrouped.value("hidden").toBool(false);
|
|
||||||
}
|
|
||||||
if (ungroupedHidden) {
|
|
||||||
// empty string represents ungrouped "group"
|
|
||||||
m_collapsedGroups.insert("");
|
|
||||||
}
|
|
||||||
m_groupsLoaded = true;
|
m_groupsLoaded = true;
|
||||||
qDebug() << "Group list loaded.";
|
qDebug() << "Group list loaded.";
|
||||||
}
|
}
|
||||||
@ -836,9 +823,6 @@ void InstanceList::on_InstFolderChanged([[maybe_unused]] const Setting& setting,
|
|||||||
}
|
}
|
||||||
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -860,16 +844,14 @@ class InstanceStaging : public Task {
|
|||||||
const unsigned maxBackoff = 16;
|
const unsigned maxBackoff = 16;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InstanceStaging(InstanceList* parent, InstanceTask* child, SettingsObjectPtr settings)
|
InstanceStaging(InstanceList* parent, InstanceTask* child, QString stagingPath, InstanceName const& instanceName, QString groupName)
|
||||||
: m_parent(parent), backoff(minBackoff, maxBackoff)
|
: m_parent(parent)
|
||||||
|
, backoff(minBackoff, maxBackoff)
|
||||||
|
, m_stagingPath(std::move(stagingPath))
|
||||||
|
, m_instance_name(std::move(instanceName))
|
||||||
|
, m_groupName(std::move(groupName))
|
||||||
{
|
{
|
||||||
m_stagingPath = parent->getStagedInstancePath();
|
|
||||||
|
|
||||||
m_child.reset(child);
|
m_child.reset(child);
|
||||||
|
|
||||||
m_child->setStagingPath(m_stagingPath);
|
|
||||||
m_child->setParentSettings(std::move(settings));
|
|
||||||
|
|
||||||
connect(child, &Task::succeeded, this, &InstanceStaging::childSucceeded);
|
connect(child, &Task::succeeded, this, &InstanceStaging::childSucceeded);
|
||||||
connect(child, &Task::failed, this, &InstanceStaging::childFailed);
|
connect(child, &Task::failed, this, &InstanceStaging::childFailed);
|
||||||
connect(child, &Task::aborted, this, &InstanceStaging::childAborted);
|
connect(child, &Task::aborted, this, &InstanceStaging::childAborted);
|
||||||
@ -881,7 +863,7 @@ class InstanceStaging : public Task {
|
|||||||
connect(&m_backoffTimer, &QTimer::timeout, this, &InstanceStaging::childSucceeded);
|
connect(&m_backoffTimer, &QTimer::timeout, this, &InstanceStaging::childSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~InstanceStaging() {}
|
virtual ~InstanceStaging(){};
|
||||||
|
|
||||||
// FIXME/TODO: add ability to abort during instance commit retries
|
// FIXME/TODO: add ability to abort during instance commit retries
|
||||||
bool abort() override
|
bool abort() override
|
||||||
@ -896,22 +878,14 @@ class InstanceStaging : public Task {
|
|||||||
bool canAbort() const override { return (m_child && m_child->canAbort()); }
|
bool canAbort() const override { return (m_child && m_child->canAbort()); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void executeTask() override
|
virtual void executeTask() override { m_child->start(); }
|
||||||
{
|
|
||||||
if (m_stagingPath.isNull()) {
|
|
||||||
emitFailed(tr("Could not create staging folder"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_child->start();
|
|
||||||
}
|
|
||||||
QStringList warnings() const override { return m_child->warnings(); }
|
QStringList warnings() const override { return m_child->warnings(); }
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void childSucceeded()
|
void childSucceeded()
|
||||||
{
|
{
|
||||||
unsigned sleepTime = backoff();
|
unsigned sleepTime = backoff();
|
||||||
if (m_parent->commitStagedInstance(m_stagingPath, *m_child.get(), m_child->group(), *m_child.get())) {
|
if (m_parent->commitStagedInstance(m_stagingPath, m_instance_name, m_groupName, *m_child.get())) {
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -920,7 +894,7 @@ class InstanceStaging : public Task {
|
|||||||
emitFailed(tr("Failed to commit instance, even after multiple retries. It is being blocked by something."));
|
emitFailed(tr("Failed to commit instance, even after multiple retries. It is being blocked by something."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
qDebug() << "Failed to commit instance" << m_child->name() << "Initiating backoff:" << sleepTime;
|
qDebug() << "Failed to commit instance" << m_instance_name.name() << "Initiating backoff:" << sleepTime;
|
||||||
m_backoffTimer.start(sleepTime * 500);
|
m_backoffTimer.start(sleepTime * 500);
|
||||||
}
|
}
|
||||||
void childFailed(const QString& reason)
|
void childFailed(const QString& reason)
|
||||||
@ -929,11 +903,7 @@ class InstanceStaging : public Task {
|
|||||||
emitFailed(reason);
|
emitFailed(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void childAborted()
|
void childAborted() { emitAborted(); }
|
||||||
{
|
|
||||||
m_parent->destroyStagingPath(m_stagingPath);
|
|
||||||
emitAborted();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
InstanceList* m_parent;
|
InstanceList* m_parent;
|
||||||
@ -945,35 +915,34 @@ class InstanceStaging : public Task {
|
|||||||
ExponentialSeries backoff;
|
ExponentialSeries backoff;
|
||||||
QString m_stagingPath;
|
QString m_stagingPath;
|
||||||
unique_qobject_ptr<InstanceTask> m_child;
|
unique_qobject_ptr<InstanceTask> m_child;
|
||||||
|
InstanceName m_instance_name;
|
||||||
|
QString m_groupName;
|
||||||
QTimer m_backoffTimer;
|
QTimer m_backoffTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
Task* InstanceList::wrapInstanceTask(InstanceTask* task)
|
Task* InstanceList::wrapInstanceTask(InstanceTask* task)
|
||||||
{
|
{
|
||||||
return new InstanceStaging(this, task, m_globalSettings);
|
auto stagingPath = getStagedInstancePath();
|
||||||
|
task->setStagingPath(stagingPath);
|
||||||
|
task->setParentSettings(m_globalSettings);
|
||||||
|
return new InstanceStaging(this, task, stagingPath, *task, task->group());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString InstanceList::getStagedInstancePath()
|
QString InstanceList::getStagedInstancePath()
|
||||||
{
|
{
|
||||||
const QString tempRoot = FS::PathCombine(m_instDir, ".tmp");
|
QString key = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
||||||
|
QString tempDir = ".LAUNCHER_TEMP/";
|
||||||
QString result;
|
QString relPath = FS::PathCombine(tempDir, key);
|
||||||
int tries = 0;
|
QDir rootPath(m_instDir);
|
||||||
|
auto path = FS::PathCombine(m_instDir, relPath);
|
||||||
do {
|
if (!rootPath.mkpath(relPath)) {
|
||||||
if (++tries > 256)
|
return QString();
|
||||||
return {};
|
}
|
||||||
|
|
||||||
const QString key = QUuid::createUuid().toString(QUuid::Id128).left(6);
|
|
||||||
result = FS::PathCombine(tempRoot, key);
|
|
||||||
} while (QFileInfo::exists(result));
|
|
||||||
|
|
||||||
if (!QDir::current().mkpath(result))
|
|
||||||
return {};
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
SetFileAttributesA(tempRoot.toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
|
auto tempPath = FS::PathCombine(m_instDir, tempDir);
|
||||||
|
SetFileAttributesA(tempPath.toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
|
||||||
#endif
|
#endif
|
||||||
return result;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstanceList::commitStagedInstance(const QString& path,
|
bool InstanceList::commitStagedInstance(const QString& path,
|
||||||
@ -984,6 +953,7 @@ bool InstanceList::commitStagedInstance(const QString& path,
|
|||||||
if (groupName.isEmpty() && !groupName.isNull())
|
if (groupName.isEmpty() && !groupName.isNull())
|
||||||
groupName = QString();
|
groupName = QString();
|
||||||
|
|
||||||
|
QDir dir;
|
||||||
QString instID;
|
QString instID;
|
||||||
InstancePtr inst;
|
InstancePtr inst;
|
||||||
|
|
||||||
@ -1007,7 +977,7 @@ bool InstanceList::commitStagedInstance(const QString& path,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!FS::move(path, destination)) {
|
if (!dir.rename(path, destination)) {
|
||||||
qWarning() << "Failed to move" << path << "to" << destination;
|
qWarning() << "Failed to move" << path << "to" << destination;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ enum class GroupsState { NotLoaded, Steady, Dirty };
|
|||||||
|
|
||||||
struct TrashHistoryItem {
|
struct TrashHistoryItem {
|
||||||
QString id;
|
QString id;
|
||||||
QString path;
|
QString polyPath;
|
||||||
QString trashPath;
|
QString trashPath;
|
||||||
QString groupName;
|
QString groupName;
|
||||||
};
|
};
|
||||||
|
@ -22,7 +22,7 @@ class InstancePageProvider : protected QObject, public BasePageProvider {
|
|||||||
public:
|
public:
|
||||||
explicit InstancePageProvider(InstancePtr parent) { inst = parent; }
|
explicit InstancePageProvider(InstancePtr parent) { inst = parent; }
|
||||||
|
|
||||||
virtual ~InstancePageProvider() = default;
|
virtual ~InstancePageProvider(){};
|
||||||
virtual QList<BasePage*> getPages() override
|
virtual QList<BasePage*> getPages() override
|
||||||
{
|
{
|
||||||
QList<BasePage*> values;
|
QList<BasePage*> values;
|
||||||
@ -39,12 +39,15 @@ class InstancePageProvider : protected QObject, public BasePageProvider {
|
|||||||
values.append(new TexturePackPage(onesix.get(), onesix->texturePackList()));
|
values.append(new TexturePackPage(onesix.get(), onesix->texturePackList()));
|
||||||
values.append(new ShaderPackPage(onesix.get(), onesix->shaderPackList()));
|
values.append(new ShaderPackPage(onesix.get(), onesix->shaderPackList()));
|
||||||
values.append(new NotesPage(onesix.get()));
|
values.append(new NotesPage(onesix.get()));
|
||||||
values.append(new WorldListPage(onesix, onesix->worldList()));
|
values.append(new WorldListPage(onesix.get(), onesix->worldList()));
|
||||||
values.append(new ServersPage(onesix));
|
values.append(new ServersPage(onesix));
|
||||||
// values.append(new GameOptionsPage(onesix.get()));
|
// values.append(new GameOptionsPage(onesix.get()));
|
||||||
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
|
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
|
||||||
values.append(new InstanceSettingsPage(onesix));
|
values.append(new InstanceSettingsPage(onesix.get()));
|
||||||
values.append(new OtherLogsPage(inst));
|
auto logMatcher = inst->getLogFileMatcher();
|
||||||
|
if (logMatcher) {
|
||||||
|
values.append(new OtherLogsPage(inst->getLogFileRoot(), logMatcher));
|
||||||
|
}
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
#include "InstanceTask.h"
|
#include "InstanceTask.h"
|
||||||
|
|
||||||
#include "Application.h"
|
|
||||||
#include "settings/SettingsObject.h"
|
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
|
|
||||||
#include <QPushButton>
|
|
||||||
|
|
||||||
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 =
|
||||||
@ -24,9 +20,6 @@ InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& ol
|
|||||||
|
|
||||||
ShouldUpdate askIfShouldUpdate(QWidget* parent, QString original_version_name)
|
ShouldUpdate askIfShouldUpdate(QWidget* parent, QString original_version_name)
|
||||||
{
|
{
|
||||||
if (APPLICATION->settings()->get("SkipModpackUpdatePrompt").toBool())
|
|
||||||
return ShouldUpdate::SkipUpdating;
|
|
||||||
|
|
||||||
auto info = CustomMessageBox::selectable(
|
auto info = CustomMessageBox::selectable(
|
||||||
parent, QObject::tr("Similar modpack was found!"),
|
parent, QObject::tr("Similar modpack was found!"),
|
||||||
QObject::tr(
|
QObject::tr(
|
||||||
@ -34,15 +27,16 @@ 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::Cancel);
|
QMessageBox::Information, QMessageBox::Ok | QMessageBox::Reset | QMessageBox::Abort);
|
||||||
QAbstractButton* update = info->addButton(QObject::tr("Update existing instance"), QMessageBox::AcceptRole);
|
info->setButtonText(QMessageBox::Ok, QObject::tr("Update existing instance"));
|
||||||
QAbstractButton* skip = info->addButton(QObject::tr("Create new instance"), QMessageBox::ResetRole);
|
info->setButtonText(QMessageBox::Abort, QObject::tr("Create new instance"));
|
||||||
|
info->setButtonText(QMessageBox::Reset, QObject::tr("Cancel"));
|
||||||
|
|
||||||
info->exec();
|
info->exec();
|
||||||
|
|
||||||
if (info->clickedButton() == update)
|
if (info->clickedButton() == info->button(QMessageBox::Ok))
|
||||||
return ShouldUpdate::Update;
|
return ShouldUpdate::Update;
|
||||||
if (info->clickedButton() == skip)
|
if (info->clickedButton() == info->button(QMessageBox::Abort))
|
||||||
return ShouldUpdate::SkipUpdating;
|
return ShouldUpdate::SkipUpdating;
|
||||||
return ShouldUpdate::Cancel;
|
return ShouldUpdate::Cancel;
|
||||||
}
|
}
|
||||||
|
@ -41,9 +41,7 @@
|
|||||||
|
|
||||||
bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget* parent)
|
bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget* parent)
|
||||||
{
|
{
|
||||||
static const QRegularExpression s_memRegex("-Xm[sx]");
|
if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegularExpression("-Xm[sx]")) || jvmargs.contains("-XX-MaxHeapSize") ||
|
||||||
static const QRegularExpression s_versionRegex("-version:.*");
|
|
||||||
if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(s_memRegex) || jvmargs.contains("-XX-MaxHeapSize") ||
|
|
||||||
jvmargs.contains("-XX:InitialHeapSize")) {
|
jvmargs.contains("-XX:InitialHeapSize")) {
|
||||||
auto warnStr = QObject::tr(
|
auto warnStr = QObject::tr(
|
||||||
"You tried to manually set a JVM memory option (using \"-XX:PermSize\", \"-XX-MaxHeapSize\", \"-XX:InitialHeapSize\", \"-Xmx\" "
|
"You tried to manually set a JVM memory option (using \"-XX:PermSize\", \"-XX-MaxHeapSize\", \"-XX:InitialHeapSize\", \"-Xmx\" "
|
||||||
@ -54,7 +52,7 @@ bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget* parent)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// block lunacy with passing required version to the JVM
|
// block lunacy with passing required version to the JVM
|
||||||
if (jvmargs.contains(s_versionRegex)) {
|
if (jvmargs.contains(QRegularExpression("-version:.*"))) {
|
||||||
auto warnStr = QObject::tr(
|
auto warnStr = QObject::tr(
|
||||||
"You tried to pass required Java version argument to the JVM (using \"-version:xxx\"). This is not safe and will not be "
|
"You tried to pass required Java version argument to the JVM (using \"-version:xxx\"). This is not safe and will not be "
|
||||||
"allowed.\n"
|
"allowed.\n"
|
||||||
@ -65,7 +63,7 @@ bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget* parent)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::javaWasOk(QWidget* parent, const JavaChecker::Result& result)
|
void JavaCommon::javaWasOk(QWidget* parent, const JavaCheckResult& result)
|
||||||
{
|
{
|
||||||
QString text;
|
QString text;
|
||||||
text += QObject::tr(
|
text += QObject::tr(
|
||||||
@ -81,7 +79,7 @@ void JavaCommon::javaWasOk(QWidget* parent, const JavaChecker::Result& result)
|
|||||||
CustomMessageBox::selectable(parent, QObject::tr("Java test success"), text, QMessageBox::Information)->show();
|
CustomMessageBox::selectable(parent, QObject::tr("Java test success"), text, QMessageBox::Information)->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::javaArgsWereBad(QWidget* parent, const JavaChecker::Result& result)
|
void JavaCommon::javaArgsWereBad(QWidget* parent, const JavaCheckResult& result)
|
||||||
{
|
{
|
||||||
auto htmlError = result.errorLog;
|
auto htmlError = result.errorLog;
|
||||||
QString text;
|
QString text;
|
||||||
@ -91,7 +89,7 @@ void JavaCommon::javaArgsWereBad(QWidget* parent, const JavaChecker::Result& res
|
|||||||
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
|
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::javaBinaryWasBad(QWidget* parent, const JavaChecker::Result& result)
|
void JavaCommon::javaBinaryWasBad(QWidget* parent, const JavaCheckResult& result)
|
||||||
{
|
{
|
||||||
QString text;
|
QString text;
|
||||||
text += QObject::tr(
|
text += QObject::tr(
|
||||||
@ -118,26 +116,34 @@ void JavaCommon::TestCheck::run()
|
|||||||
emit finished();
|
emit finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checker.reset(new JavaChecker(m_path, "", 0, 0, 0, 0));
|
checker.reset(new JavaChecker());
|
||||||
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinished);
|
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinished);
|
||||||
checker->start();
|
checker->m_path = m_path;
|
||||||
|
checker->performCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::TestCheck::checkFinished(const JavaChecker::Result& result)
|
void JavaCommon::TestCheck::checkFinished(JavaCheckResult result)
|
||||||
{
|
{
|
||||||
if (result.validity != JavaChecker::Result::Validity::Valid) {
|
if (result.validity != JavaCheckResult::Validity::Valid) {
|
||||||
javaBinaryWasBad(m_parent, result);
|
javaBinaryWasBad(m_parent, result);
|
||||||
emit finished();
|
emit finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checker.reset(new JavaChecker(m_path, m_args, m_maxMem, m_maxMem, result.javaVersion.requiresPermGen() ? m_permGen : 0, 0));
|
checker.reset(new JavaChecker());
|
||||||
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinishedWithArgs);
|
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinishedWithArgs);
|
||||||
checker->start();
|
checker->m_path = m_path;
|
||||||
|
checker->m_args = m_args;
|
||||||
|
checker->m_minMem = m_minMem;
|
||||||
|
checker->m_maxMem = m_maxMem;
|
||||||
|
if (result.javaVersion.requiresPermGen()) {
|
||||||
|
checker->m_permGen = m_permGen;
|
||||||
|
}
|
||||||
|
checker->performCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::TestCheck::checkFinishedWithArgs(const JavaChecker::Result& result)
|
void JavaCommon::TestCheck::checkFinishedWithArgs(JavaCheckResult result)
|
||||||
{
|
{
|
||||||
if (result.validity == JavaChecker::Result::Validity::Valid) {
|
if (result.validity == JavaCheckResult::Validity::Valid) {
|
||||||
javaWasOk(m_parent, result);
|
javaWasOk(m_parent, result);
|
||||||
emit finished();
|
emit finished();
|
||||||
return;
|
return;
|
||||||
|
@ -10,11 +10,11 @@ namespace JavaCommon {
|
|||||||
bool checkJVMArgs(QString args, QWidget* parent);
|
bool checkJVMArgs(QString args, QWidget* parent);
|
||||||
|
|
||||||
// Show a dialog saying that the Java binary was usable
|
// Show a dialog saying that the Java binary was usable
|
||||||
void javaWasOk(QWidget* parent, const JavaChecker::Result& result);
|
void javaWasOk(QWidget* parent, const JavaCheckResult& result);
|
||||||
// Show a dialog saying that the Java binary was not usable because of bad options
|
// Show a dialog saying that the Java binary was not usable because of bad options
|
||||||
void javaArgsWereBad(QWidget* parent, const JavaChecker::Result& result);
|
void javaArgsWereBad(QWidget* parent, const JavaCheckResult& result);
|
||||||
// Show a dialog saying that the Java binary was not usable
|
// Show a dialog saying that the Java binary was not usable
|
||||||
void javaBinaryWasBad(QWidget* parent, const JavaChecker::Result& result);
|
void javaBinaryWasBad(QWidget* parent, const JavaCheckResult& result);
|
||||||
// Show a dialog if we couldn't find Java Checker
|
// Show a dialog if we couldn't find Java Checker
|
||||||
void javaCheckNotFound(QWidget* parent);
|
void javaCheckNotFound(QWidget* parent);
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ class TestCheck : public QObject {
|
|||||||
TestCheck(QWidget* parent, QString path, QString args, int minMem, int maxMem, int permGen)
|
TestCheck(QWidget* parent, QString path, QString args, int minMem, int maxMem, int permGen)
|
||||||
: m_parent(parent), m_path(path), m_args(args), m_minMem(minMem), m_maxMem(maxMem), m_permGen(permGen)
|
: m_parent(parent), m_path(path), m_args(args), m_minMem(minMem), m_maxMem(maxMem), m_permGen(permGen)
|
||||||
{}
|
{}
|
||||||
virtual ~TestCheck() = default;
|
virtual ~TestCheck(){};
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
@ -32,11 +32,11 @@ class TestCheck : public QObject {
|
|||||||
void finished();
|
void finished();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void checkFinished(const JavaChecker::Result& result);
|
void checkFinished(JavaCheckResult result);
|
||||||
void checkFinishedWithArgs(const JavaChecker::Result& result);
|
void checkFinishedWithArgs(JavaCheckResult result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JavaChecker::Ptr checker;
|
std::shared_ptr<JavaChecker> checker;
|
||||||
QWidget* m_parent = nullptr;
|
QWidget* m_parent = nullptr;
|
||||||
QString m_path;
|
QString m_path;
|
||||||
QString m_args;
|
QString m_args;
|
||||||
|
@ -188,10 +188,10 @@ T ensureIsType(const QJsonObject& parent, const QString& key, const T default_ =
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
QList<T> requireIsArrayOf(const QJsonDocument& doc)
|
QVector<T> requireIsArrayOf(const QJsonDocument& doc)
|
||||||
{
|
{
|
||||||
const QJsonArray array = requireArray(doc);
|
const QJsonArray array = requireArray(doc);
|
||||||
QList<T> out;
|
QVector<T> out;
|
||||||
for (const QJsonValue val : array) {
|
for (const QJsonValue val : array) {
|
||||||
out.append(requireIsType<T>(val, "Document"));
|
out.append(requireIsType<T>(val, "Document"));
|
||||||
}
|
}
|
||||||
@ -199,10 +199,10 @@ QList<T> requireIsArrayOf(const QJsonDocument& doc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
QList<T> ensureIsArrayOf(const QJsonValue& value, const QString& what = "Value")
|
QVector<T> ensureIsArrayOf(const QJsonValue& value, const QString& what = "Value")
|
||||||
{
|
{
|
||||||
const QJsonArray array = ensureIsType<QJsonArray>(value, QJsonArray(), what);
|
const QJsonArray array = ensureIsType<QJsonArray>(value, QJsonArray(), what);
|
||||||
QList<T> out;
|
QVector<T> out;
|
||||||
for (const QJsonValue val : array) {
|
for (const QJsonValue val : array) {
|
||||||
out.append(requireIsType<T>(val, what));
|
out.append(requireIsType<T>(val, what));
|
||||||
}
|
}
|
||||||
@ -210,7 +210,7 @@ QList<T> ensureIsArrayOf(const QJsonValue& value, const QString& what = "Value")
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
QList<T> ensureIsArrayOf(const QJsonValue& value, const QList<T> default_, const QString& what = "Value")
|
QVector<T> ensureIsArrayOf(const QJsonValue& value, const QVector<T> default_, const QString& what = "Value")
|
||||||
{
|
{
|
||||||
if (value.isUndefined()) {
|
if (value.isUndefined()) {
|
||||||
return default_;
|
return default_;
|
||||||
@ -220,7 +220,7 @@ QList<T> ensureIsArrayOf(const QJsonValue& value, const QList<T> default_, const
|
|||||||
|
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template <typename T>
|
template <typename T>
|
||||||
QList<T> requireIsArrayOf(const QJsonObject& parent, const QString& key, const QString& what = "__placeholder__")
|
QVector<T> requireIsArrayOf(const QJsonObject& parent, const QString& key, const QString& what = "__placeholder__")
|
||||||
{
|
{
|
||||||
const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\'');
|
const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\'');
|
||||||
if (!parent.contains(key)) {
|
if (!parent.contains(key)) {
|
||||||
@ -230,10 +230,10 @@ QList<T> requireIsArrayOf(const QJsonObject& parent, const QString& key, const Q
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
QList<T> ensureIsArrayOf(const QJsonObject& parent,
|
QVector<T> ensureIsArrayOf(const QJsonObject& parent,
|
||||||
const QString& key,
|
const QString& key,
|
||||||
const QList<T>& default_ = QList<T>(),
|
const QVector<T>& default_ = QVector<T>(),
|
||||||
const QString& what = "__placeholder__")
|
const QString& what = "__placeholder__")
|
||||||
{
|
{
|
||||||
const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\'');
|
const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\'');
|
||||||
if (!parent.contains(key)) {
|
if (!parent.contains(key)) {
|
||||||
|
@ -36,14 +36,12 @@
|
|||||||
|
|
||||||
#include "LaunchController.h"
|
#include "LaunchController.h"
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "launch/steps/PrintServers.h"
|
|
||||||
#include "minecraft/auth/AccountData.h"
|
|
||||||
#include "minecraft/auth/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/MSALoginDialog.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"
|
||||||
@ -54,15 +52,15 @@
|
|||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QRegularExpression>
|
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
#include "JavaCommon.h"
|
#include "JavaCommon.h"
|
||||||
#include "launch/steps/TextPrint.h"
|
#include "launch/steps/TextPrint.h"
|
||||||
|
#include "minecraft/auth/AccountTask.h"
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
LaunchController::LaunchController() : Task() {}
|
LaunchController::LaunchController(QObject* parent) : Task(parent) {}
|
||||||
|
|
||||||
void LaunchController::executeTask()
|
void LaunchController::executeTask()
|
||||||
{
|
{
|
||||||
@ -87,7 +85,7 @@ void LaunchController::decideAccount()
|
|||||||
|
|
||||||
// Find an account to use.
|
// Find an account to use.
|
||||||
auto accounts = APPLICATION->accounts();
|
auto accounts = APPLICATION->accounts();
|
||||||
if (accounts->count() <= 0 || !accounts->anyAccountIsValid()) {
|
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 "
|
tr("In order to play Minecraft, you must have at least one Microsoft "
|
||||||
@ -131,64 +129,12 @@ void LaunchController::decideAccount()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LaunchController::askPlayDemo()
|
|
||||||
{
|
|
||||||
QMessageBox box(m_parentWidget);
|
|
||||||
box.setWindowTitle(tr("Play demo?"));
|
|
||||||
box.setText(
|
|
||||||
tr("This account does not own Minecraft.\nYou need to purchase the game first to play it.\n\nDo you want to play "
|
|
||||||
"the demo?"));
|
|
||||||
box.setIcon(QMessageBox::Warning);
|
|
||||||
auto demoButton = box.addButton(tr("Play Demo"), QMessageBox::ButtonRole::YesRole);
|
|
||||||
auto cancelButton = box.addButton(tr("Cancel"), QMessageBox::ButtonRole::NoRole);
|
|
||||||
box.setDefaultButton(cancelButton);
|
|
||||||
|
|
||||||
box.exec();
|
|
||||||
return box.clickedButton() == demoButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString LaunchController::askOfflineName(QString playerName, bool demo, bool& ok)
|
|
||||||
{
|
|
||||||
// we ask the user for a player name
|
|
||||||
QString message = tr("Choose your offline mode player name.");
|
|
||||||
if (demo) {
|
|
||||||
message = tr("Choose your demo mode player name.");
|
|
||||||
}
|
|
||||||
|
|
||||||
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
|
|
||||||
QString usedname = lastOfflinePlayerName.isEmpty() ? playerName : lastOfflinePlayerName;
|
|
||||||
QString name = QInputDialog::getText(m_parentWidget, tr("Player name"), message, QLineEdit::Normal, usedname, &ok);
|
|
||||||
if (!ok)
|
|
||||||
return {};
|
|
||||||
if (name.length()) {
|
|
||||||
usedname = name;
|
|
||||||
APPLICATION->settings()->set("LastOfflinePlayerName", usedname);
|
|
||||||
}
|
|
||||||
return usedname;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LaunchController::login()
|
void LaunchController::login()
|
||||||
{
|
{
|
||||||
decideAccount();
|
decideAccount();
|
||||||
|
|
||||||
|
// if no account is selected, we bail
|
||||||
if (!m_accountToUse) {
|
if (!m_accountToUse) {
|
||||||
// if no account is selected, ask about demo
|
|
||||||
if (!m_demo) {
|
|
||||||
m_demo = askPlayDemo();
|
|
||||||
}
|
|
||||||
if (m_demo) {
|
|
||||||
// we ask the user for a player name
|
|
||||||
bool ok = false;
|
|
||||||
auto name = askOfflineName("Player", m_demo, ok);
|
|
||||||
if (ok) {
|
|
||||||
m_session = std::make_shared<AuthSession>();
|
|
||||||
static const QRegularExpression s_removeChars("[{}-]");
|
|
||||||
m_session->MakeDemo(name, MinecraftAccount::uuidFromUsername(name).toString().remove(s_removeChars));
|
|
||||||
launchInstance();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if no account is selected, we bail
|
|
||||||
emitFailed(tr("No account selected for launch."));
|
emitFailed(tr("No account selected for launch."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -197,12 +143,6 @@ 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) ||
|
|
||||||
m_accountToUse->shouldRefresh()) {
|
|
||||||
// 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
|
|
||||||
m_accountToUse->refresh();
|
|
||||||
}
|
|
||||||
while (tryagain) {
|
while (tryagain) {
|
||||||
if (tries > 0 && tries % 3 == 0) {
|
if (tries > 0 && tries % 3 == 0) {
|
||||||
auto result =
|
auto result =
|
||||||
@ -220,34 +160,13 @@ void LaunchController::login()
|
|||||||
m_session->demo = m_demo;
|
m_session->demo = m_demo;
|
||||||
m_accountToUse->fillSession(m_session);
|
m_accountToUse->fillSession(m_session);
|
||||||
|
|
||||||
MinecraftAccountPtr accountToCheck;
|
// Launch immediately in true offline mode
|
||||||
|
if (m_accountToUse->isOffline()) {
|
||||||
if (m_accountToUse->ownsMinecraft())
|
launchInstance();
|
||||||
accountToCheck = m_accountToUse;
|
|
||||||
else if (const MinecraftAccountPtr defaultAccount = APPLICATION->accounts()->defaultAccount();
|
|
||||||
defaultAccount != nullptr && defaultAccount->ownsMinecraft()) {
|
|
||||||
accountToCheck = defaultAccount;
|
|
||||||
} else {
|
|
||||||
for (int i = 0; i < APPLICATION->accounts()->count(); i++) {
|
|
||||||
MinecraftAccountPtr account = APPLICATION->accounts()->at(i);
|
|
||||||
if (account->ownsMinecraft())
|
|
||||||
accountToCheck = account;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accountToCheck == nullptr) {
|
|
||||||
if (!m_session->demo)
|
|
||||||
m_session->demo = askPlayDemo();
|
|
||||||
|
|
||||||
if (m_session->demo)
|
|
||||||
launchInstance();
|
|
||||||
else
|
|
||||||
emitFailed(tr("Launch cancelled - account does not own Minecraft."));
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (accountToCheck->accountState()) {
|
switch (m_accountToUse->accountState()) {
|
||||||
case AccountState::Offline: {
|
case AccountState::Offline: {
|
||||||
m_session->wants_online = false;
|
m_session->wants_online = false;
|
||||||
}
|
}
|
||||||
@ -256,41 +175,68 @@ void LaunchController::login()
|
|||||||
if (!m_session->wants_online) {
|
if (!m_session->wants_online) {
|
||||||
// we ask the user for a player name
|
// we ask the user for a player name
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
QString name;
|
|
||||||
if (m_offlineName.isEmpty()) {
|
QString message = tr("Choose your offline mode player name.");
|
||||||
name = askOfflineName(m_session->player_name, m_session->demo, ok);
|
if (m_session->demo) {
|
||||||
if (!ok) {
|
message = tr("Choose your demo mode player name.");
|
||||||
tryagain = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
name = m_offlineName;
|
|
||||||
}
|
}
|
||||||
m_session->MakeOffline(name);
|
|
||||||
|
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
|
||||||
|
QString usedname = lastOfflinePlayerName.isEmpty() ? m_session->player_name : lastOfflinePlayerName;
|
||||||
|
QString name = QInputDialog::getText(m_parentWidget, tr("Player name"), message, QLineEdit::Normal, usedname, &ok);
|
||||||
|
if (!ok) {
|
||||||
|
tryagain = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (name.length()) {
|
||||||
|
usedname = name;
|
||||||
|
APPLICATION->settings()->set("LastOfflinePlayerName", usedname);
|
||||||
|
}
|
||||||
|
m_session->MakeOffline(usedname);
|
||||||
// offline flavored game from here :3
|
// offline flavored game from here :3
|
||||||
} else if (m_accountToUse == accountToCheck && !m_accountToUse->hasProfile()) {
|
}
|
||||||
// Now handle setting up a profile name here...
|
if (m_accountToUse->ownsMinecraft()) {
|
||||||
ProfileSetupDialog dialog(m_accountToUse, m_parentWidget);
|
if (!m_accountToUse->hasProfile()) {
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
// Now handle setting up a profile name here...
|
||||||
tryagain = true;
|
ProfileSetupDialog dialog(m_accountToUse, m_parentWidget);
|
||||||
continue;
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
|
tryagain = true;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
emitFailed(tr("Received undetermined session status during login."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// we own Minecraft, there is a profile, it's all ready to go!
|
||||||
|
launchInstance();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// play demo ?
|
||||||
|
QMessageBox box(m_parentWidget);
|
||||||
|
box.setWindowTitle(tr("Play demo?"));
|
||||||
|
box.setText(
|
||||||
|
tr("This account does not own Minecraft.\nYou need to purchase the game first to play it.\n\nDo you want to play "
|
||||||
|
"the demo?"));
|
||||||
|
box.setIcon(QMessageBox::Warning);
|
||||||
|
auto demoButton = box.addButton(tr("Play Demo"), QMessageBox::ButtonRole::YesRole);
|
||||||
|
auto cancelButton = box.addButton(tr("Cancel"), QMessageBox::ButtonRole::NoRole);
|
||||||
|
box.setDefaultButton(cancelButton);
|
||||||
|
|
||||||
|
box.exec();
|
||||||
|
if (box.clickedButton() == demoButton) {
|
||||||
|
// play demo here
|
||||||
|
m_session->MakeDemo();
|
||||||
|
launchInstance();
|
||||||
} else {
|
} else {
|
||||||
emitFailed(tr("Received undetermined session status during login."));
|
emitFailed(tr("Launch cancelled - account does not own Minecraft."));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_accountToUse->accountType() == AccountType::Offline)
|
|
||||||
m_session->wants_online = false;
|
|
||||||
|
|
||||||
// we own Minecraft, there is a profile, it's all ready to go!
|
|
||||||
launchInstance();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case AccountState::Errored:
|
case AccountState::Errored:
|
||||||
// This means some sort of soft error that we can fix with a refresh ... so let's refresh.
|
// This means some sort of soft error that we can fix with a refresh ... so let's refresh.
|
||||||
case AccountState::Unchecked: {
|
case AccountState::Unchecked: {
|
||||||
accountToCheck->refresh();
|
m_accountToUse->refresh();
|
||||||
}
|
}
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case AccountState::Working: {
|
case AccountState::Working: {
|
||||||
@ -299,19 +245,25 @@ void LaunchController::login()
|
|||||||
if (m_online) {
|
if (m_online) {
|
||||||
progDialog.setSkipButton(true, tr("Play Offline"));
|
progDialog.setSkipButton(true, tr("Play Offline"));
|
||||||
}
|
}
|
||||||
auto task = accountToCheck->currentTask();
|
auto task = m_accountToUse->currentTask();
|
||||||
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: {
|
||||||
if (reauthenticateAccount(accountToCheck))
|
auto errorString = tr("The account has expired and needs to be logged into manually again.");
|
||||||
continue;
|
QMessageBox::warning(m_parentWidget, tr("Account refresh failed"), errorString, QMessageBox::StandardButton::Ok,
|
||||||
|
QMessageBox::StandardButton::Ok);
|
||||||
|
emitFailed(errorString);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case AccountState::Disabled: {
|
case AccountState::Disabled: {
|
||||||
auto errorString = tr("The launcher's client identification has changed. Please remove '%1' and try again.")
|
auto errorString = tr("The launcher's client identification has changed. Please remove this account and add it again.");
|
||||||
.arg(accountToCheck->profileName());
|
|
||||||
|
|
||||||
QMessageBox::warning(m_parentWidget, tr("Client identification changed"), errorString, QMessageBox::StandardButton::Ok,
|
QMessageBox::warning(m_parentWidget, tr("Client identification changed"), errorString, QMessageBox::StandardButton::Ok,
|
||||||
QMessageBox::StandardButton::Ok);
|
QMessageBox::StandardButton::Ok);
|
||||||
emitFailed(errorString);
|
emitFailed(errorString);
|
||||||
@ -319,9 +271,8 @@ void LaunchController::login()
|
|||||||
}
|
}
|
||||||
case AccountState::Gone: {
|
case AccountState::Gone: {
|
||||||
auto errorString =
|
auto errorString =
|
||||||
tr("'%1' no longer exists on the servers. It may have been migrated, in which case please add the new account "
|
tr("The account no longer exists on the servers. It may have been migrated, in which case please add the new account "
|
||||||
"you migrated this one to.")
|
"you migrated this one to.");
|
||||||
.arg(accountToCheck->profileName());
|
|
||||||
QMessageBox::warning(m_parentWidget, tr("Account gone"), errorString, QMessageBox::StandardButton::Ok,
|
QMessageBox::warning(m_parentWidget, tr("Account gone"), errorString, QMessageBox::StandardButton::Ok,
|
||||||
QMessageBox::StandardButton::Ok);
|
QMessageBox::StandardButton::Ok);
|
||||||
emitFailed(errorString);
|
emitFailed(errorString);
|
||||||
@ -332,38 +283,6 @@ void LaunchController::login()
|
|||||||
emitFailed(tr("Failed to launch."));
|
emitFailed(tr("Failed to launch."));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LaunchController::reauthenticateAccount(MinecraftAccountPtr account)
|
|
||||||
{
|
|
||||||
auto button = QMessageBox::warning(
|
|
||||||
m_parentWidget, tr("Account refresh failed"),
|
|
||||||
tr("'%1' has expired and needs to be reauthenticated. Do you want to reauthenticate this account?").arg(account->profileName()),
|
|
||||||
QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, QMessageBox::StandardButton::Yes);
|
|
||||||
if (button == QMessageBox::StandardButton::Yes) {
|
|
||||||
auto accounts = APPLICATION->accounts();
|
|
||||||
bool isDefault = accounts->defaultAccount() == account;
|
|
||||||
accounts->removeAccount(accounts->index(accounts->findAccountByProfileId(account->profileId())));
|
|
||||||
if (account->accountType() == AccountType::MSA) {
|
|
||||||
auto newAccount = MSALoginDialog::newAccount(m_parentWidget);
|
|
||||||
|
|
||||||
if (newAccount != nullptr) {
|
|
||||||
accounts->addAccount(newAccount);
|
|
||||||
|
|
||||||
if (isDefault)
|
|
||||||
accounts->setDefaultAccount(newAccount);
|
|
||||||
|
|
||||||
if (m_accountToUse == account) {
|
|
||||||
m_accountToUse = nullptr;
|
|
||||||
decideAccount();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
emitFailed(tr("The account has expired and needs to be reauthenticated"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LaunchController::launchInstance()
|
void LaunchController::launchInstance()
|
||||||
{
|
{
|
||||||
Q_ASSERT_X(m_instance != NULL, "launchInstance", "instance is NULL");
|
Q_ASSERT_X(m_instance != NULL, "launchInstance", "instance is NULL");
|
||||||
@ -375,7 +294,7 @@ void LaunchController::launchInstance()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_launcher = m_instance->createLaunchTask(m_session, m_targetToJoin);
|
m_launcher = m_instance->createLaunchTask(m_session, m_serverToJoin);
|
||||||
if (!m_launcher) {
|
if (!m_launcher) {
|
||||||
emitFailed(tr("Couldn't instantiate a launcher."));
|
emitFailed(tr("Couldn't instantiate a launcher."));
|
||||||
return;
|
return;
|
||||||
@ -397,9 +316,26 @@ void LaunchController::launchInstance()
|
|||||||
online_mode = "online";
|
online_mode = "online";
|
||||||
|
|
||||||
// Prepend Server Status
|
// Prepend Server Status
|
||||||
QStringList servers = { "login.microsoftonline.com", "session.minecraft.net", "textures.minecraft.net", "api.mojang.com" };
|
QStringList servers = { "authserver.mojang.com", "session.minecraft.net", "textures.minecraft.net", "api.mojang.com" };
|
||||||
|
QString resolved_servers = "";
|
||||||
|
QHostInfo host_info;
|
||||||
|
|
||||||
m_launcher->prependStep(makeShared<PrintServers>(m_launcher.get(), servers));
|
for (QString server : servers) {
|
||||||
|
host_info = QHostInfo::fromName(server);
|
||||||
|
resolved_servers = resolved_servers + server + " resolves to:\n [";
|
||||||
|
if (!host_info.addresses().isEmpty()) {
|
||||||
|
for (QHostAddress address : host_info.addresses()) {
|
||||||
|
resolved_servers = resolved_servers + address.toString();
|
||||||
|
if (!host_info.addresses().endsWith(address)) {
|
||||||
|
resolved_servers = resolved_servers + ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resolved_servers = resolved_servers + "N/A";
|
||||||
|
}
|
||||||
|
resolved_servers = resolved_servers + "]\n\n";
|
||||||
|
}
|
||||||
|
m_launcher->prependStep(makeShared<TextPrint>(m_launcher.get(), resolved_servers, MessageLevel::Launcher));
|
||||||
} else {
|
} else {
|
||||||
online_mode = m_demo ? "demo" : "offline";
|
online_mode = m_demo ? "demo" : "offline";
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include "minecraft/auth/MinecraftAccount.h"
|
#include "minecraft/auth/MinecraftAccount.h"
|
||||||
#include "minecraft/launch/MinecraftTarget.h"
|
#include "minecraft/launch/MinecraftServerTarget.h"
|
||||||
|
|
||||||
class InstanceWindow;
|
class InstanceWindow;
|
||||||
class LaunchController : public Task {
|
class LaunchController : public Task {
|
||||||
@ -47,8 +47,8 @@ class LaunchController : public Task {
|
|||||||
public:
|
public:
|
||||||
void executeTask() override;
|
void executeTask() override;
|
||||||
|
|
||||||
LaunchController();
|
LaunchController(QObject* parent = nullptr);
|
||||||
virtual ~LaunchController() = default;
|
virtual ~LaunchController(){};
|
||||||
|
|
||||||
void setInstance(InstancePtr instance) { m_instance = instance; }
|
void setInstance(InstancePtr instance) { m_instance = instance; }
|
||||||
|
|
||||||
@ -56,15 +56,13 @@ class LaunchController : public Task {
|
|||||||
|
|
||||||
void setOnline(bool online) { m_online = online; }
|
void setOnline(bool online) { m_online = online; }
|
||||||
|
|
||||||
void setOfflineName(const QString& offlineName) { m_offlineName = offlineName; }
|
|
||||||
|
|
||||||
void setDemo(bool demo) { m_demo = demo; }
|
void setDemo(bool demo) { m_demo = demo; }
|
||||||
|
|
||||||
void setProfiler(BaseProfilerFactory* profiler) { m_profiler = profiler; }
|
void setProfiler(BaseProfilerFactory* profiler) { m_profiler = profiler; }
|
||||||
|
|
||||||
void setParentWidget(QWidget* widget) { m_parentWidget = widget; }
|
void setParentWidget(QWidget* widget) { m_parentWidget = widget; }
|
||||||
|
|
||||||
void setTargetToJoin(MinecraftTarget::Ptr targetToJoin) { m_targetToJoin = std::move(targetToJoin); }
|
void setServerToJoin(MinecraftServerTargetPtr serverToJoin) { m_serverToJoin = std::move(serverToJoin); }
|
||||||
|
|
||||||
void setAccountToUse(MinecraftAccountPtr accountToUse) { m_accountToUse = std::move(accountToUse); }
|
void setAccountToUse(MinecraftAccountPtr accountToUse) { m_accountToUse = std::move(accountToUse); }
|
||||||
|
|
||||||
@ -76,9 +74,6 @@ class LaunchController : public Task {
|
|||||||
void login();
|
void login();
|
||||||
void launchInstance();
|
void launchInstance();
|
||||||
void decideAccount();
|
void decideAccount();
|
||||||
bool askPlayDemo();
|
|
||||||
QString askOfflineName(QString playerName, bool demo, bool& ok);
|
|
||||||
bool reauthenticateAccount(MinecraftAccountPtr account);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void readyForLaunch();
|
void readyForLaunch();
|
||||||
@ -90,7 +85,6 @@ class LaunchController : public Task {
|
|||||||
private:
|
private:
|
||||||
BaseProfilerFactory* m_profiler = nullptr;
|
BaseProfilerFactory* m_profiler = nullptr;
|
||||||
bool m_online = true;
|
bool m_online = true;
|
||||||
QString m_offlineName;
|
|
||||||
bool m_demo = false;
|
bool m_demo = false;
|
||||||
InstancePtr m_instance;
|
InstancePtr m_instance;
|
||||||
QWidget* m_parentWidget = nullptr;
|
QWidget* m_parentWidget = nullptr;
|
||||||
@ -98,5 +92,5 @@ class LaunchController : public Task {
|
|||||||
MinecraftAccountPtr m_accountToUse = nullptr;
|
MinecraftAccountPtr m_accountToUse = nullptr;
|
||||||
AuthSessionPtr m_session;
|
AuthSessionPtr m_session;
|
||||||
shared_qobject_ptr<LaunchTask> m_launcher;
|
shared_qobject_ptr<LaunchTask> m_launcher;
|
||||||
MinecraftTarget::Ptr m_targetToJoin;
|
MinecraftServerTargetPtr m_serverToJoin;
|
||||||
};
|
};
|
||||||
|
@ -39,16 +39,8 @@ if [ "x$DEPS_LIST" = "x" ]; then
|
|||||||
# Just to be sure...
|
# Just to be sure...
|
||||||
chmod +x "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}"
|
chmod +x "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}"
|
||||||
|
|
||||||
ARGS=("${LAUNCHER_DIR}/${LAUNCHER_NAME}" "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}")
|
|
||||||
|
|
||||||
if [ -f portable.txt ]; then
|
|
||||||
ARGS+=("-d" "${LAUNCHER_DIR}")
|
|
||||||
fi
|
|
||||||
|
|
||||||
ARGS+=("$@")
|
|
||||||
|
|
||||||
# Run the launcher
|
# Run the launcher
|
||||||
exec -a "${ARGS[@]}"
|
exec -a "${LAUNCHER_DIR}/${LAUNCHER_NAME}" "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}" -d "${LAUNCHER_DIR}" "$@"
|
||||||
|
|
||||||
# Run the launcher in valgrind
|
# Run the launcher in valgrind
|
||||||
# valgrind --log-file="valgrind.log" --leak-check=full --track-origins=yes "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}" -d "${LAUNCHER_DIR}" "$@"
|
# valgrind --log-file="valgrind.log" --leak-check=full --track-origins=yes "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}" -d "${LAUNCHER_DIR}" "$@"
|
||||||
|
@ -39,8 +39,7 @@
|
|||||||
#include <QTextDecoder>
|
#include <QTextDecoder>
|
||||||
#include "MessageLevel.h"
|
#include "MessageLevel.h"
|
||||||
|
|
||||||
LoggedProcess::LoggedProcess(const QTextCodec* output_codec, QObject* parent)
|
LoggedProcess::LoggedProcess(QObject* parent) : QProcess(parent)
|
||||||
: QProcess(parent), m_err_decoder(output_codec), m_out_decoder(output_codec)
|
|
||||||
{
|
{
|
||||||
// QProcess has a strange interface... let's map a lot of those into a few.
|
// QProcess has a strange interface... let's map a lot of those into a few.
|
||||||
connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut);
|
connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut);
|
||||||
|
@ -49,7 +49,7 @@ class LoggedProcess : public QProcess {
|
|||||||
enum State { NotRunning, Starting, FailedToStart, Running, Finished, Crashed, Aborted };
|
enum State { NotRunning, Starting, FailedToStart, Running, Finished, Crashed, Aborted };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit LoggedProcess(const QTextCodec* output_codec = QTextCodec::codecForLocale(), QObject* parent = 0);
|
explicit LoggedProcess(QObject* parent = 0);
|
||||||
virtual ~LoggedProcess();
|
virtual ~LoggedProcess();
|
||||||
|
|
||||||
State state() const;
|
State state() const;
|
||||||
@ -80,8 +80,8 @@ class LoggedProcess : public QProcess {
|
|||||||
QStringList reprocess(const QByteArray& data, QTextDecoder& decoder);
|
QStringList reprocess(const QByteArray& data, QTextDecoder& decoder);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTextDecoder m_err_decoder;
|
QTextDecoder m_err_decoder = QTextDecoder(QTextCodec::codecForLocale());
|
||||||
QTextDecoder m_out_decoder;
|
QTextDecoder m_out_decoder = QTextDecoder(QTextCodec::codecForLocale());
|
||||||
QString m_leftover_line;
|
QString m_leftover_line;
|
||||||
bool m_killed = false;
|
bool m_killed = false;
|
||||||
State m_state = NotRunning;
|
State m_state = NotRunning;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* Prism Launcher - Minecraft Launcher
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
* 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,7 +42,6 @@
|
|||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
#if defined(LAUNCHER_APPLICATION)
|
#if defined(LAUNCHER_APPLICATION)
|
||||||
@ -51,7 +50,7 @@
|
|||||||
|
|
||||||
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);
|
||||||
@ -120,10 +119,9 @@ bool compressDirFiles(QuaZip* zip, QString dir, QFileInfoList files, bool follow
|
|||||||
bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files, bool followSymlinks)
|
bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files, bool followSymlinks)
|
||||||
{
|
{
|
||||||
QuaZip zip(fileCompressed);
|
QuaZip zip(fileCompressed);
|
||||||
zip.setUtf8Enabled(true);
|
|
||||||
QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
|
QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
|
||||||
if (!zip.open(QuaZip::mdCreate)) {
|
if (!zip.open(QuaZip::mdCreate)) {
|
||||||
FS::deletePath(fileCompressed);
|
QFile::remove(fileCompressed);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +129,7 @@ bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files,
|
|||||||
|
|
||||||
zip.close();
|
zip.close();
|
||||||
if (zip.getZipError() != 0) {
|
if (zip.getZipError() != 0) {
|
||||||
FS::deletePath(fileCompressed);
|
QFile::remove(fileCompressed);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,9 +141,8 @@ bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files,
|
|||||||
bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod*>& mods)
|
bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod*>& mods)
|
||||||
{
|
{
|
||||||
QuaZip zipOut(targetJarPath);
|
QuaZip zipOut(targetJarPath);
|
||||||
zipOut.setUtf8Enabled(true);
|
|
||||||
if (!zipOut.open(QuaZip::mdCreate)) {
|
if (!zipOut.open(QuaZip::mdCreate)) {
|
||||||
FS::deletePath(targetJarPath);
|
QFile::remove(targetJarPath);
|
||||||
qCritical() << "Failed to open the minecraft.jar for modding";
|
qCritical() << "Failed to open the minecraft.jar for modding";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -163,7 +160,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
|
|||||||
if (mod->type() == ResourceType::ZIPFILE) {
|
if (mod->type() == ResourceType::ZIPFILE) {
|
||||||
if (!mergeZipFiles(&zipOut, mod->fileinfo(), addedFiles)) {
|
if (!mergeZipFiles(&zipOut, mod->fileinfo(), addedFiles)) {
|
||||||
zipOut.close();
|
zipOut.close();
|
||||||
FS::deletePath(targetJarPath);
|
QFile::remove(targetJarPath);
|
||||||
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -172,7 +169,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
|
|||||||
auto filename = mod->fileinfo();
|
auto filename = mod->fileinfo();
|
||||||
if (!JlCompress::compressFile(&zipOut, filename.absoluteFilePath(), filename.fileName())) {
|
if (!JlCompress::compressFile(&zipOut, filename.absoluteFilePath(), filename.fileName())) {
|
||||||
zipOut.close();
|
zipOut.close();
|
||||||
FS::deletePath(targetJarPath);
|
QFile::remove(targetJarPath);
|
||||||
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -195,7 +192,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
|
|||||||
|
|
||||||
if (!compressDirFiles(&zipOut, parent_dir, files)) {
|
if (!compressDirFiles(&zipOut, parent_dir, files)) {
|
||||||
zipOut.close();
|
zipOut.close();
|
||||||
FS::deletePath(targetJarPath);
|
QFile::remove(targetJarPath);
|
||||||
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -203,7 +200,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
|
|||||||
} else {
|
} else {
|
||||||
// Make sure we do not continue launching when something is missing or undefined...
|
// Make sure we do not continue launching when something is missing or undefined...
|
||||||
zipOut.close();
|
zipOut.close();
|
||||||
FS::deletePath(targetJarPath);
|
QFile::remove(targetJarPath);
|
||||||
qCritical() << "Failed to add unknown mod type" << mod->fileinfo().fileName() << "to the jar.";
|
qCritical() << "Failed to add unknown mod type" << mod->fileinfo().fileName() << "to the jar.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -211,7 +208,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
|
|||||||
|
|
||||||
if (!mergeZipFiles(&zipOut, QFileInfo(sourceJarPath), addedFiles, [](const QString key) { return !key.contains("META-INF"); })) {
|
if (!mergeZipFiles(&zipOut, QFileInfo(sourceJarPath), addedFiles, [](const QString key) { return !key.contains("META-INF"); })) {
|
||||||
zipOut.close();
|
zipOut.close();
|
||||||
FS::deletePath(targetJarPath);
|
QFile::remove(targetJarPath);
|
||||||
qCritical() << "Failed to insert minecraft.jar contents.";
|
qCritical() << "Failed to insert minecraft.jar contents.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -219,7 +216,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
|
|||||||
// Recompress the jar
|
// Recompress the jar
|
||||||
zipOut.close();
|
zipOut.close();
|
||||||
if (zipOut.getZipError() != 0) {
|
if (zipOut.getZipError() != 0) {
|
||||||
FS::deletePath(targetJarPath);
|
QFile::remove(targetJarPath);
|
||||||
qCritical() << "Failed to finalize minecraft.jar!";
|
qCritical() << "Failed to finalize minecraft.jar!";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -289,11 +286,10 @@ std::optional<QStringList> extractSubDir(QuaZip* zip, const QString& subdir, con
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
QString file_name = zip->getCurrentFileName();
|
QString file_name = zip->getCurrentFileName();
|
||||||
file_name = FS::RemoveInvalidPathChars(file_name);
|
|
||||||
if (!file_name.startsWith(subdir))
|
if (!file_name.startsWith(subdir))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto relative_file_name = QDir::fromNativeSeparators(file_name.mid(subdir.size()));
|
auto relative_file_name = QDir::fromNativeSeparators(file_name.remove(0, subdir.size()));
|
||||||
auto original_name = relative_file_name;
|
auto original_name = relative_file_name;
|
||||||
|
|
||||||
// Fix subdirs/files ending with a / getting transformed into absolute paths
|
// Fix subdirs/files ending with a / getting transformed into absolute paths
|
||||||
@ -331,31 +327,9 @@ std::optional<QStringList> extractSubDir(QuaZip* zip, const QString& subdir, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
extracted.append(target_file_path);
|
extracted.append(target_file_path);
|
||||||
auto fileInfo = QFileInfo(target_file_path);
|
QFile::setPermissions(target_file_path,
|
||||||
if (fileInfo.isFile()) {
|
QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser);
|
||||||
auto permissions = fileInfo.permissions();
|
|
||||||
auto maxPermisions = QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser |
|
|
||||||
QFileDevice::Permission::ReadGroup | QFileDevice::Permission::ReadOther;
|
|
||||||
auto minPermisions = QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser;
|
|
||||||
|
|
||||||
auto newPermisions = (permissions & maxPermisions) | minPermisions;
|
|
||||||
if (newPermisions != permissions) {
|
|
||||||
if (!QFile::setPermissions(target_file_path, newPermisions)) {
|
|
||||||
qWarning() << (QObject::tr("Could not fix permissions for %1").arg(target_file_path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (fileInfo.isDir()) {
|
|
||||||
// Ensure the folder has the minimal required permissions
|
|
||||||
QFile::Permissions minimalPermissions = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner | QFile::ReadGroup |
|
|
||||||
QFile::ExeGroup | QFile::ReadOther | QFile::ExeOther;
|
|
||||||
|
|
||||||
QFile::Permissions currentPermissions = fileInfo.permissions();
|
|
||||||
if ((currentPermissions & minimalPermissions) != minimalPermissions) {
|
|
||||||
if (!QFile::setPermissions(target_file_path, minimalPermissions)) {
|
|
||||||
qWarning() << (QObject::tr("Could not fix permissions for %1").arg(target_file_path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qDebug() << "Extracted file" << relative_file_name << "to" << target_file_path;
|
qDebug() << "Extracted file" << relative_file_name << "to" << target_file_path;
|
||||||
} while (zip->goToNextFile());
|
} while (zip->goToNextFile());
|
||||||
|
|
||||||
@ -378,7 +352,7 @@ std::optional<QStringList> extractDir(QString fileCompressed, QString dir)
|
|||||||
if (fileInfo.size() == 22) {
|
if (fileInfo.size() == 22) {
|
||||||
return QStringList();
|
return QStringList();
|
||||||
}
|
}
|
||||||
qWarning() << "Could not open archive for unpacking:" << fileCompressed << "Error:" << zip.getZipError();
|
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();
|
||||||
;
|
;
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@ -395,7 +369,7 @@ std::optional<QStringList> extractDir(QString fileCompressed, QString subdir, QS
|
|||||||
if (fileInfo.size() == 22) {
|
if (fileInfo.size() == 22) {
|
||||||
return QStringList();
|
return QStringList();
|
||||||
}
|
}
|
||||||
qWarning() << "Could not open archive for unpacking:" << fileCompressed << "Error:" << zip.getZipError();
|
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();
|
||||||
;
|
;
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@ -412,13 +386,13 @@ bool extractFile(QString fileCompressed, QString file, QString target)
|
|||||||
if (fileInfo.size() == 22) {
|
if (fileInfo.size() == 22) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
qWarning() << "Could not open archive for unpacking:" << fileCompressed << "Error:" << zip.getZipError();
|
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return extractRelFile(&zip, file, target);
|
return extractRelFile(&zip, file, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList* files, FilterFileFunction excludeFilter)
|
bool collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList* files, FilterFunction excludeFilter)
|
||||||
{
|
{
|
||||||
QDir rootDirectory(rootDir);
|
QDir rootDirectory(rootDir);
|
||||||
if (!rootDirectory.exists())
|
if (!rootDirectory.exists())
|
||||||
@ -443,8 +417,8 @@ bool collectFileListRecursively(const QString& rootDir, const QString& subDir, Q
|
|||||||
// collect files
|
// collect files
|
||||||
entries = directory.entryInfoList(QDir::Files);
|
entries = directory.entryInfoList(QDir::Files);
|
||||||
for (const auto& e : entries) {
|
for (const auto& e : entries) {
|
||||||
if (excludeFilter && excludeFilter(e)) {
|
QString relativeFilePath = rootDirectory.relativeFilePath(e.absoluteFilePath());
|
||||||
QString relativeFilePath = rootDirectory.relativeFilePath(e.absoluteFilePath());
|
if (excludeFilter && excludeFilter(relativeFilePath)) {
|
||||||
qDebug() << "Skipping file " << relativeFilePath;
|
qDebug() << "Skipping file " << relativeFilePath;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -489,7 +463,7 @@ auto ExportToZipTask::exportZip() -> ZipResult
|
|||||||
|
|
||||||
auto absolute = file.absoluteFilePath();
|
auto absolute = file.absoluteFilePath();
|
||||||
auto relative = m_dir.relativeFilePath(absolute);
|
auto relative = m_dir.relativeFilePath(absolute);
|
||||||
setStatus("Compressing: " + relative);
|
setStatus("Compresing: " + relative);
|
||||||
setProgress(m_progress + 1, m_progressTotal);
|
setProgress(m_progress + 1, m_progressTotal);
|
||||||
if (m_follow_symlinks) {
|
if (m_follow_symlinks) {
|
||||||
if (file.isSymLink())
|
if (file.isSymLink())
|
||||||
@ -513,10 +487,10 @@ auto ExportToZipTask::exportZip() -> ZipResult
|
|||||||
void ExportToZipTask::finish()
|
void ExportToZipTask::finish()
|
||||||
{
|
{
|
||||||
if (m_build_zip_future.isCanceled()) {
|
if (m_build_zip_future.isCanceled()) {
|
||||||
FS::deletePath(m_output_path);
|
QFile::remove(m_output_path);
|
||||||
emitAborted();
|
emitAborted();
|
||||||
} else if (auto result = m_build_zip_future.result(); result.has_value()) {
|
} else if (auto result = m_build_zip_future.result(); result.has_value()) {
|
||||||
FS::deletePath(m_output_path);
|
QFile::remove(m_output_path);
|
||||||
emitFailed(result.value());
|
emitFailed(result.value());
|
||||||
} else {
|
} else {
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
@ -533,138 +507,6 @@ bool ExportToZipTask::abort()
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExtractZipTask::executeTask()
|
|
||||||
{
|
|
||||||
if (!m_input->isOpen() && !m_input->open(QuaZip::mdUnzip)) {
|
|
||||||
emitFailed(tr("Unable to open supplied zip file."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_zip_future = QtConcurrent::run(QThreadPool::globalInstance(), [this]() { return extractZip(); });
|
|
||||||
connect(&m_zip_watcher, &QFutureWatcher<ZipResult>::finished, this, &ExtractZipTask::finish);
|
|
||||||
m_zip_watcher.setFuture(m_zip_future);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ExtractZipTask::extractZip() -> ZipResult
|
|
||||||
{
|
|
||||||
auto target = m_output_dir.absolutePath();
|
|
||||||
auto target_top_dir = QUrl::fromLocalFile(target);
|
|
||||||
|
|
||||||
QStringList extracted;
|
|
||||||
|
|
||||||
qDebug() << "Extracting subdir" << m_subdirectory << "from" << m_input->getZipName() << "to" << target;
|
|
||||||
auto numEntries = m_input->getEntriesCount();
|
|
||||||
if (numEntries < 0) {
|
|
||||||
return ZipResult(tr("Failed to enumerate files in archive"));
|
|
||||||
}
|
|
||||||
if (numEntries == 0) {
|
|
||||||
logWarning(tr("Extracting empty archives seems odd..."));
|
|
||||||
return ZipResult();
|
|
||||||
}
|
|
||||||
if (!m_input->goToFirstFile()) {
|
|
||||||
return ZipResult(tr("Failed to seek to first file in zip"));
|
|
||||||
}
|
|
||||||
|
|
||||||
setStatus("Extracting files...");
|
|
||||||
setProgress(0, numEntries);
|
|
||||||
do {
|
|
||||||
if (m_zip_future.isCanceled())
|
|
||||||
return ZipResult();
|
|
||||||
setProgress(m_progress + 1, m_progressTotal);
|
|
||||||
QString file_name = m_input->getCurrentFileName();
|
|
||||||
if (!file_name.startsWith(m_subdirectory))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto relative_file_name = QDir::fromNativeSeparators(file_name.mid(m_subdirectory.size()));
|
|
||||||
auto original_name = relative_file_name;
|
|
||||||
setStatus("Unpacking: " + relative_file_name);
|
|
||||||
|
|
||||||
// Fix subdirs/files ending with a / getting transformed into absolute paths
|
|
||||||
if (relative_file_name.startsWith('/'))
|
|
||||||
relative_file_name = relative_file_name.mid(1);
|
|
||||||
|
|
||||||
// Fix weird "folders with a single file get squashed" thing
|
|
||||||
QString sub_path;
|
|
||||||
if (relative_file_name.contains('/') && !relative_file_name.endsWith('/')) {
|
|
||||||
sub_path = relative_file_name.section('/', 0, -2) + '/';
|
|
||||||
FS::ensureFolderPathExists(FS::PathCombine(target, sub_path));
|
|
||||||
|
|
||||||
relative_file_name = relative_file_name.split('/').last();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString target_file_path;
|
|
||||||
if (relative_file_name.isEmpty()) {
|
|
||||||
target_file_path = target + '/';
|
|
||||||
} else {
|
|
||||||
target_file_path = FS::PathCombine(target_top_dir.toLocalFile(), sub_path, relative_file_name);
|
|
||||||
if (relative_file_name.endsWith('/') && !target_file_path.endsWith('/'))
|
|
||||||
target_file_path += '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!target_top_dir.isParentOf(QUrl::fromLocalFile(target_file_path))) {
|
|
||||||
return ZipResult(tr("Extracting %1 was cancelled, because it was effectively outside of the target path %2")
|
|
||||||
.arg(relative_file_name, target));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!JlCompress::extractFile(m_input.get(), "", target_file_path)) {
|
|
||||||
JlCompress::removeFile(extracted);
|
|
||||||
return ZipResult(tr("Failed to extract file %1 to %2").arg(original_name, target_file_path));
|
|
||||||
}
|
|
||||||
|
|
||||||
extracted.append(target_file_path);
|
|
||||||
auto fileInfo = QFileInfo(target_file_path);
|
|
||||||
if (fileInfo.isFile()) {
|
|
||||||
auto permissions = fileInfo.permissions();
|
|
||||||
auto maxPermisions = QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser |
|
|
||||||
QFileDevice::Permission::ReadGroup | QFileDevice::Permission::ReadOther;
|
|
||||||
auto minPermisions = QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser;
|
|
||||||
|
|
||||||
auto newPermisions = (permissions & maxPermisions) | minPermisions;
|
|
||||||
if (newPermisions != permissions) {
|
|
||||||
if (!QFile::setPermissions(target_file_path, newPermisions)) {
|
|
||||||
logWarning(tr("Could not fix permissions for %1").arg(target_file_path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (fileInfo.isDir()) {
|
|
||||||
// Ensure the folder has the minimal required permissions
|
|
||||||
QFile::Permissions minimalPermissions = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner | QFile::ReadGroup |
|
|
||||||
QFile::ExeGroup | QFile::ReadOther | QFile::ExeOther;
|
|
||||||
|
|
||||||
QFile::Permissions currentPermissions = fileInfo.permissions();
|
|
||||||
if ((currentPermissions & minimalPermissions) != minimalPermissions) {
|
|
||||||
if (!QFile::setPermissions(target_file_path, minimalPermissions)) {
|
|
||||||
logWarning(tr("Could not fix permissions for %1").arg(target_file_path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "Extracted file" << relative_file_name << "to" << target_file_path;
|
|
||||||
} while (m_input->goToNextFile());
|
|
||||||
|
|
||||||
return ZipResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExtractZipTask::finish()
|
|
||||||
{
|
|
||||||
if (m_zip_future.isCanceled()) {
|
|
||||||
emitAborted();
|
|
||||||
} else if (auto result = m_zip_future.result(); result.has_value()) {
|
|
||||||
emitFailed(result.value());
|
|
||||||
} else {
|
|
||||||
emitSucceeded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ExtractZipTask::abort()
|
|
||||||
{
|
|
||||||
if (m_zip_future.isRunning()) {
|
|
||||||
m_zip_future.cancel();
|
|
||||||
// NOTE: Here we don't do `emitAborted()` because it will be done when `m_build_zip_future` actually cancels, which may not occur
|
|
||||||
// immediately.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace MMCZip
|
} // namespace MMCZip
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* Prism Launcher - Minecraft Launcher
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
* 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
|
||||||
@ -56,12 +56,11 @@
|
|||||||
|
|
||||||
namespace MMCZip {
|
namespace MMCZip {
|
||||||
using FilterFunction = std::function<bool(const QString&)>;
|
using FilterFunction = std::function<bool(const QString&)>;
|
||||||
using FilterFileFunction = std::function<bool(const QFileInfo&)>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
@ -150,18 +149,12 @@ bool extractFile(QString fileCompressed, QString file, QString dir);
|
|||||||
* \param excludeFilter function to excludeFilter which files shouldn't be included (returning true means to excude)
|
* \param excludeFilter function to excludeFilter which files shouldn't be included (returning true means to excude)
|
||||||
* \return true for success or false for failure
|
* \return true for success or false for failure
|
||||||
*/
|
*/
|
||||||
bool collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList* files, FilterFileFunction excludeFilter);
|
bool collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList* files, FilterFunction excludeFilter);
|
||||||
|
|
||||||
#if defined(LAUNCHER_APPLICATION)
|
#if defined(LAUNCHER_APPLICATION)
|
||||||
class ExportToZipTask : public Task {
|
class ExportToZipTask : public Task {
|
||||||
Q_OBJECT
|
|
||||||
public:
|
public:
|
||||||
ExportToZipTask(QString outputPath,
|
ExportToZipTask(QString outputPath, QDir dir, QFileInfoList files, QString destinationPrefix = "", bool followSymlinks = false)
|
||||||
QDir dir,
|
|
||||||
QFileInfoList files,
|
|
||||||
QString destinationPrefix = "",
|
|
||||||
bool followSymlinks = false,
|
|
||||||
bool utf8Enabled = false)
|
|
||||||
: m_output_path(outputPath)
|
: m_output_path(outputPath)
|
||||||
, m_output(outputPath)
|
, m_output(outputPath)
|
||||||
, m_dir(dir)
|
, m_dir(dir)
|
||||||
@ -170,15 +163,9 @@ class ExportToZipTask : public Task {
|
|||||||
, m_follow_symlinks(followSymlinks)
|
, m_follow_symlinks(followSymlinks)
|
||||||
{
|
{
|
||||||
setAbortable(true);
|
setAbortable(true);
|
||||||
m_output.setUtf8Enabled(utf8Enabled);
|
|
||||||
};
|
};
|
||||||
ExportToZipTask(QString outputPath,
|
ExportToZipTask(QString outputPath, QString dir, QFileInfoList files, QString destinationPrefix = "", bool followSymlinks = false)
|
||||||
QString dir,
|
: ExportToZipTask(outputPath, QDir(dir), files, destinationPrefix, followSymlinks){};
|
||||||
QFileInfoList files,
|
|
||||||
QString destinationPrefix = "",
|
|
||||||
bool followSymlinks = false,
|
|
||||||
bool utf8Enabled = false)
|
|
||||||
: ExportToZipTask(outputPath, QDir(dir), files, destinationPrefix, followSymlinks, utf8Enabled) {};
|
|
||||||
|
|
||||||
virtual ~ExportToZipTask() = default;
|
virtual ~ExportToZipTask() = default;
|
||||||
|
|
||||||
@ -207,34 +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;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExtractZipTask : public Task {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
ExtractZipTask(QString input, QDir outputDir, QString subdirectory = "")
|
|
||||||
: ExtractZipTask(std::make_shared<QuaZip>(input), outputDir, subdirectory)
|
|
||||||
{}
|
|
||||||
ExtractZipTask(std::shared_ptr<QuaZip> input, QDir outputDir, QString subdirectory = "")
|
|
||||||
: m_input(input), m_output_dir(outputDir), m_subdirectory(subdirectory)
|
|
||||||
{}
|
|
||||||
virtual ~ExtractZipTask() = default;
|
|
||||||
|
|
||||||
using ZipResult = std::optional<QString>;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void executeTask() override;
|
|
||||||
bool abort() override;
|
|
||||||
|
|
||||||
ZipResult extractZip();
|
|
||||||
void finish();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<QuaZip> m_input;
|
|
||||||
QDir m_output_dir;
|
|
||||||
QString m_subdirectory;
|
|
||||||
|
|
||||||
QFuture<ZipResult> m_zip_future;
|
|
||||||
QFutureWatcher<ZipResult> m_zip_watcher;
|
|
||||||
};
|
|
||||||
#endif
|
#endif
|
||||||
} // namespace MMCZip
|
} // namespace MMCZip
|
||||||
|
@ -101,7 +101,7 @@ class PixmapCache final : public QObject {
|
|||||||
*/
|
*/
|
||||||
bool _markCacheMissByEviciton()
|
bool _markCacheMissByEviciton()
|
||||||
{
|
{
|
||||||
static constexpr uint maxCache = static_cast<uint>(std::numeric_limits<int>::max()) / 4;
|
static constexpr uint maxInt = static_cast<uint>(std::numeric_limits<int>::max());
|
||||||
static constexpr uint step = 10240;
|
static constexpr uint step = 10240;
|
||||||
static constexpr int oneSecond = 1000;
|
static constexpr int oneSecond = 1000;
|
||||||
|
|
||||||
@ -118,8 +118,8 @@ class PixmapCache final : public QObject {
|
|||||||
if (m_consecutive_fast_evicitons >= m_consecutive_fast_evicitons_threshold) {
|
if (m_consecutive_fast_evicitons >= m_consecutive_fast_evicitons_threshold) {
|
||||||
// increase the cache size
|
// increase the cache size
|
||||||
uint newSize = _cacheLimit() + step;
|
uint newSize = _cacheLimit() + step;
|
||||||
if (newSize >= maxCache) { // increase it until you overflow :D
|
if (newSize >= maxInt) { // increase it until you overflow :D
|
||||||
newSize = maxCache;
|
newSize = maxInt;
|
||||||
qDebug() << m_consecutive_fast_evicitons
|
qDebug() << m_consecutive_fast_evicitons
|
||||||
<< tr("pixmap cache misses by eviction happened too fast, doing nothing as the cache size reached it's limit");
|
<< tr("pixmap cache misses by eviction happened too fast, doing nothing as the cache size reached it's limit");
|
||||||
} else {
|
} else {
|
||||||
|
@ -40,8 +40,8 @@ namespace MangoHud {
|
|||||||
|
|
||||||
QString getLibraryString()
|
QString getLibraryString()
|
||||||
{
|
{
|
||||||
/**
|
/*
|
||||||
* Guess MangoHud install location by searching for vulkan layers in this order:
|
* Check for vulkan layers in this order:
|
||||||
*
|
*
|
||||||
* $VK_LAYER_PATH
|
* $VK_LAYER_PATH
|
||||||
* $XDG_DATA_DIRS (/usr/local/share/:/usr/share/)
|
* $XDG_DATA_DIRS (/usr/local/share/:/usr/share/)
|
||||||
@ -49,9 +49,8 @@ QString getLibraryString()
|
|||||||
* /etc
|
* /etc
|
||||||
* $XDG_CONFIG_DIRS (/etc/xdg)
|
* $XDG_CONFIG_DIRS (/etc/xdg)
|
||||||
* $XDG_CONFIG_HOME (~/.config)
|
* $XDG_CONFIG_HOME (~/.config)
|
||||||
*
|
|
||||||
* @returns Absolute path of libMangoHud.so if found and empty QString otherwise.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
QStringList vkLayerList;
|
QStringList vkLayerList;
|
||||||
{
|
{
|
||||||
QString home = QDir::homePath();
|
QString home = QDir::homePath();
|
||||||
@ -86,7 +85,7 @@ QString getLibraryString()
|
|||||||
vkLayerList << FS::PathCombine(xdgConfigHome, "vulkan", "implicit_layer.d");
|
vkLayerList << FS::PathCombine(xdgConfigHome, "vulkan", "implicit_layer.d");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QString& vkLayer : vkLayerList) {
|
for (QString vkLayer : vkLayerList) {
|
||||||
// prefer to use architecture specific vulkan layers
|
// prefer to use architecture specific vulkan layers
|
||||||
QString currentArch = QSysInfo::currentCpuArchitecture();
|
QString currentArch = QSysInfo::currentCpuArchitecture();
|
||||||
|
|
||||||
@ -96,8 +95,8 @@ QString getLibraryString()
|
|||||||
|
|
||||||
QStringList manifestNames = { QString("MangoHud.%1.json").arg(currentArch), "MangoHud.json" };
|
QStringList manifestNames = { QString("MangoHud.%1.json").arg(currentArch), "MangoHud.json" };
|
||||||
|
|
||||||
QString filePath{};
|
QString filePath = "";
|
||||||
for (const QString& manifestName : manifestNames) {
|
for (QString manifestName : manifestNames) {
|
||||||
QString tryPath = FS::PathCombine(vkLayer, manifestName);
|
QString tryPath = FS::PathCombine(vkLayer, manifestName);
|
||||||
if (QFile::exists(tryPath)) {
|
if (QFile::exists(tryPath)) {
|
||||||
filePath = tryPath;
|
filePath = tryPath;
|
||||||
@ -108,34 +107,14 @@ QString getLibraryString()
|
|||||||
if (filePath.isEmpty()) {
|
if (filePath.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
auto conf = Json::requireDocument(filePath, vkLayer);
|
|
||||||
auto confObject = Json::requireObject(conf, vkLayer);
|
|
||||||
auto layer = Json::ensureObject(confObject, "layer");
|
|
||||||
QString libraryName = Json::ensureString(layer, "library_path");
|
|
||||||
|
|
||||||
if (libraryName.isEmpty()) {
|
auto conf = Json::requireDocument(filePath, vkLayer);
|
||||||
continue;
|
auto confObject = Json::requireObject(conf, vkLayer);
|
||||||
}
|
auto layer = Json::ensureObject(confObject, "layer");
|
||||||
if (QFileInfo(libraryName).isAbsolute()) {
|
return Json::ensureString(layer, "library_path");
|
||||||
return libraryName;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __GLIBC__
|
|
||||||
// Check whether mangohud is usable on a glibc based system
|
|
||||||
QString libraryPath = findLibrary(libraryName);
|
|
||||||
if (!libraryPath.isEmpty()) {
|
|
||||||
return libraryPath;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
// Without glibc return recorded shared library as-is.
|
|
||||||
return libraryName;
|
|
||||||
#endif
|
|
||||||
} catch (const Exception& e) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString findLibrary(QString libName)
|
QString findLibrary(QString libName)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user